avatarRuchira Madhushan Rajapaksha

Summary

The provided content outlines a comprehensive guide on integrating Grafana Loki with Spring Boot 3 for enhanced log monitoring and observability using OpenTelemetry.

Abstract

The article delves into the integration of Grafana Loki with a Spring Boot 3 application to improve log management and observability. It is part of a series on observability with OpenTelemetry, following previous discussions on monitoring metrics and traces. The integration involves configuring OpenTelemetry with Loki and Grafana, setting up the application with necessary dependencies, and configuring the OpenTelemetry Collector and logging appender. The guide also includes instructions for running the OpenTelemetry Collector, Loki, and Grafana using Docker, and attaching Loki as a data source in Grafana to visualize logs effectively. The article emphasizes Loki's cost-effectiveness, label-based indexing, and compatibility with Kubernetes, making it an efficient choice for log aggregation.

Opinions

  • The author positively endorses Loki for log aggregation due to its simplicity, cost-effectiveness, and seamless integration with Prometheus and Kubernetes.
  • The article suggests that integrating Loki with Spring Boot applications via OpenTelemetry significantly enhances system troubleshooting and visibility.
  • The author implies that the OpenTelemetry Collector is a versatile tool, capable of handling metrics, traces, and logs, and is essential for observability in modern applications.
  • By providing a step-by-step guide and code examples, the author conveys the importance of a structured approach to setting up observability in software development.
  • The recommendation of ZAI.chat at the end of the article indicates the author's belief in the value of cost-effective AI services that offer performance comparable to premium offerings like ChatGPT Plus.

Spring Boot 3 Observability With OpenTelemetry Series (Log Monitoring)

Overview of Observability Series So Far

In our Observability Series, we have already covered, Monitoring Metrics and Monitoring Traces with OpenTelemetry and you can refer to the respective articles with the below links.

With today’s approach, we will optimize our existing application developed with Spring Boot by Integrating with Loki, a log aggregation system inspired by Prometheus.

This integration will significantly enhance the logging capabilities of our application, enabling us to effectively manage and analyze logs, increasing visibility, and facilitating system troubleshooting.

Our Approach

In this tutorial, I’ll show you how to integrate Open Telemetry with Loki and Grafana to achieve observability via enhancing logging capabilities. To learn more about OpenTelemetry please head over to the following Link.

Grafana Loki

Loki is a horizontally scalable, highly available, multi-tenant log aggregation system inspired by Prometheus. It is designed to be very cost-effective and easy to operate. It does not index the contents of the logs, but a set of labels for each log stream.

Compared to other log aggregation systems, Loki:

  • No full-text indexing on logs: Loki stores compressed, unstructured logs and only indexes metadata. This makes Loki simpler to operate and cheaper to run.
  • Label-based indexing and grouping: Loki Indexes and groups log streams using the same labels used with Prometheus. This enables seamless switching between metrics and logs using the same labels that you’re already using with Prometheus.
  • Query Language: Loki provides a query language called LogQL, This enables users to generate queries against the logs. The language also facilitates the generation of metrics from log data, a powerful feature that goes well beyond log aggregation.
  • Distributed Architecture: Loki is designed to be horizontally scalable and can run in a distributed architecture. This scalability allows it to handle large volumes of log data in a clustered setup.
  • Perfect for the logs of Kubernetes Pods: Loki is an especially good fit for storing Kubernetes Pod logs. Metadata such as pod labels are automatically scraped and indexed.
  • Native support in Grafana: Loki Has native support in Grafana (needs Grafana v6.0).

Application Setup with SpringBoot

We will set up the application with Spring Initializer with the following dependencies in the pom.xml file.

