Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Info

Disponible desde versión 5.1.0 de Onesait Platform (Survivor).

Table of Contents

Introducción

En la release de Q2 de 2023 se ha incluido la capacidad de Tracing distribuido en Plataforma.

Esto nos permite obtener la trazabilidad distribuida entre sus componentes y otros componentes como microservicios que pueden invocar un API REST de plataforma y poder ver esta trazabilidad completa desde este microservicio.

Cómo acceder a la funcionalidad

Estas trazas pueden verse desde el control panel Control Panel en la opción TRACING:

...

En este ejemplo se muestran las trazas de un micr servicio microservicio que invoca a otro microservicio, y este éste a su vez a un servicio RESTexpuesto REST expuesto desde el Api API Manager de plataformaPlataforma. En las trazas se ve cuanto cuánto tiempo se ha empleado en cada span, lo cual es útil para detectar cueellos cuellos de botella, interrupciones entre componentes,…

...

Detalle de funcionamiento

...

¿Cómo configurar tu microservicio para que tracee?

Instrumentación del microservicio

La instrumentación de una aplicación, microservicio, etc, … es adaptarla para que tu microservicio permitirá que éste genere una información de trazas y span que enviará al colector, estas . Estas trazas y span comparten un contexto por lo que puede trazarse, desde el inicio hasta el fin, el camino recorrido, el tiempo en cada punto del camino, y además contiene información del tipo clave-valor, para luego poder interpretar todo y poder sacar conclusiones.

En La Plataforma se utiliza Open Telemetry para crear las trazas y spans y enviarla al colector para su tratamiento.

Tipos de instrumentación

Existen 2 dos tipos de instrumentación, :

  • Está la instrumentación Automática, consiste automática. Consiste en utilizar el agente de Open Telemetry para que de forma no intrusiva obtener las trazas sin tener que tocar el código del micro servicio, aplicación, etc.. , desde el que se pretendan obtener las trazas, ya que el agente se encarga de escuchar las distintas librerías más importantes que se suelen utilizar y a partir de estas generar éstas genera las trazas. Es la que usaremos por defecto.

  • Luego también está la instrumentalización Manual, manual. en este caso hay que añadir en la aplicación, micro servicio las librerias librerías con el SDK de Opentelemetry Open Telemetry e implementar como se van a generar las distintas trazas. Este caso es más útil cuando se pretenden generar ciertos tipos de trazas con información especifica o más customizada.

Aquí se puede encontrar la información necesaria para poder implementar los dos tipos de instrumentación:

https://opentelemetry.io/

...

Ejemplo de Instrumentación

Para los ejemplo crearemos , crearás dos microservicios a partir de proyectos creados con Spring Boot.Uno para Spring Boot, uno en el que configurarás la instrumentación automática, y otro para la manual.

Instrumentación

...

automática

Para este tipo de instrumentación tan sólo hay que arrancar junto a la aplicación el agente de Open Telemetry, el cual es altamente configurable por parametría.

En el ejemplo más sencillo tan sólo se tendría tienes que especificar donde dónde se encuentra el jar en los parámetros de la JVM:

-javaagent:/path/opentelemetry-javaagent.jar

El nombre del servicio, así será como aparece en las trazas

-Dotel.resource.attributes=service.name=Onesait-Platform-Microservice

...

Y finalmente la dirección del colector que recogerá las trazas y spans generados por el agente

-Dotel.exporter.otlp.endpoint:https://lab.onesaitplatform.com/otelcollector/Además de añadir las siguientes variables de entorno:

Code Block
OTEL_JAVAAGENT_ENABLED=false #(Des)Activa el agente
OTEL_EXPORTER_OTLP_ENDPOINT=http://jaeger-service:4317 #endpoint del collector
OTEL_SERVICE_NAME=microservice #Nombre del servicio
OTEL_METRICS_EXPORTER=none #Para que no exporte métricas, ya que no está activada esta feature

...

El agente puede descargarse con esta url:

download java agent. (opentelemetry-javaagent-1.27.0.jar)

También existen agentes para otras tecnologías, no sólo java.

Instrumentación

...

manual

En este caso habría tienes que añadir código a la aplicación para generar las trazas.añadir , añadiendo estas dependencias al fichero pom.xml:

Code Block
<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>io.opentelemetry</groupId>
			<artifactId>opentelemetry-api</artifactId>
		</dependency>
		<dependency>
			<groupId>io.opentelemetry</groupId>
			<artifactId>opentelemetry-sdk</artifactId>
		</dependency>
		<dependency>
			<groupId>io.opentelemetry</groupId>
			<artifactId>opentelemetry-exporter-otlp</artifactId>
		</dependency>
		<dependency>
			<groupId>io.opentelemetry</groupId>
			<artifactId>opentelemetry-semconv</artifactId>
			<version>1.27.0-alpha</version>
		</dependency>
		 

	</dependencies>
	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>io.opentelemetry</groupId>
				<artifactId>opentelemetry-bom</artifactId>
				<version>1.27.0</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

