PingIDM

OpenTelemetry logging

OpenTelemetry (OTEL) logging is an Evolving feature in PingIDM. It’s subject to change without notice, even in a minor or maintenance release.

OTEL logging collects and exports logs using the OpenTelemetry Protocol (OTLP). It’s a part of the broader OpenTelemetry observability framework that provides a unified way to collect logs, traces, and metrics from applications. Learn more in Distributed tracing.

In PingIDM, logs are sent directly from IDM to an OTEL collector using JSON format and OTLP, rather than through traditional logging pipelines. Learn more in Server logs.

Benefits of OTEL logging

OTEL logging makes it easier to:

  • Correlate logs across Ping Identity products using trace IDs and span IDs. When a request flows through multiple systems, such as PingAM, IDM, and PingDS, you can track the entire journey using a single trace ID. Learn more in Understand a trace object.

  • Troubleshoot and pinpoint where issues occur in complex workflows. Trace IDs provide a high-level overview of a request, while span IDs show specific tasks within that trace.

  • Standardize observability. You can use your preferred observability tools, such as Splunk, Datadog, or Grafana that support OTLP.

  • Simplify setup because logs go directly to the OTEL collector and bypass previous processing steps.

  • Enhance visibility to efficiently identify patterns, bottlenecks, or errors across distributed systems.

Configuring OTEL logging

To configure and implement OpenTelemetry logging:

  1. Enable distributed tracing in IDM, which includes trace and span IDs in the logs.

  2. Start the OTEL collector. Learn more in the OTEL Collector Quick Start and in Visualize traces with a trace collector.

  3. Configure the OpenTelemetryAppender. Learn more in Log appenders.

  4. Initialize the OTEL LoggerProvider, which contains information about the OTEL collector endpoint where logs are sent and default settings for batched log processing.

    • Add the LoggerProvider configuration to the trace.json file created when you enabled distributed tracing in step 1:

      {
         "logging": {
            "enabled": true,
            "exporter": {
               "type": "otlp",
               "config": {
                  "endpoint": "http://localhost:4318/v1/logs"
               }
            }
         }
      }

      The following example shows all available LoggerProvider configuration options:

      {
         "logging": {
            "enabled": true,
            "exporter": {
               "type": "otlp",
               "config": {
                  "endpoint": "http://localhost:4318/v1/logs",
                  "headers": "<headers>",
                  "connectionTimeout": "10 seconds",
                  "timeout": "10 seconds",
                  "compressionMethod": "gzip",
                  "retries": {
                     "backoffMultiplier": 1.5,
                     "initialBackoff": "1 second",
                     "maxAttempts": 5,
                     "maxBackoff": "5 seconds"
                  }
               },
               "batch": {
                  "maxExportBatchSize": 512,
                  "maxQueueSize": 2048,
                  "scheduleDelay": "5 seconds",
                  "exporterTimeout": "30 seconds"
               }
            }
         }
      }
      OpenTelemetry logging configuration properties
      enabled: boolean, optional

      Set to true to enable OpenTelemetry logging.

      Default: false

      resourceAttributes: object, optional

      A map of additional resource attributes for processing logs. Find more information in the OpenTelemetry documentation on Semantic Attributes with SDK-provided Default Value.

      For example, if there are multiple Ping Identity Platform instances in a deployment, you could set the "service.instance.id" resource attribute differently for each one to distinguish between them:

      {
        "resourceAttributes": {
          "service.instance.id": "idm-server-1"
        }
      }
      exporter: object, optional

      Configuration for the exporter, which pushes logs to the OpenTelemetry service:

      type: string, optional

      Set to otlp for OpenTelemetry Protocol (OTLP) support. This is currently the only supported protocol.

      Default: otlp

      config: object, optional

      Endpoint and timeout configuration:

      • compressionMethod: enumeration, optional

        Method used to compress log data; either gzip or none.

        Default: gzip

      • connectionTimeout: duration, optional

        Time out a connection to the endpoint after this duration.

        Default: 10 seconds.

      • endpoint: string, optional

        The endpoint to publish traces to.

        For HTTPS, IDM trusts the default JVM CAs. To override this, set the -Djavax.net.ssl.trustStore and associated JVM settings when starting IDM. Learn more about the optional settings in the Java Secure Socket Extension (JSSE) Reference Guide.

        IDM doesn’t support TLS configuration for the tracing endpoint at this time.

        Default: http://localhost:4318/v1/traces

      • headers: object, optional

        Map of additional headers to include in the export span request.

        The following example sets the authorization header, Authorization: Bearer ${bearer.token}:

        "headers": { "Authorization": "Bearer ${bearer.token}" }
      • retries: object, optional

        Defines a retry policy for the export span requests.

        Default: Enabled

        • backoffMultiplier: number, optional Multiplier for the backoff wait time before retries.

          Default: 1.5

        • enabled: boolean, optional

          Retry failed requests.

          Default: true

        • initialBackoff: duration, optional

          How long to wait before the first retry.

          Default: 1 second

        • maxAttempts: number, optional

          Maximum number of retries.

          Default: 5

        • maxBackoff: duration, optional

          Maximum wait time between retries.

          Default: 5 seconds

      • timeout: duration, optional

        Time out a request to publish data to the endpoint after this duration.

        Default: 10 seconds.

      batch: object, optional

      Enable and configure batch processing for log data.

      • enabled: boolean, optional

        Leave batch processing enabled in deployment.

        Default: true

      • exporterTimeout: duration, optional

        Time out a data exporter after this duration.

        Default: 30 seconds

      • exportUnsampledSpans: boolean, optional

        Whether to report on unsampled spans.

        Default: false

      • maxExportBatchSize: number, optional

        Maximum number of spans in a batch.

        Default: 512

      • maxQueueSize: number, optional

        Maximum number of spans to queue before dropping them.

        Default: 2048

      • scheduleDelay: duration, optional

        Maximum interval between sending batches of log data.

        Default: 5 seconds

  5. At the end of the resolver/boot.properties file, add the location of the trace.json file:

    openidm.tracing.config.path=trace/trace.json
  6. Start IDM.

  7. Go to your OTEL collector and view the logs sent from IDM.

