Il existe une application Spring Boot existante qui utilise l'enregistreur SLF4J. J'ai décidé d'ajouter le support du traçage distribué via l'API standard opentracing
avec Jaeger comme traceur. Il est vraiment étonnant de voir à quel point la configuration initiale est facile - tout ce qui est nécessaire est simplement d'ajouter deux dépendances au pom.xml
:
<dependency>
<groupId>io.opentracing.contrib</groupId>
<artifactId>opentracing-spring-web-autoconfigure</artifactId>
<version>${io.opentracing.version}</version>
</dependency>
<dependency>
<groupId>io.jaegertracing</groupId>
<artifactId>jaeger-core</artifactId>
<version>${jaegerVersion}</version>
</dependency>
et fournir au bean Tracer
la configuration:
@Bean
public io.opentracing.Tracer getTracer() throws ConfigurationException {
return new new io.jaegertracing.Tracer.Builder("my-spring-boot-app").build();
}
Tout fonctionne comme un charme - les demandes d'application sont traitées par Jaeger et les portées sont créées:
Cependant, dans l'intervalle Logs
, il n'y a que preHandle
& afterCompletion
événements avec des informations sur la classe/méthode qui ont été appelées lors de l'exécution de la demande (aucun journal produit par slf4j
l'enregistreur est collecté):
La question est de savoir s'il est possible de configurer le Tracer pour récupérer les journaux produits par l'enregistreur d'application (slf4j
dans mon cas) pour que tous les journaux d'application se fassent via: LOG.info
/LOG.warn
/LOG.error
etc. serait également reflété dans Jaeger
[~ # ~] note [~ # ~] : J'ai compris comment se connecter pour s'étendre manuellement via opentracing
API par exemple:
Scope scope = tracer.scopeManager().active();
if (scope != null) {
scope.span().log("...");
}
Et faites quelques manipulations manuelles avec la balise ERROR
pour le traitement des exceptions dans les filtres, par exemple.
} catch(Exception ex) {
Tags.ERROR.set(span, true);
span.log(Map.of(Fields.EVENT, "error", Fields.ERROR_OBJECT, ex, Fields.MESSAGE, ex.getMessage()));
throw ex
}
Mais, je me demande toujours s'il est possible de configurer le traceur pour récupérer les journaux d'application automatically
:
LOG.info
-> tracer ajoute un nouveau journal à la plage activeLOG.error
-> tracer ajoute un nouveau journal à la plage active et ajoute la balise ERROR
[~ # ~] mise à jour [~ # ~] : j'ai pu ajouter les journaux d'application au traceur en ajoutant un wrapper pour l'enregistreur, par ex.
public void error(String message, Exception e) {
Scope scope = tracer.scopeManager().active();
if (scope != null) {
Span span = scope.span();
Tags.ERROR.set(span, true);
span.log(Map.of(Fields.EVENT, "error", Fields.ERROR_OBJECT, e, Fields.MESSAGE, e.getMessage()));
}
LOG.error(message, e);
}
Cependant, jusqu'à présent, je n'ai pas pu trouver d'options de configuration d'opentracing qui permettraient d'ajouter automatiquement les journaux d'application au traceur par défaut. Fondamentalement, il semble que le développeur devrait ajouter des journaux supplémentaires au traceur par programme si nécessaire. De plus, après avoir étudié davantage le traçage, il semble que normalement logging
et tracing
sont traités séparément et l'ajout de tous les journaux d'application au traceur n'est pas une bonne idée (le traceur devrait principalement inclure des exemples de données et étiquettes d'identification de la demande)
https://github.com/opentracing-contrib/Java-spring-cloud le projet envoie automatiquement la journalisation standard à la plage active. Ajoutez simplement la dépendance suivante à votre pom.xml
<dependency>
<groupId>io.opentracing.contrib</groupId>
<artifactId>opentracing-spring-cloud-starter</artifactId>
</dependency>
Ou utilisez ceci https://github.com/opentracing-contrib/Java-spring-cloud/tree/master/instrument-starters/opentracing-spring-cloud-core starter si vous souhaitez uniquement l'intégration de la journalisation .
Voici ce que j'ai fait pour que les journaux liés à jdbc de Logback (Slf4j) soient écrits dans le serveur Jaeger:
En commençant par la configuration de Logback (logback-spring.xml):
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<include resource="org/springframework/boot/logging/logback/defaults.xml"/>
<springProperty scope="context" name="consoleAppender" source="logging.console.enabled" defaultValue="false"/>
<property name="ENV" value="${SPRING_PROFILES_ACTIVE:-dev}"/>
<include resource="org/springframework/boot/logging/logback/console-appender.xml"/>
<jmxConfigurator/>
<appender name="JSON_CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="net.logstash.logback.encoder.LogstashEncoder">
<includeMdc>true</includeMdc>
<customFields>{"log_type":"application","appname":"products-rs-load", "environment": "${ENV}"}
</customFields>
</encoder>
</appender>
<appender name="myAppender" class="com.test.MyAppender">
</appender>
<root level="DEBUG">
<appender-ref ref="myAppender"/>
</root>
<logger name="org.springframework.boot" level="INFO"/>
<logger name="p6spy" additivity="false" level="ALL">
<appender-ref ref="myAppender" />
</logger>
</configuration>
Voici mon appender:
import ch.qos.logback.core.AppenderBase;
public class MyAppender extends AppenderBase {
@Override
protected void append(Object eventObject) {
LoggingEvent event = (LoggingEvent) eventObject;
final String loggerName = event.getLoggerName();
// only DB related operations have to be traced:
if (!("p6spy".equals(loggerName))) {
return;
}
/// Tracer config is straight forward
Span sp = TracingUtils.buildActiveChildSpan(loggerName, null);
if (Level.ERROR.equals(event.getLevel())) {
TracingUtils.setErrorTag(sp);
}
Map<String, String> fields = new HashMap<String, String>();
fields.put("level", event.getLevel().toString());
fields.put("logger", loggerName);
fields.put("content", event.getFormattedMessage());
sp.log(fields);
sp.finish();
}
}
Ensuite, j'utilise opentracing-spring-jaeger-cloud-starter
<dependency>
<groupId>io.opentracing.contrib</groupId>
<artifactId>opentracing-spring-jaeger-cloud-starter</artifactId>
<version>2.0.0</version>
</dependency>
J'ai une seule ligne dans la console avec la trace et l'étendue actuelles i.j.internal.reporters.LoggingReporter: Span a signalé: f1a264bbe2c7eae9: f1a264bbe2c7eae9: 0: 1 - my_method
2019-05-20 16:07:59.549 DEBUG 24428 --- [ctor-http-nio-2] o.s.w.s.adapter.HttpWebHandlerAdapter : [632103eb] HTTP POST "/api"
2019-05-20 16:07:59.552 DEBUG 24428 --- [ctor-http-nio-2] s.w.r.r.m.a.RequestMappingHandlerMapping : [632103eb] Mapped to public reactor.core.publisher.Mono<org.springframework.http.ResponseEntity<model.Response>> service.controller.method(model.Request)
2019-05-20 16:07:59.559 DEBUG 24428 --- [ctor-http-nio-2] .s.w.r.r.m.a.RequestBodyArgumentResolver : [632103eb] Content-Type:application/json
2019-05-20 16:08:01.450 INFO 24428 --- [ctor-http-nio-2] i.j.internal.reporters.LoggingReporter : Span reported: f1a264bbe2c7eae9:f1a264bbe2c7eae9:0:1 - method
2019-05-20 16:08:01.450 DEBUG 24428 --- [ctor-http-nio-2] o.s.w.s.adapter.HttpWebHandlerAdapter : [632103eb] Completed 200 OK
Ensuite, j'utilise Spring-cloud-starter-sleuth
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
J'ai la trace et les étendues comme [my-service, 90e1114e35c897d6,90e1114e35c897d6, false] dans chaque ligne et c'est utile pour le battement de fichiers dans ELK
2019-05-20 16:15:38.646 DEBUG [my-service,,,] 12548 --- [ctor-http-nio-2] o.s.w.s.adapter.HttpWebHandlerAdapter : [3e578505] HTTP POST "/api"
2019-05-20 16:15:38.662 DEBUG [my-service,,,] 12548 --- [ctor-http-nio-2] o.s.c.s.instrument.web.TraceWebFilter : Received a request to uri [/api]
2019-05-20 16:15:38.667 DEBUG [my-service,,,] 12548 --- [ctor-http-nio-2] o.s.c.s.instrument.web.TraceWebFilter : Handled receive of span NoopSpan(90e1114e35c897d6/90e1114e35c897d6)
2019-05-20 16:15:38.713 DEBUG [my-service,90e1114e35c897d6,90e1114e35c897d6,false] 12548 --- [ctor-http-nio-2] s.w.r.r.m.a.RequestMappingHandlerMapping : [3e578505] Mapped to public reactor.core.publisher.Mono<org.springframework.http.ResponseEntity<model.Response>> service.controller.method(model.Request)
2019-05-20 16:15:38.727 DEBUG [my-service,90e1114e35c897d6,90e1114e35c897d6,false] 12548 --- [ctor-http-nio-2] .s.w.r.r.m.a.RequestBodyArgumentResolver : [3e578505] Content-Type:application/json
2019-05-20 16:15:39.956 DEBUG [my-service,90e1114e35c897d6,90e1114e35c897d6,false] 12548 --- [gine-1-thread-1] .s.w.r.r.m.a.ResponseEntityResultHandler : Using 'application/json;charset=UTF-8' given [*/*] and supported [application/json;charset=UTF-8, application/*+json;charset=UTF-8, text/event-stream]
2019-05-20 16:15:40.009 DEBUG [my-service,90e1114e35c897d6,90e1114e35c897d6,false] 12548 --- [ctor-http-nio-2] o.s.c.s.instrument.web.TraceWebFilter : Adding a method tag with value [method] to a span NoopSpan(90e1114e35c897d6/90e1114e35c897d6)
2019-05-20 16:15:40.009 DEBUG [my-service,90e1114e35c897d6,90e1114e35c897d6,false] 12548 --- [ctor-http-nio-2] o.s.c.s.instrument.web.TraceWebFilter : Adding a class tag with value [Controller] to a span NoopSpan(90e1114e35c897d6/90e1114e35c897d6)
2019-05-20 16:15:40.010 DEBUG [my-service,90e1114e35c897d6,90e1114e35c897d6,false] 12548 --- [ctor-http-nio-2] o.s.c.s.instrument.web.TraceWebFilter : Handled send of NoopSpan(90e1114e35c897d6/90e1114e35c897d6)
2019-05-20 16:15:40.021 DEBUG [my-service,90e1114e35c897d6,90e1114e35c897d6,false] 12548 --- [ctor-http-nio-2] o.s.w.s.adapter.HttpWebHandlerAdapter : [3e578505] Completed 200 OK
Comment puis-je obtenir la même console de connexion en utilisant opentracing-spring-jaeger-cloud-starter?
ma config opentracing
opentracing:
jaeger:
enabled: true
enable-b3-propagation: true
log-spans: true
const-sampler:
decision: true
http-sender:
url: http://jaeger-collector:14268/api/traces