<dependencies>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-actuator</artifactId>
  </dependency>

  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-webflux</artifactId>
  </dependency>

  </dependency>
  <dependency>
   <groupId>io.micrometer</groupId>
   <artifactId>micrometer-registry-otlp</artifactId>
   <scope>runtime</scope>
  </dependency>

  <dependency>
   <groupId>io.micrometer</groupId>
   <artifactId>micrometer-tracing-bridge-otel</artifactId>
   <version>1.1.6</version>
  </dependency>

  <dependency>
   <groupId>io.opentelemetry</groupId>
   <artifactId>opentelemetry-api</artifactId>
   <version>1.31.0</version>
  </dependency>

  <dependency>
   <groupId>io.opentelemetry</groupId>
   <artifactId>opentelemetry-exporter-otlp</artifactId>
   <version>1.31.0</version>
  </dependency>

  <dependency>
   <groupId>io.opentelemetry</groupId>
   <artifactId>opentelemetry-exporter-common</artifactId>
   <version>1.31.0</version>
  </dependency>

  <dependency>
   <groupId>io.opentelemetry.instrumentation</groupId>
   <artifactId>opentelemetry-logback-appender-1.0</artifactId>
   <version>1.31.0-alpha</version>
  </dependency>
  
  <dependency>
   <groupId>io.opentelemetry</groupId>
   <artifactId>opentelemetry-sdk</artifactId>
   <version>1.31.0</version>
  </dependency>
  
  <dependency>
   <groupId>io.opentelemetry.instrumentation</groupId>
   <artifactId>opentelemetry-instrumentation-api-semconv</artifactId>
   <version>1.31.0-alpha</version>
  </dependency>
  
  <dependency>
   <groupId>io.opentelemetry</groupId>
   <artifactId>opentelemetry-exporter-otlp-common</artifactId>
   <version>1.31.0</version>
  </dependency>
  
</dependencies>

Configuring OpenTelemetry Collector

We will update the configurations related to the OpenTelemetry Collector, including Loki, as an exporter inside the otel-collector.yml file.

receivers:
  otlp:
    protocols:
      http:
      grpc:

processors:
  # batch metrics before sending to reduce API usage
  batch:

exporters:
  logging:
    loglevel: debug
  prometheus:
    endpoint: "0.0.0.0:8889"
    const_labels:
      label1: spring
  otlp:
    endpoint: tempo:4317  # tempo container host and port
    tls:
      insecure: true
  loki:
    endpoint: "http://loki:3100/loki/api/v1/push"

extensions:
  # responsible for responding to health check calls on behalf of the collector.
  health_check:
  # fetches the collector’s performance data
  pprof:
  # serves as an http endpoint that provides live debugging data about instrumented components.
  zpages:

service:
  extensions: [health_check, pprof, zpages]
  pipelines:
    # for now we only interested about metrics...
    metrics:
      receivers: [otlp]
      processors: [batch]
      exporters: [prometheus]
    traces:
      receivers: [otlp]
      processors: [batch]
      exporters: [otlp]  # name here should match the exporter name for tempo which is otlp
    logs:
      receivers: [otlp]
      exporters: [loki,logging]

Configuring Logging Appender

We will customize the logging appender by creating a logback-spring.xml.

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>
                %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n
            </pattern>
        </encoder>
    </appender>
    <appender name="OpenTelemetry"
              class="io.opentelemetry.instrumentation.logback.appender.v1_0.OpenTelemetryAppender">
        <captureExperimentalAttributes>true</captureExperimentalAttributes>
        <captureKeyValuePairAttributes>true</captureKeyValuePairAttributes>
        <captureCodeAttributes>true</captureCodeAttributes>
        <captureMarkerAttribute>true</captureMarkerAttribute>
        <captureMdcAttributes>*</captureMdcAttributes>
    </appender>

    <root level="INFO">
        <appender-ref ref="console"/>
        <appender-ref ref="OpenTelemetry"/>
    </root>

</configuration>

Configurations to push logs to the OpenTelemetry Collector

Create a configuration class to configure Spring boot application to push logs to Open Telemetry Collector.

@Configuration
public class OpenTelemetryConfig {
    