OTEL log records

In the OTEL collector, you can view log records in the OTLP format to find the trace and span IDs to follow a request across multiple systems.

This is an example of an IDM log record in the OTEL collector:

Trace ID:
Span ID:
Flags: 0
LogRecord #238
ObservedTimestamp: 2025-11-14 18:23:29.219669 +0000 UTC
Timestamp: 2025-11-14 18:23:29.219661 +0000 UTC
SeverityText: DEBUG
SeverityNumber: Debug(5)
Body: Str(Bundle xstream not matched by org.forgerock.*)
Attributes:
 -> thread.name: Str(HealthCheck Bundles Started)

Log record fields

Field Name Description

LogRecord

Represents the recording of an event. In OpenTelemetry, a log record contains two kinds of fields:

  • Named top-level fields of specific type and meaning

  • Resource and attributes fields of arbitrary value and type

ObservedTimestamp

Time when the event was observed.

Timestamp

Time when the event occurred.

SeverityText

The severity text (also known as log level).

SeverityNumber

Numerical value of the severity.

Body

The body of the log record.

Attributes

Additional information about the event.

Trace ID

Request trace ID.

Span ID

Request span ID.

Flags

A binary encoding that contains trace information.

OTEL logging for HTTP inbound requests

When tracing is enabled, incoming HTTP requests automatically generate trace and span IDs. These IDs are included in log records sent to the OTEL collector. The trace and span ID fields are blank if the request doesn’t come from an HTTP inbound request.

For an HTTP inbound request, here’s an example scenario to find the trace and span IDs in the OTEL collector logs:

  1. Sign on to the IDM admin user interface (UI).

  2. Go to the OTEL collector and view the span for the sign-on request that contains the trace ID:

    Span #7 (1)
    Trace ID: 4cafb0e638a8c2ba58a8288e0e12470fd (2)
    Parent ID:
    ID: 6bdc24e07a2c9754
    Name: GET /openidm
    Kind: Server
    Start time: 2025-11-14 18:26:24.104794 +0000 UTC
    End time: 2025-11-14 18:26:24.110788 +0000 UTC
    Status code: Unset
    Status message:
    Attributes:
     -> http.request.method: Str(GET)
     -> url.path: Str(/openidm/info/version)
     -> url.full: Str(https://localhost:8443/openidm/info/version)
     -> network.protocol.name: Str(http)
     -> forgerock.transaction.id: Str(3caddd39-2942-4ccd-b527-9dfbd1f6353-1380)
     -> {"resource": "{service.instance.id": "5f481198b-5fc4-416b-a8d5-1d2cd5581f64", "service.name": "otelcol-contrib", "service.version": "0.128.0"}, "otelcol.component.id": "debug", "otelcol.component.kind": "exporter", "otelcol.signal": "traces"}
    2025-11-14T18:26:27.590Z info Metrics {"resource": "{service.instance.id": "5f481198b-5fc4-416b-a8d5-1d2cd5581f64", "service.name": "otelcol-contrib", "service.version": "0.128.0"}, "otelcol.component.id": "debug", "otelcol.component.kind": "exporter", "otelcol.signal": "metrics", "resource metrics": 1, "metrics": 27, "data points": 28}
    2025-11-14T18:26:27.591Z info Resource@Metrics #0
    Resource SchemaURL:
    Resource attributes:
     -> service.name: Str(otelcol-contrib)
     -> service.instance.id: Str(5f481198b-5fc4-416b-a8d5-1d2cd5581f64)
     -> server.port: Str(8888)
    1 Span for the sign-on request
    2 Associated trace ID for the span
  3. Find the matching trace ID in the log records to see the associated span ID:

    LogRecord #23
    ObservedTimestamp: 2025-11-14 18:26:24.107832 +0000 UTC
    Timestamp: 2025-11-14 18:26:24.107823 +0000 UTC
    SeverityText: DEBUG
    SeverityNumber: Debug(5)
    Body: Str(Invoking read access)
    Attributes:
     -> thread.name: Str(qtp1868624459-218)
    Trace ID: 4cafb0e638a8c2ba58a8288e0e12470fd (1)
    Span ID: 6bdc24e07a2c9754 (2)
    Flags: 1
    1 Matching trace ID in the log record
    2 Matching associated span ID
  4. View the log record body and attributes for more details about the sign-on request.

    In this example, the Body field for LogRecord #23 shows the string (Invoking read access) because the user requested read access to the admin dashboard. This inbound HTTP request generated the trace and span IDs in the previous steps:

    LogRecord #23
    ObservedTimestamp: 2025-11-14 18:26:24.107832 +0000 UTC
    Timestamp: 2025-11-14 18:26:24.107823 +0000 UTC
    SeverityText: DEBUG
    SeverityNumber: Debug(5)
    Body: Str(Invoking read access) (1)
    Attributes:
     -> thread.name: Str(qtp1868624459-218)
    Trace ID: 4cafb0e638a8c2ba58a8288e0e12470fd
    Span ID: 6bdc24e07a2c9754
    Flags: 1
    1 This string shows the user requested read access to the admin dashboard.