Fundamentals 16 min read

Best Practices for Writing Application Logs and Understanding Log Levels

This article explains why proper logging is essential for software maintenance, outlines the purposes of logs, describes the requirements for readable, performant, and space‑efficient log output, and details Log4j components, log‑level hierarchy, and concrete code examples for TRACE, INFO, DEBUG, WARN, and ERROR logging.

Java Captain
Java Captain
Java Captain
Best Practices for Writing Application Logs and Understanding Log Levels

Writing logs in a program is crucial but often overlooked; good logs greatly reduce maintenance effort, while developers under time pressure may neglect this tedious task.

Developers should cultivate good logging habits from the start and allocate sufficient time for it during development.

1.1 Purpose of Logs

Typical program logs serve several needs:

Audit logs that record user actions, sometimes required by regulators.

Quickly locate the root cause of problems.

Trace the execution flow of the program.

Track data changes.

Collect statistics and performance analysis.

Gather runtime environment information.

After a system goes live, the first step when an exception occurs is to determine what happened: user actions, environment impact, data changes, and whether the issue repeats. Logs provide the first‑hand information needed for this investigation.

1.2 Requirements for Writing Logs

1.2.1 Readability

Logs should be understandable not only to the author but also to other developers who have never seen the source code. Using obscure symbols such as ++++++++++ , ========== , or ------ makes logs hard to read and is a bad practice.

Separating logs into different files helps reduce noise, and using English text avoids garbled characters caused by unsupported encodings.

1.2.2 Performance

Writing logs to files or databases consumes I/O resources; controlling log output improves program performance. For example, avoid logging insignificant messages inside large loops and check the log level before calling expensive logging methods (e.g., isDebugEnabled() ).

1.2.3 Disk Space

Logs are usually stored on disk. Using log rotation and regularly cleaning old files prevents logs from filling the disk, which can cause the application to fail to start.

1.2.4 Timeliness

Sometimes problems are not detected immediately; retaining logs for a reasonable period enables retrospective analysis.

1.2.5 Log Levels

In production environments logs are typically kept at INFO level or higher, so the logging implementation must still provide enough information for diagnosis.

1.2.6 Log Content

Log messages should describe business‑related actions clearly and avoid leaking sensitive data such as usernames or passwords. Consistent encoding (preferably English) prevents unreadable characters.

1.2.7 Log Format

A standard log entry includes timestamp, log level, code location, message content, and optionally error codes.

2 Log Levels and Their Meaning

Log4j, an Apache open‑source logging framework, allows directing log output to consoles, files, GUI components, or remote servers, configuring output formats, and controlling log generation through defined levels.

2.1 Log4j Components

Log4j consists of three main parts: Loggers, Appenders, and Layouts.

2.1.1 Logger

Controls which logging statements are enabled and applies level filtering.

2.1.2 Appender

Specifies where the log is written (console, file, etc.).

2.1.3 Layout

Defines the visual format of each log entry.

2.2 Log Levels

Log4j defines six levels: TRACE , DEBUG , INFO , WARN , ERROR and FATAL . Only messages with a level equal to or higher than the configured threshold are output.

2.2.1 TRACE

Very fine‑grained informational events, usually tracing function calls without variable data.

2.2.2 DEBUG

Fine‑grained details useful during development for debugging.

2.2.3 INFO

Highlights important runtime information; suitable for production but should not be overused.

2.2.4 WARN

Indicates potentially problematic situations that the program can recover from automatically.

2.2.5 ERROR

Reports errors that do not halt the application but may require attention; often includes error codes.

2.2.6 FATAL

Serious errors that cause the application to terminate and require a restart.

2.3 Level Hierarchy

The relationship between levels is:

ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF

Log4j recommends using the four most common levels: DEBUG , INFO , WARN , and ERROR .

3 Log Formatting Examples

Studying well‑written logs helps form a personal style. Below are examples of good logging statements.

3.1 TRACE Log Example

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("- =============间隔超过分钟再次发送电流电压值");

3.2 INFO Log Example

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);

3.3 DEBUG Log Example

DRV_LOG_DEBUG("- 输出报警情况:电网编号:%d,报警数量:%d,报警内容:%s.", datas.data1.chn, datas.data1.alarm_num, datas.data1.alarms);
DRV_LOG_DEBUG("- =============datas.data1.huab = %d", datas.data1.huab);
DRV_LOG_DEBUG("- =============datas.data1.hiab = %d", datas.data1.hiab);
... (additional similar lines omitted for brevity) ...
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);

3.4 WARN Log Example

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] - SetEventCallBack should be called first", DRV_ERROR);

3.5 ERROR Log Example

DRV_LOG_ERROR("Init DwSDK filded;
", 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
", 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());

The placeholder [0x%08x] in format strings prints a hexadecimal value padded to eight digits, e.g., printf("0x%08x", 0x1234); outputs 0x00001234 .

software developmentBest PracticesLogginglog4jlog levels
Java Captain
Written by

Java Captain

Focused on Java technologies: SSM, the Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading; occasionally covers DevOps tools like Jenkins, Nexus, Docker, ELK; shares practical tech insights and is dedicated to full‑stack Java development.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.