    @Bean
    OpenTelemetry openTelemetry(final SdkLoggerProvider sdkLoggerProvider, final SdkTracerProvider sdkTracerProvider, final ContextPropagators contextPropagators) {
        final OpenTelemetrySdk openTelemetrySdk = OpenTelemetrySdk.builder()
                .setLoggerProvider(sdkLoggerProvider)
                .setTracerProvider(sdkTracerProvider)
                .setPropagators(contextPropagators)
                .build();
        OpenTelemetryAppender.install(openTelemetrySdk);
        return openTelemetrySdk;
    }

    @Bean
    SdkLoggerProvider otelSdkLoggerProvider(final Environment environment, final ObjectProvider<LogRecordProcessor> logRecordProcessors) {
        final String applicationName = environment.getProperty("spring.application.name", "application");
        final Resource resource = Resource.create(Attributes.of(ResourceAttributes.SERVICE_NAME, applicationName));
        final SdkLoggerProviderBuilder builder = SdkLoggerProvider.builder()
                .setResource(Resource.getDefault().merge(resource));
        logRecordProcessors.orderedStream().forEach(builder::addLogRecordProcessor);
        return builder.build();
    }

    @Bean
    LogRecordProcessor otelLogRecordProcessor() {
        return BatchLogRecordProcessor
                .builder(
                        OtlpGrpcLogRecordExporter.builder()
                                .setEndpoint("http://localhost:4317")
                                .build())
                .build();
    }
}

Running OpenTelemetry Collector Loki and Grafana

We will run the OpenTelemetry Collector, Loki and Grafana with Docker using docker-compose.yaml file as in the following example:

version: '3'
services:
  otel-collector:
    image: otel/opentelemetry-collector-contrib
    restart: always
    command:
      - --config=/etc/otelcol-cont/otel-collector.yml
    volumes:
      - ./collector/otel-collector.yml:/etc/otelcol-cont/otel-collector.yml
    ports:
      - "1888:1888" # pprof extension
      - "8888:8888" # Prometheus metrics exposed by the collector
      - "8889:8889" # Prometheus exporter metrics
      - "13133:13133" # health_check extension
      - "4317:4317" # OTLP gRPC receiver
      - "4318:4318" # OTLP http receiver
      - "55679:55679" # zpages extension

  prometheus:
    container_name: prometheus
    image: prom/prometheus
    restart: always
    command:
      - --config.file=/etc/prometheus/prometheus.yml
    volumes:
      - ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
    ports:
      - "9090:9090"

  grafana:
    container_name: grafana
    image: grafana/grafana
    ports:
      - "3000:3000"

  tempo:
    image: grafana/tempo:latest
    command: [ "-config.file=/etc/tempo.yml" ]
    volumes:
      - ./tempo/tempo.yml:/etc/tempo.yml
    ports:
      - "3200:3200"   # tempo
      - "4317"  # otlp grpc

  loki:
    image: grafana/loki:latest
    command: -config.file=/etc/loki/local-config.yaml
    ports:
      - "3100:3100"

Attaching Loki as a Data Source in Grafana

Follow the below steps to set up Loki as a data source in Grafana.

  • Grafana is accessible via http://localhost:3000/login enter admin as the default username and admin as the default password.
  • Add Loki as a new data source.
  • Configure the data source to connect to our Loki container.

Then You can see the logs as shown below.

Summary

In this article, we have covered:

  1. What is Grafana Loki
  2. Configuring Open Telemetry with Loki and Grafana in SpringBoot.

The GitHub repo for the article can be found here.

Please feel free to share your feedback.

Visit to find more of my articles on Medium.

Thanks for reading.

Stackademic

Thank you for reading until the end. Before you go:

  • Please consider clapping and following the writer! 👏
  • Follow us on Twitter(X), LinkedIn, and YouTube.
  • Visit Stackademic.com to find out more about how we are democratizing free programming education around the world.
Spring
Observability
Loki
Grafana
Java
Recommended from ReadMedium