5. springboot
새로만들기 귀찮다면 내가 올린 테스트 사용~!
https://github.com/victory940209/testspringboot/tree/main/testSpringboot
1. pom.xml 설정
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.8</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
...
<properties>
<java.version>11</java.version>
<spring-cloud.version>3.1.5</spring-cloud.version>
</properties>
...
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
<version>${spring-cloud.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
<version>${spring-cloud.version}</version>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-core</artifactId>
</dependency>
<dependency>
<groupId>io.micrometer</groupId>
<artifactId>micrometer-tracing-bridge-brave</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>io.zipkin.brave</groupId>
<artifactId>brave-instrumentation-http</artifactId>
<version>5.13.3</version>
</dependency>
<dependency>
<groupId>io.zipkin.brave</groupId>
<artifactId>brave</artifactId>
<version>5.13.3</version>
</dependency>
<dependency>
<groupId>io.zipkin.reporter2</groupId>
<artifactId>zipkin-reporter-brave</artifactId>
<version>2.16.3</version>
</dependency>
<!-- 로그를 Loki로 바로 보내려면 설정 필요 -->
<dependency>
<groupId>com.github.loki4j</groupId>
<artifactId>loki-logback-appender</artifactId>
<version>1.4.0-m1</version>
</dependency>
...
처음에 spring boot 3으로 해보려고 할때 sleuth가 spring boot3에서 지원을 하지않았다.....그래서 io.micrometer와 io.zipkin를 사용해서 했는데 회사에서 버전을 낮추자고 해서...... sleuth가 다시 추가.... 정리를 한번 하고 다시 올리겠다.
2.application.yml 설정
server:
port: 9000
spring:
application:
name: springboot01
pid:
file: /data1/springboot/springboot01.pid
zipkin:
base-url: http://127.0.0.1:9411 #zipkin 연결 부분 ip.port
logging:
config: classpath:logback-local.xml #logback 파일 위치 설정
3. logback설정 (Loki에 데이터를 바로 보내는 설정)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE xml>
<configuration debug="false" scan="true"
scanPeriod="30 seconds">
<property name="LOGS_PATH" value="/data/logs" />
<springProperty scope="context" name="appName" source="spring.application.name"/>
<appender name="log_file"
class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${LOGS_PATH}/springboot01.log</file>
<encoder
class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level) %magenta(%-4relative) --- [${appName} ,%blue(%X{traceId}), %green(%X{spanId})] %cyan(%logger{20}) : %msg%n</pattern>
</encoder>
<rollingPolicy
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${LOGS_PATH}/springboot01_%d{yyyyMMdd}.log</fileNamePattern>
<maxHistory>60</maxHistory>
</rollingPolicy>
</appender>
<logger name="com.victory" level="DEBUG">
<appender-ref ref="log_file" />
</logger>
<appender name="console"
class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level) %magenta(%-4relative) --- [${appName}, %blue(%X{traceId}), %green(%X{spanId}) %X{sessionId}] %cyan(%logger{20}) : %msg%n</pattern>
</layout>
</appender>
<appender name="LOKI" class="com.github.loki4j.logback.Loki4jAppender">
<http>
<url>http://192.168.0.103:3200/loki/api/v1/push</url>
</http>
<format>
<label>
<pattern>app=${appName},host=${HOSTNAME},traceID=%X{traceId:-NONE},level=%level</pattern>
</label>
<message>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level) %magenta(%-4relative) --- [${appName}, %blue(%X{traceId}), %green(%X{spanId})] %cyan(%logger{20}) : %msg%n</pattern>
</message>
<sortByTime>true</sortByTime>
</format>
</appender>
<root level="DEBUG">
<appender-ref ref="console" />
<appender-ref ref="log_file" />
<appender-ref ref="LOKI" />
</root>
<logger name="com.victory" level="DEBUG" additivity="false">
<appender-ref ref="console" />
<appender-ref ref="log_file" />
<appender-ref ref="LOKI" />
</logger>
</configuration>
여기서 중요한점은
<property name="LOGS_PATH" value="/data/logs" />
-> promtail에서 설정한 위치
<file>${LOGS_PATH}/springboot01.log</file>
-> promtail에서 설정한 이름
<springProperty scope="context" name="appName" source="spring.application.name"/>
->application.yml에서 설정한 spring.application.name을 appName변수에 담은것
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(%-5level) %magenta(%-4relative) --- [${appName} ,%blue(%X{traceId}), %green(%X{spanId})] %cyan(%logger{20}) : %msg%n</pattern>
-> 로그 패턴안에 appName, traceId, spanId를 넣어다는것
4. java 설정(log tracing 처리)
Config 생성 http 통신을 할때 RestTemplate를 이용하여 하는데 해당 을 관찰하기 위해서 import io.micrometer.observation 설정
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
import io.micrometer.observation.ObservationRegistry;
import io.micrometer.observation.aop.ObservedAspect;
@Configuration(proxyBeanMethods = false)
public class MyConfiguration {
@Bean
RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
@Bean
ObservedAspect observedAspect(ObservationRegistry observationRegistry) {
return new ObservedAspect(observationRegistry);
}
@Bean
ObservationRegistry observationRegistry() {
return ObservationRegistry.create();
}
}
Controller를 생성
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.client.RestTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import io.micrometer.observation.Observation;
import io.micrometer.observation.ObservationRegistry;
@Slf4j
@RestController
public class TestController {
@Autowired
private ObservationRegistry observationRegistry;
@Autowired
RestTemplate restTemplate;
@GetMapping(value = "/test", produces = MediaType.APPLICATION_JSON_VALUE)
public Map<String, Object> test(@RequestParam Map<String, Object> param) throws Exception {
log.debug("param : {}", param);
return Map.of("key1", "value1", "key2", "value2");
}
@PostMapping(value = "/testResultPost")
public Map<String, Object> testResultVoPost(@RequestBody Map<String, Object> param) throws Exception {
String url = param.get("url").toString();
String port = param.get("port").toString();
String resulturl = "http://127.0.0.1:" + port + "/" + url;
Observation.createNotStarted("user.name", observationRegistry)
.contextualName("httpGetConnection")
.lowCardinalityKeyValue(url, url)
.observe(() -> {
ResponseEntity respEntity = restTemplate.getForEntity(resulturl, Map.class);
log.info("result : {}", respEntity.getBody());
});
return Map.of("key12345", "value12345", "key2", "value2");
}
...
}
5. 실행
로그내용에 logback 설정 하였던 appName, traceId, spanId 3개가 나오는것을 알수 있다.
zipkin 화면
grafana화면
성공! 이제 springboot01에서 springboot02를 호출 할때 로그 트레이싱이 잘되는지 확인해볼것이다.!