Spring Boot / Java logging to UptimeEye

Java services usually log through Logback (Spring Boot's default) or Log4j2. Pick the option that fits how you deploy: the OpenTelemetry Java agent needs no code and no agent on the host; structured logging plus a log agent is the classic container setup; the plain-text endpoint gets you started in a minute.

Endpoint: https://logs.uptimeeye.com/v1/ingest/otlp/v1/logs

Option 1: OpenTelemetry Java agent (no code changes)

The agent captures Logback and Log4j2 records with MDC and exception details and exports them over OTLP. Attach it with a JVM flag and set the environment.

shell / Dockerfile
curl -sSL -o opentelemetry-javaagent.jar \
  https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar

export OTEL_SERVICE_NAME=orders
export OTEL_RESOURCE_ATTRIBUTES=deployment.environment=prod
export OTEL_LOGS_EXPORTER=otlp
export OTEL_TRACES_EXPORTER=none
export OTEL_METRICS_EXPORTER=none
export OTEL_EXPORTER_OTLP_LOGS_PROTOCOL=http/protobuf
export OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=https://logs.uptimeeye.com/v1/ingest/otlp/v1/logs
export OTEL_EXPORTER_OTLP_LOGS_HEADERS="Authorization=Bearer%20ue_ingest_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"

java -javaagent:./opentelemetry-javaagent.jar -jar orders.jar
Note: Search with service.name:=orders severity_text:=ERROR. MDC keys arrive as attributes; exception.stacktrace holds the full trace.

Option 2: Spring Boot structured logging + agent (containers)

Spring Boot 3.4+ can write ECS/JSON to stdout with one property. Your Kubernetes or Docker agent then lifts the JSON keys to fields.

application.properties
logging.structured.format.console=ecs
logging.structured.ecs.service.name=orders
logging.structured.ecs.service.environment=prod

Option 3: Logback JSON to a file, tailed by Fluent Bit or Vector

For VMs. logstash-logback-encoder writes one JSON object per line; the agent guides on this site pick it up with _msg_field=message&_time_field=@timestamp.

logback-spring.xml
<configuration>
  <appender name="JSON" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>/var/log/orders/application.json</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <fileNamePattern>/var/log/orders/application.%d{yyyy-MM-dd}.json</fileNamePattern>
      <maxHistory>3</maxHistory>
    </rollingPolicy>
    <encoder class="net.logstash.logback.encoder.LogstashEncoder">
      <customFields>{"service":"orders","env":"prod"}</customFields>
      <includeMdcKeyName>traceId</includeMdcKeyName>
      <includeMdcKeyName>orderId</includeMdcKeyName>
    </encoder>
  </appender>
  <root level="INFO"><appender-ref ref="JSON"/></root>
</configuration>

Option 4: the plain-text file, right now

Keep your pattern layout and upload the file. Timestamps and levels are detected, stack traces stay with their line.

shell
curl -sS -X POST "https://logs.uptimeeye.com/v1/ingest/text?service=orders&env=prod&_stream_fields=service,env" \
  -H "Authorization: Bearer ue_ingest_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" -H "Content-Type: text/plain" \
  --data-binary @/var/log/orders/application.log

Fields you get

These show up in the fields panel and can be used in every filter:

  • service / service.name, env
  • level / severity_text
  • logger_name, thread_name
  • MDC keys such as traceId, orderId
  • stack_trace / exception.stacktrace

Tips

  • Log in UTC or with an explicit offset — the plain-text endpoint reads zone-less timestamps as UTC.
  • Put business identifiers into MDC (MDC.put("orderId", id)) instead of the message; they become filterable fields in every option above.
  • Log4j2 users: the OpenTelemetry agent covers Log4j2 too; for files use JsonTemplateLayout with the EcsLayout.json template.

FAQ

Which option should I pick?
Kubernetes or Docker with a log agent already in place → Option 2. VM without an agent → Option 1 (nothing to install besides the jar) or Option 3. Just trying it out → Option 4.
Does the OpenTelemetry agent slow the JVM down?
Startup takes a bit longer (instrumentation), steady state overhead is low. With traces and metrics exporters set to none only log records are exported.
Where do I get the ingest key?
In the app under API Keys → New API Key → type “Log ingest”. The key starts with ue_ingest_ and is shown once. Management keys (ue_live_) are refused by the ingest endpoint.
How do I check that logs arrive?
Open Logs in the app, pick the 15m range and search for service:=<your service>. New lines are searchable within about a second; Live tail shows them with a ~6 s delay.