- ローカル環境の Spring Boot アプリにログをJSON形式で出力
- pom.xml に依存を追加 (必要ない?かも?)
-
<mdc/>
と<structuredArguments/>
で出力内容を追加できる
What is it?
- enables logging in JSON format
- flexible. options to customize the JSON output
- convert Logback events into a format suitable for Logstash
version used: 8.1
-
add dependency to
pom.xml
<!-- https://mvnrepository.com/artifact/net.logstash.logback/logstash-logback-encoder --> <dependency> <groupId>net.logstash.logback</groupId> <artifactId>logstash-logback-encoder</artifactId> <version>8.1</version> </dependency>
-
create and add log configuration file
<configuration> <springProperty name="env" source="app.env" defaultValue="local"/> <springProperty name="version" source="build.version" defaultValue="dev"/> <springProperty name="appName" source="spring.application.name" defaultValue="myapp"/> <appender name="JSON" class="ch.qos.logback.core.ConsoleAppender"> <encoder class="net.logstash.logback.encoder.LoggingEventCompositeJsonEncoder"> <providers> <timestamp/><level/><threadName/><loggerName/> <mdc/> <!-- requestId/job/day --> <structuredArguments/> <!-- kv("key", val) support --> <message/><stackTrace/> <provider class="net.logstash.logback.composite.GlobalCustomFieldsJsonProvider"> <customFields>{"service":"${appName}","env":"${env}","version":"${version}"}</customFields> </provider> </providers> </encoder> </appender> <root level="INFO"><appender-ref ref="JSON"/></root> </configuration>
what each tag means
-
appender
: where to send it (eg. console, file, TCP…) -
encoder
: how to turn the log event into bytes (eg. JSON, txt) -
provider
: specifies JSON field to include -
structuredArguments
: allows caller to put a line specific log items-
log.info("fetch completed", kv("meetings_found", found), kv("duration_ms", tookMs));
-
他にもcustomFields
やMarkers
を使ってfieldの追加ができる
my confusions
1. <mdc/>
vs <structuredArguments/>
to me, it looks like mdc
and structuredArguments
are doing the same thing - allowing callers to add something specific to caller's class to the log.
✏️ scope is different
- mdc: implicit context for the whole request/job (all log lines in that scope)
- structuredArguments: just on that one log call line
TLDR: MDC = context-for-many; Structured args = details-for-one
takeaway
- context you want on every line of a request/job (e.g., requestId, job, day)? use MDC
- event-specific details on a single log call? use structured args
- common to use both: MDC for correlation + structured args for details
2. <fieldNames/>
vs <providers/>
to me they both specify fields to include in the json log output.
✏️ encoder styles are different: LogstashEncoder
and LoggingEventCompositeJsonEncoder
-
<fieldNames>
is forLogstashEncoder
- it just renames keys like
timestamp → time
,message → msg
- ✅good for quick setup
- ❌less flexible
- it just renames keys like
-
<providers>
is forLoggingEventCompositeJsonEncoder
- it picks which components to emit and in what order
- it lets you set fieldName directly (so you can do the same renames you’d do in )
takeaway
-
fieldNames
= rename keys on a fixed set of fields (LogstashEncoder) -
providers
= compose your JSON from modular parts (Composite encoder), including the ability to rename per provider and skip what you don’t want
3. how does the program find configuration file logback-spring.xml
without specifying?
(answers from AI)
Logback, by default, searches for configuration files in the root of the classpath. This means if you place logback.xml in the src/main/resources directory of a Maven or Gradle project, it will be automatically detected at runtime.
Spring Boot provides additional capabilities by recognizing logback-spring.xml
Logback looks for files in a specific order:
-
logback-test.xml
(often used for testing environments) logback.groovy
logback.xml
what's already included in the log by default
Field | Description |
---|---|
@timestamp |
Time of the log event (ISO_OFFSET_DATE_TIME ) - see Customizing Timestamp
|
@version |
Logstash format version (e.g. 1 ) - see Customizing Version
|
message |
Formatted log message of the event - see Customizing Message |
logger_name |
Name of the logger that logged the event |
thread_name |
Name of the thread that logged the event |
level |
String name of the level of the event |
level_value |
Integer value of the level of the event |
stack_trace |
(Only if a throwable was logged) The stacktrace of the throwable. Stackframes are separated by line endings. |
tags |
(Only if tags are found) The names of any markers not explicitly handled. (e.g. markers from MarkerFactory.getMarker will be included as tags, but the markers from Markers will not.) This can be fully disabled by specifying <includeTags>false</includeTags> , in the encoder/layout/appender configuration. |