Definir y definir cierta información en el fichero application.properties:

Code Block
otel.config.trace-id-ratio-based: 1.0 
otel.exporter.otlp.endpoint: https://lab.onesaitplatform.com/otelcollector/
service.name: Onesait-Platform-Microservice

En este caso se , configura el ratio base, la url donde se encuentra el colector de OTel Otel y en el nombre del servicio.

Finalmente, en el microservicio, lo que se hace es invocar un servicio rest REST generado con el api manager API Manager de plataforma, entonces la finalidad es crear una traza que envuelva esta llamada.

Code Block
languagejava
	@Autowired
	private TracingConfiguration tracingConfiguration;

	private static final Logger log = LoggerFactory.getLogger(ExampleRestController.class);
	private Tracer tracer;

	@PostConstruct
	public void init() {
		tracer = tracingConfiguration.getOpenTelemetry().getTracer(ExampleRestController.class.getPackageName());
	}

	@Autowired
	HttpServletRequest request;

//@RequestHeader(required = false) HttpHeaders headers
	@GetMapping(value = "/getAll")
	public void getAll() throws IOException {
		request.getHeaderNames();
		Context extractedContext = tracingConfiguration.getOpenTelemetry().getPropagators().getTextMapPropagator()
				.extract(Context.current(), request, Utils.getter);
		// the span is created

		try (Scope scope = extractedContext.makeCurrent()) {
			Span span = tracer.spanBuilder("example span with context propagation").setSpanKind(SpanKind.SERVER)
					.startSpan();
			try (Scope ignored = span.makeCurrent()) {
				URL url = new URL("https://lab.onesaitplatform.com/api-manager/server/api/v1/customer/");
				// from here you would be making a call to a platform rest api that queries the
				// information of an entity for example
				HttpURLConnection con = (HttpURLConnection) url.openConnection();
				// adding information to the span is optional but recommended
				span.setAttribute(SemanticAttributes.HTTP_URL, url.toString());
				span.setAttribute(SemanticAttributes.HTTP_METHOD, "GET");
				span.setAttribute("component", "http");
				// Inject the request with the *current* Context, which contains our current
				// Span.
				tracingConfiguration.getOpenTelemetry().getPropagators().getTextMapPropagator()
						.inject(Context.current(), con, Utils.setter);
				// the necessary information is added to the request
				con.setRequestProperty("accept", "application/json");
				con.setRequestProperty("X-OP-APIKey", "6bfb064cb62548b78d7....");
				con.setRequestMethod("GET");
				int status = con.getResponseCode();
				log.info("status:  " + status);
			} finally {
				// the span is closed
				span.end();
			}
		}
	}

En este ejemplo Se se obtiene la traza:

Code Block
languagejava
@PostConstruct
	public void init() {
		tracer = tracingConfiguration.getOpenTelemetry().getTracer(ExampleRestController.class.getPackageName());
	}

Luego se obtiene el contexto por si este microservicio fuese invocado desde otro que ya hubiese creado una traza previa. Con esto, con esto se consigue que no se parta la traza en fragmentos que partan de distintos servicios y todos parten desde una llamada incialinicial.

Code Block
languagejava
Context extractedContext = tracingConfiguration.getOpenTelemetry().getPropagators().getTextMapPropagator()
				.extract(Context.current(), request, Utils.getter);

...

Code Block
languagejava
try (Scope scope = extractedContext.makeCurrent()) {
			Span span = tracer.spanBuilder("example span with context propagation").setSpanKind(SpanKind.SERVER)
					.startSpan();

Al invocar al servicio rest REST se añade la información del contexto actual para que el próximo componente de la traza tenga el contexto previo y pueda decidir si crear una traza nueva o continuar con la actual, esto se consigue con los propagators.

Code Block
languagejava
tracingConfiguration.getOpenTelemetry().getPropagators().getTextMapPropagator()
						.inject(Context.current(), con, Utils.setter);

Para finalizar, es siempre recomendable cerrar el span.

...

Si vamos a las trazas y expandimos el detalle, se comprueba que la información especifica añadida por el desarrollador es visible.

...

Para comprobar que no se pierde el contexto con esta implementación, se creo creó otro micro servicio Onesait-Platform-Microservice2 idéntico al mostrado pero que llamaba a Onesait-Platform-Microservice en lugar de invocar al servicio rest REST de plataforma, con lo que se muestra en las trazas primero el servicio Onesait-Platform-Microservice2 → Onesait-Platform-Microservice → api-manager.

...