Стандартизированные журналы — это начало формирования хороших навыков программирования, а также спасительная соломинка для устранения серьезных ошибок в критические моменты. Программисты могут распечатывать журналы отладки в процессе разработки и предоставлять журналы для устранения проблем в сложных предприятиях. Они также могут быстро решать проблемы и своевременно устранять их при возникновении производственных проблем. В любом случае понимание и изучение спецификаций логов — это базовый навык, необходимый программисту.
Это хороший способ непосредственно ознакомиться с некоторыми отличными платформами с открытым исходным кодом или прочитать некоторые примеры обработки исключений в исходном коде JDK. Вот несколько примеров:
Журнал печатается на основе собранной конкретной информации об исключении:
try {
File defaultAclFile = new File(fileName);
if (!defaultAclFile.exists()) {
defaultAclFile.createNewFile();
}
} catch (IOException e) {
// Собирайте информацию об определенных исключениях и печатайте журналы.
log.warn("create default acl file has exception when update accessConfig. ", e);
}
Используйте String.format вместо + сплайсинга, определите и создайте собственные исключения:
try {
byte[] signature = sign(data.getBytes(charset), key.getBytes(charset), algorithm);
return new String(Base64.encodeBase64(signature), DEFAULT_CHARSET);
} catch (Exception e) {
// Используйте String.format заменять + Сращивание
String message = String.format(CAL_SIGNATURE_FAILED_MSG, CAL_SIGNATURE_FAILED, e.getMessage());
log.error(message, e);
// Пользовательское исключение
throw new AclException("CAL_SIGNATURE_FAILED", CAL_SIGNATURE_FAILED, message, e);
}
Иногда обработка исключений ведет себя неожиданно. Я думаю, что такая обработка выглядит хорошо, но на самом деле ее легко «заложить». Если автор не представит ее в документе, это будет очень опасное поведение.
try {
return Long.parseLong(value);
} catch (NumberFormatException e) {
// Я думаю, что такая обработка выглядит хорошо, но на самом деле ее очень легко «закопать мины».
return new BigDecimal(value).longValue();
}
Можно сказать, что структуру журналирования JAVA представляет собой кусок шпагата, и в конечном итоге вся эта куча шпагата сделана одним человеком. Соответственно, если мы воспользуемся инструментом lombok, мы обнаружим, что существуют такие аннотации, как @Log4j, @Slf4j и @Log4j2. Имена этих логов не только трудно запомнить, но и имеют почти одинаковую длину. используя их, мы не знаем, какой из них использовать, или даже не знаем, почему это используется. Вот общий обзор результатов развития всего фреймворка к настоящему моменту:
Давайте начнем разбираться, как получилась эта картинка =-=.
System.outа такжеSystem.err
Это самый старый способ печати журналов в JAVA. Такая печать проста и быстра. Недостаток в том, что ее нельзя настроить в любом формате, и нет проблем с выводом, поэтому эффективность крайне низкая.
Log4j
В 1996 году проект, родившийся на европейском рынке электронной безопасности, решил разработать набор API-интерфейсов для отслеживания журналов. Впоследствии этот набор API стал независимым проектом Log4j.
Ceki Gülcü
какLog4jОсновное развитие,Предоставляет множество ссылок на инфраструктуру разработки журналов. Лог4дж Он до сих пор используется большим количеством компаний, и его влияние имеет далеко идущие последствия.
JUL(Java Util Logging)
Sun очень завидует Log4j. Отклонив просьбу об интеграции Log4j в Java, она разработала собственную структуру журналов. Конечно, по сути, это можно рассматривать как копирование. Но поскольку Log4j существует уже много лет, отзывы рынка не идеальны, и все по-прежнему используют Log4j.
JCL(Jakarta Commons Logging)
Вот ключевой момент сравнения,Apach и Sun начинают спорить из-за стандартов ведения журналов,Впоследствии компания Apach разработала JCL.,предназначен для использованияJCLВзлететьSunРазвитый инструмент журналирования。Jakarta Commons Logging
После выпуска также предоставляется единый интерфейс журнала.,По сути, это простой уровень абстракции печати журналов.
Но идея очень красивая, но реальность очень уродлива. JCL и JUL тоже постигла похожая судьба. Они не получили хороших отзывов на рынке и позже были скрыты Apach.
Slf4j(Simple Logging Facade for Java)
На этом фоне,Ceki Gülcü
По личным причинам отApachПодать в отставку,И попытки самостоятельно сформулировать набор спецификаций для замены JCL.,Наконец назван Sfl4j,Судя по результатам, он действительно гораздо успешнее JCL.,Но мы должны обратить вниманиеSlf4jиJCLПросто набор стандартов,Так что позжеCeki Gülcü
Разработано сновамостовой пакетсовместимый JCL, Log4j и JUC также интегрированы в него. Он все сделал сам, он действительно как бог.
На данный момент мы можем грубо организовать упомянутые выше отношения. Синяя часть представляет собой конкретный физический инструмент или продукт, а желтая часть представляет собой спецификацию.
Давайте присоединимся сновамостовой пакет(красный логотипмостовой пакет),Следующие изменения произошли снова,Результаты пакета спецификации + совместимости Slf4j следующие:
Но иногда возникает другая ситуация при конкретном использовании фреймворка. Хотя все продукты реализованы с использованием Slf4j, фактические детали печати журналов размещаются отдельно, поскольку Slf4j только упрощает унифицированный вход и не выполняет никаких операций по объединению журналов. Например, здесь мы используем среду SpringBoot, предполагая, что она использует log4j, а наш собственный бизнес-код использует slf4j, будет два разных формата журналов.
Поэтому Slf4j впоследствии реализовал обработку совместимости. Целью является не только возможность доступа к различным журналам, но и взять на себя всю работу других фреймворков журналов. Да, мостовое соединение здесь все еще используется. Однако мостовое соединение эквивалентно обеспечению совместимости всей печати журналов с совместимой платформой журналов и управления ею в соответствии с форматом журнала sfl4j.
На данный момент Slf4j стал совместим со всеми другими продуктами, и он действительно достиг эффекта замены одной платформы другими платформами журналирования.
Logback
SLf4j объединяет несколько фреймворков.,Но Sl4j всё-таки стандартизирован,Не конкретный продукт,затемCeki Gülcü
Трахнул еще одногоLogbackпублично заявить,Этот LogBack можно рассматривать как обновление Log4j.,Не только производительность может быть в десять раз быстрее, чем у Log4j.,Это также идеальная заменаSlf4j。Для простоты памяти вот простое резюме:Журнал регистрации = Slf4j + Log4j (улучшено)
。
Log4j2
Ceki Gülcü
из старого клубаApachВполне естественно не радоваться, когда вы видите, как бывший сотрудник бьет вас по носу или лицу.,для сравнительного анализаLogbackразвитыйLog4j 2. Неудивительно, что он охватывает практически все функции Logback, а также предоставляет отдельные операции. Да, это всего лишь небольшое улучшение на основе Slf4j и использует интерфейсы, совместимые с другими платформами журналов, в виде пакета (Api), самого продукта журнала. формируется в пакет (Core).
Итоговый рисунок немного пугает. Построение можно сохранить и просмотреть несколько раз (для удобства просмотра здесь убраны вспомогательные линии).
Вся платформа ведения журналов Java разработала четыре платформы и три интерфейса.,Основная используемая структура::Log4j2、Slf4j、Logback、JUL(Sunразвивать),Интерфейсы — это набор вещей мостового пакета.,Используется для объединения всех спецификаций и интерфейсов других платформ в ваши собственные продукты.,
Примечание. На самом деле здесь вы можете увидеть более интересную деталь.,То есть
JCL(Jakarta Commons Logging)
Тихо уходим со сцены истории,Потому что в прошлом это действительно было мошенничество,Log4j2, разработанный Apach, имеет доступ только к JUL вместо JCL, который он разработал ранее.
Итак, когда система выбирает план ведения журнала, как принять решение?
• Очевидно, что первым делом следует использовать API интерфейса журнала вместо непосредственного использования API продукта журнала. Это также необходимо.,Это также соответствует принципу инверсии зависимостей.,мы должныПолагайтесь на абстракцию журнала, а не на его реализацию.。
• Добавляйте только одну зависимость продукта журналов. Если вы полагаетесь на несколько продуктов журналов, это только усложнит обработку журналов вашего приложения и не сможет управляться единообразно.
• Установите зависимость продукта журнала наOptionalиruntime scopeвOptionalдляЗависимости не будут переданы,Например, если кто-то другой цитирует вашу банку,Вы будете вынуждены использовать зависимости журналов, которые вы не хотите использовать.
Например, чтобы предотвратить передачу зависимостей, вы можете использовать следующий метод:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>${log4j.version}</version>
<optional>true</optional>
</dependency>
Установка области выполнения во время выполнения может гарантировать, что зависимости продукта журнала будут необходимы только во время выполнения, а не во время компиляции. Это также может гарантировать, что разработчики неправильно используют API:
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>${log4j.version}</version>
<scope>runtime</scope>
</dependency>
Вышеизложенное представляет собой историю беспорядка с журналированием Java. Я надеюсь, что читатели смогут извлечь из этого уроки, а не опыт.
Журналы записи в основном проверяют следующие моменты:
Мы можем использовать следующий формат для форматирования вывода журнала:
2019-12-01 00:00:00.000|pid|log-level|[svc-name,trace-id,span-id,user-id,biz-id]|thread-name|package-name.class-name : log message
Взяв в качестве примера Logback, мы можем использовать следующий формат для стандартизированной печати:
%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}|${PID:- }|%level|${LOG_LEVEL_PATTERN:-%5p}|%t|%-40.40logger{39}: %msg%n
Настройки logback.xml следующие:
<configuration><property name="LOG_PATH"
value="${LOG_PATH:-${LOG_TEMP:-${java.io.tmpdir:-/tmp}}}"/>
<springProperty scope="context" name="APP_NAME"
source="spring.application.name" defaultValue="spring-boot-fusion"/>
<!-- Глобальное единство pattern -->
<property name="LOG_PATTERN"
value="%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}|${PID:- }|%level|${LOG_LEVEL_PATTERN:-%5p}|%t|%-40.40logger{39}: %msg%n"/>
<!-- Режим вывода файл, файл скользящей записи, сначала назначьте файл журнала файлу, при выполнении определенного условия регистрация в других файлах -->
<appender name="fileInfo" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--Имя файла пишется,Может быть относительным каталогом,Это также может быть абсолютный каталог,Если каталог верхнего уровня не существует, он будет создан автоматически.,нет значения по умолчанию。-->
<file>${LOG_PATH}/${APP_NAME}-info.log</file>
<!--скользящая стратегия Стратегия субподряда, основанная на времени -->
<rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
<!-- yyyy-MM-dd стратегия времени — один файл в день -->
<FileNamePattern>${LOG_PATH}/${APP_NAME}-info.%d{yyyy-MM-dd-HH}.%i.log</FileNamePattern>
<!--Часы хранения файла журнала-->
<MaxHistory>48</MaxHistory>
<maxFileSize>1GB</maxFileSize>
<totalSizeCap>20GB</totalSizeCap>
</rollingPolicy>
<!-- layout Отвечает за преобразование событий в строки и вывод форматированной информации журнала. -->
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>${LOG_PATTERN}</pattern>
</layout>
<!--фильтр уровня,Фильтрация по уровню журнала. Если уровень журнала равен уровню конфигурации,Фильтр будет основан на onMath и onMismatchПринять или отклонить журналы-->
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<!--Установить уровень фильтрации-->
<level>INFO</level>
<!--Используется для настройки действий, соответствующих условиям фильтра.-->
<onMatch>ACCEPT</onMatch>
<!--Используется для настройки операций, которые не соответствуют условиям фильтра.-->
<onMismatch>DENY</onMismatch>
</filter>
</appender>
</configuration>
Вот несколько ключевых моментов, которые стоит представить:
@lombok.extern.slf4j.Slf4j
+logbackплан,сам logback также является автором slft4j,Что-то сделано автором log4j,Это конечный интегрированный продукт.<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<scope>provided</scope>
</dependency>
@ToString
аннотацияилииспользоватьIDEМожет генерироваться автоматически。+
而是更建议использовать{}
Распечатать как заполнитель:// Для корректных примеров необходимо использовать параметризованную информацию.
log.debug("order is paying with userId:[{}] and orderId : [{}]",userId, orderId);
// ошибка Пример,Не вводите строку Сращивание, которая сгенерирует много String объект,Занимая место,влияют на производительность. И уровень журнала выше этого уровня также будет выполнять логику строкового Сращивания.
log.debug("order is paying with userId: " + userId + " and orderId: " + orderId);
Если разрешено, вы можете использовать lombok для добавления аннотаций для использования экземпляров переменных журнала.
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<scope>provided</scope>
</dependency>
Используются следующие места:
import lombok.extern.slf4j.Slf4j;
@Slf4j public class LogTest
{
public static void main(String[] args) {
log.info("this is log test");
}
}
Основные уровни журналов следующие: Уровни журналов от малого к большому:
Сам уровень DEBUG ниже уровня INFO, и журналы уровня INFO обычно включаются онлайн. Журналы DEBUG наиболее подходят для локального использования и тестирования, тогда как журналы уровня INFO не могут служить убедительным доказательством для эксплуатации и обслуживания или обратной связи с операциями. вывод бессмысленной или бесполезной информации должен быть критической информацией, прежде чем будут выведены журналы INFO.
Как и в приведенном выше описании, вы можете использовать WARN для предупреждения о конфиденциальных операциях пользователей или неожиданных результатах, но при этом никаких происшествий не происходит. Если у вас есть какие-либо сомнения, вы можете проверить журнал WARN для устранения неполадок позже. ОШИБКА используется в более серьезных ситуациях, требующих технического онлайн-устранения неполадок, поэтому в процессе разработки необходимо тщательно учитывать положение печати ОШИБКИ.
Основные моменты ERROR следующие:
Все логи, относящиеся к интерфейсу,а такжеключевые методыженьшеняи返回值都建议加上бревно。
Справочный шаблон:
"%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n"
если... иначе... или переключитьсяЕсли условий ветки много, рекомендуется их распечатать перед входом в ветку.,Конечно, вы также можете использовать этот метод, чтобы определить, какую ветку вы используете при самостоятельной отладке:
String type = ???;
if(log.isDebugEnbale()){
log.debug("Текущий тип ветки: {}", type);
}
if(type == "xxx"){
}else if(type == "aaa"){
}
// или
switch(type){
case "xxx":
// ....
break;
case "xxx":
// ....
break;
}
Эта статья предназначена для журналов низкого уровня, таких как отладка и трассировка, а также для сокращения потерь при печати онлайн-журналов вызовов без журналов:
User user = new User(666L, "xxxx", "xxxx");
if (log.isDebugEnabled()) {
log.debug("userId is: {}", user.getId());
}
людиlombokОни все дали один@Slf4j
的аннотация,Так что используйте это.
На самом деле, это потому, что slf4j также был написан автором log4j, и его совместимость с фасадами получила широкую оценку. Потом... потом apach научился этому, я тоже могу это сделать! Конечным результатом является то, что компоненты системы журналирования Java с открытым исходным кодом чрезвычайно запутаны и плохи, как кусок дерьма. Из этой ситуации также видно, что установление стандартов очень важно.
При компиляции в класс с помощью Java StringBuffer будет использоваться для выполнения операций сращивания строк. Я обнаружил, что независимо от того, насколько велик или мал проект, даже когда речь идет о фреймворке, мы часто видим сращивание знаков +. Хотя влияние оптимизации компиляции более высоких версий JDK на самом деле очень мало, лично я все еще не замечаю этого. Мне не нравится такое соединение знаков +, оно недостаточно элегантно.
Правильное использование
logger.info("Processing trade with id: {} and symbol : {} ", id, symbol);
использовать+
Оператор для строки Сращивание,Есть определенная суммаПотеря производительности
logger.info("Processing trade with id: " + id + " and symbol: " + symbol);
<appender name="FILE_ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<appender-ref ref="ASYNC"/>
</appender>
Причины не использовать:
e.printStackTrace()
打印出的堆栈бревно跟业务代码бревно是交错混合在一起的,Обычно неудобно устранять неполадки в журналах исключений.e.printStackTrace()
Строка, сгенерированная оператором, записывает информацию о стеке.,Если сообщение слишком длинное и его слишком много,В блоке памяти, где расположен пул строковых констант, нет места, то есть память заполнена.,Так,Запрос пользователя застрял~Следует использовать следующее правильное употребление:
try{
// Обработка бизнес-кода
}catch(Exception e){
log.error("В вашей программе есть исключение",e);
}
Например, следующий журнал не имеет значения:
try {
//Обработка бизнес-кода
} catch (Exception e) {
// ошибка
LOG.error('В вашей программе есть исключение');
}
На самом деле метод обработки очень прост:
try{
// Обработка бизнес-кода
}catch(Exception e){
log.error("В вашей программе есть исключение",e);
}
Также необходимо обратить внимание,e.getMessage()
Подробная информация об исключениях стека не будет регистрироваться.,Будет записана только основная информация описания.,Не способствует решению проблем. также,如果использовать Hutool Tools, есть класс инструментов для извлечения информации об исключениях, что более удобно.
Это примечание очень простое, но очень важное. Старайтесь избегать его использования. Exception Вместо того, чтобы принимать их все, вам необходимо рассмотреть возможность предоставления более полезной информации журнала для конкретных исключений, что может сократить время на устранение неполадок в Интернете.
Мало того, что в системе будет много журналов отладки, но также возникнет проблема с выводом журнала отладки платформы. Включение онлайн-отладки может легко заполнить диск и заставить ЦП ждать дискового ввода-вывода, что приведет к тому, что процессор будет ожидать дискового ввода-вывода. напрямую влияют на системные службы с течением времени.
Вложенные исключения — это самый простой сценарий поглощения исключений. Во многих случаях блоки кода метода вложены слой за слоем и забывают перехватывать исключения внутри. Внешний уровень перехватывает исключения, но на самом деле вообще не может их получить. тогда это само собой значительно усложнит поиск и устранение неисправностей.
В этой статье предполагается, что перед написанием метода или класса проектирования необходимо заранее продумать, как обрабатывать исключения, и своевременно просматривать код после выполнения всего вызова.
Ниже приводится соответствующий контрпример:
try{
// Обработка бизнес-кода
try{
// Обработка бизнес-кода
}catch(Exception e){
log.error("В вашей программе есть исключение",e);
}
}catch(Exception e){
log.error("В вашей программе есть исключение",e);
}
Вызов исключения после записи — очень опасная операция.,Потому что внешний уровень может не обработать исключение снова после того, как внутренний уровень его перехватит.,в случае Пользовательское Примечание Устранить проблему еще сложнее,Кроме того, такой подход приведет кСтековая вторичная печать,Очень расточительно влияет на производительность системы,
Контрпример следующий:
try{
// Обработка бизнес-кода
}catch(Exception e){
log.error("IO exception", e);
throw new MyException(e);
}
Различные типы журналов могут быть разделены,напримерaccess.log
,илиerrorуровеньerror.log
,Все можно распечатать отдельно в файл. Разделение по бизнес-модулям – это тоже способ,Таким образом, модули, ответственные за каждый из них, могут четко видеть журналы.
Если журнал можно выразить одной строкой, попробуйте использовать одну строку для выражения смысла.
log.info("Этот пользователь является участником,Id:{}",user,getUserId());
//Избыточно, можно объединить с предыдущим журналом
log.info("Начать обработку логики членства, идентификатор: {}", user, getUserId());
Если это журнал основного функционального модуля, на самом деле допустимо распечатать больше контента, но следует отметить, что распечатанный журнал должен позволять немедленно обнаружить проблему.
Ниже приводится стандартная печать журнала:
2018-05-22 15:35:53.850 TRACE TDWZLog [0x00001b10] <36> <TDWZProtocol::Init>,TDWZProtocol::Init
2018-05-22 15:35:53.850 TRACE TDWZLog [0x00001b10] <89> <TDWZProtocol::Init>,End in processing TDWZProtocol::Init
2018-05-22 15:35:53.853 TRACE TDWZLog [0x00001b10] <142> <TDWZProtocol::Connect>,Connect Execute finish
2018-05-22 15:35:53.853 TRACE TDWZLog [0x00002f10] <149> <GetAlarmEventPro>,Enter GetAlarmEventPro func
2018-05-22 15:39:36.382 WARN TrackLog [0x000029fc] - [ internal WARN htrace_server_convert_msgstring_to_contextintls(493) ] detect input id error, trace_id span_id,this chain may not be tracked.
2018-05-22 15:39:36.383 WARN TrackLog [0x000029fc] - [ internal WARN htrace_server_receive(195) ] can not detect trace_id in context, this chain may not be tracked.
2018-05-22 15:39:36.383 TRACE TDWZLog [0x000029fc] <231> <TDWZProtocol::DisConnect>,TDWZProtocol::DisConnect
2018-05-22 15:39:37.502 TRACE TDWZLog [0x00002f10] <225> <GetAlarmEventPro>,End Get AlarmEventPro Func
2018-05-22 15:39:37.503 TRACE TDWZLog [0x000029fc] <241> <TDWZProtocol::DisConnect>,close socket
2018-05-22 15:39:37.503 TRACE TDWZLog [0x000029fc] <242> <TDWZProtocol::DisConnect>,Execute DisConnect function succeed.
DRV_LOG_TRACE("Connect Execute start");
DRV_LOG_TRACE("Connect Execute finish");
DRV_LOG_TRACE("DisConnect func");
DRV_LOG_TRACE("Execute DisConnect function succeed.");
DRV_LOG_TRACE("Enter UploadEvent Func");
DRV_LOG_TRACE("extInfo = %s", Extension);
DRV_LOG_TRACE("Send a Msg ");
DRV_LOG_TRACE("- Connect Execute start");
DRV_LOG_TRACE("- Connect Execute finish");
DRV_LOG_TRACE("- Enter GetAlarmEventPro func");
DRV_LOG_TRACE("- Receive an info");
DRV_LOG_TRACE("- End Get AlarmEventPro Func");
DRV_LOG_TRACE("- DisConnect func");
DRV_LOG_TRACE("- Execute DisConnect function succeed.");
DRV_LOG_TRACE("- Enter UploadEvent Func");
DRV_LOG_TRACE("- Leave UploadEvent Func");
DRV_LOG_TRACE("- ============Сработала сигнализация электросети");
DRV_LOG_TRACE("- ============Начать отправку значений тока и напряжения");
DRV_LOG_TRACE("- ============ Отправьте значения тока и напряжения повторно через интервал более минуты");
DRV_LOG_INFO("- UpdataEvent nchal= %d,EventID = %d.",iChannelNo,nEventType);
DRV_LOG_INFO("- do not support doControl");
DRV_LOG_INFO("- channelId = %s, nStatusType = %d", channelId.c_str(), nStatusType)
DRV_LOG_DEBUG("- Ситуация выходного сигнала тревоги: номер сетки: %d, номер сигнала тревоги: %d, содержание сигнала тревоги: %s.", datas.data1.chn, datas.data1.alarm_num, datas.data1.alarms);
DRV_LOG_DEBUG("- Ситуация выходного сигнала тревоги: номер сетки: %d, номер сигнала тревоги: %d, содержание сигнала тревоги: %s.", datas.data2.chn, datas.data2.alarm_num, datas.data2.alarms);
DRV_LOG_DEBUG("- Ситуация выходного сигнала тревоги: номер сетки: %d, номер сигнала тревоги: %d, содержание сигнала тревоги: %s.", datas.data3.chn, datas.data3.alarm_num, datas.data3.alarms);
DRV_LOG_DEBUG("- Ситуация выходного сигнала тревоги: номер сетки: %d, номер сигнала тревоги: %d, содержание сигнала тревоги: %s.",datas.data4.chn,datas.data4.alarm_num,datas.data4.alarms);
DRV_LOG_DEBUG("- ============datas.data1.huab = %d",datas.data1.huab);
DRV_LOG_DEBUG("- ============datas.data1.hiab = %d",datas.data1.hiab);
DRV_LOG_DEBUG("- ============datas.data2.huab = %d",datas.data2.huab);
DRV_LOG_DEBUG("- ============datas.data2.hiab = %d",datas.data2.hiab);
DRV_LOG_DEBUG("- ============datas.data3.huab = %d",datas.data3.huab);
DRV_LOG_DEBUG("- ============datas.data3.hiab = %d",datas.data3.hiab);
DRV_LOG_DEBUG("- ============datas.data4.huab = %d",datas.data4.huab);
DRV_LOG_DEBUG("- ============datas.data4.hiab = %d",datas.data4.hiab);
DRV_LOG_DEBUG("- Alarm is : %s",szEvent.c_str());
DRV_LOG_DEBUG("- GetChannelExtInfo channelId=%s", channelId.c_str());
DRV_LOG_DEBUG("- nChan = %d, szInfo = %s", nChan, szInfo);
DRV_LOG_WARN("[0x%08x] - invaild event msg,discard it", DRV_INVALID_ARG);
DRV_LOG_WARN("[0x%08x] - Can't find channel by channelId");
DRV_LOG_WARN("[0x%08x] - [DWSdk.errorcode=0x%08x]Connect device failed", DRV_CONNECT_FAILED, sdkErrCode);
DRV_LOG_WARN("[0x%08x] - [DWSdk.errorcode=0x%08x]dw_start_receive failed", DRV_ERROR, sdkErrCode);
DRV_LOG_WARN("[0x%08x] - [DWSdk.errorcode=0x%08x]Communicate failed, socket recv error", DRV_ERROR, DW_SOCKET_RECV_ERROR);
DRV_LOG_WARN("[0x%08x] - [DWSdk.errorcode=0x%08x>other error", DRV_ERROR, iGetResult);
DRV_LOG_WARN("[0x%08x] - [DWSdk.errorcode=0x%08x>other error", DRV_ERROR, iGetResult);
DRV_LOG_WARN("[0x%08x] - SetEventCallBack should be called first", DRV_ERROR);
DRV_LOG_ERROR("Init DwSDK filded;<errCode=%d>", initRet);
DRV_LOG_ERROR("Connect device failed");
DRV_LOG_ERROR("Create thread failed");
DRV_LOG_ERROR("dw_start_receive failed");
DRV_LOG_ERROR("Communicate failed, socket recv error");
DRV_LOG_ERROR("other error<errCode=%d>", iGetResult);
DRV_LOG_ERROR("SetEventCallBack should be called first");
DRV_LOG_ERROR("[0x%08x] - [DWSdk.errorcode=0x%08x]Init DwSDK filded", DRV_INIT_FAILED, initRet);
DRV_LOG_ERROR("- [HPR.errorcode=0x%08x]Create thread failed", HPR_GetLastError());
Значение 0x%08x можно объяснить на примере.,
printf("0x%08x", 0x1234);
,После форматирования он станет0x00001234
。