Skip to content

Conversation

@Anty0
Copy link
Collaborator

@Anty0 Anty0 commented Feb 3, 2026

Summary by CodeRabbit

  • New Features

    • Added support for running the application with local observability and tracing enabled.
    • Introduced two setup options: a full Docker-based stack or local app with Docker observability services.
  • Documentation

    • Updated setup guides with detailed instructions for both deployment scenarios.
    • Clarified commands and verification steps for tracing configuration.

@Anty0 Anty0 requested a review from gabrielshanahan February 3, 2026 16:43
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 3, 2026

📝 Walkthrough

Walkthrough

This pull request introduces a local OpenTelemetry observability stack for development, adding Gradle tasks to enable tracing in the backend application, a Docker Compose configuration defining the observability infrastructure services, and documentation guiding developers through setup and verification procedures.

Changes

Cohort / File(s) Summary
Gradle Build Configuration
backend/app/build.gradle
Adds two new Gradle tasks: copyOtelAgent to copy the OpenTelemetry Java agent artifact, and bootRunWithObservability to configure the backend to run with local observability stack integration, setting OTEL environment variables, Spring profiles, and database/Redis connection details.
Observability Infrastructure
docker/docker-compose.local-observability-stack-dev.yaml
Introduces a new Docker Compose configuration defining a complete observability stack with eight services: Tempo, OTEL Collector, Loki, Promtail, Prometheus, Grafana, PostgreSQL, and Redis, with inter-service dependencies, health checks, volume mounts, and environment configuration.
Documentation
docs/local-observability-stack/1_Setting_Up_the_Tracing_Stack.md, docs/observability/README.md
Restructures setup instructions to present two options (Full Docker Stack vs. Local Tolgee with Docker Observability), adds comparison table, updates command references to use new Gradle task and Docker Compose file, and provides option-specific verification and troubleshooting guidance.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • zomp
  • JanCizmar

Poem

🐰 Whiskers twitching with observability glee,
Traces now flowing through Tempo and Loki so free,
With OTEL agents and Grafana's bright light,
Our stack hops to life, making debugging quite right! ✨

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: introducing a local observability stack setup that allows Tolgee to run outside Docker, which is the core purpose of the PR changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch jirikuchynka/local-observability-dev

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@backend/app/build.gradle`:
- Around line 309-342: The bootRunWithObservability task currently only sets
OTEL_* environment vars in doFirst, but bootRun reads
System.getenv("OTEL_JAVAAGENT_ENABLED") at configuration time so the Java agent
never gets added; update bootRunWithObservability (and/or its doFirst block) to
explicitly append the javaagent JVM arg to bootRun.jvmArgs (e.g., add
"-javaagent:<path-to-opentelemetry-javaagent.jar>") so the agent is attached to
the JVM that runs the app, while keeping the existing environment(...) OTEL
settings; reference the bootRunWithObservability task and the bootRun.jvmArgs
property when making this change.

In `@docs/observability/README.md`:
- Around line 34-37: Update the "Method" column entry that currently reads
`./gradlew server-app:bootRun` to match the actual command used (`./gradlew
server-app:bootRunWithObservability`) in the table row where the How cell
contains `./gradlew server-app:bootRunWithObservability
--args='--spring.profiles.active=dev'`, so the Method label and the command
string are consistent.
🧹 Nitpick comments (2)
docker/docker-compose.local-observability-stack-dev.yaml (1)

79-103: Consider limiting Grafana exposure when anonymous admin is enabled.
Binding the UI to localhost reduces accidental LAN exposure while keeping the dev UX intact.

🛠️ Suggested hardening
-      - "3000:3000"
+      - "127.0.0.1:3000:3000"
docs/local-observability-stack/1_Setting_Up_the_Tracing_Stack.md (1)

59-91: Drop the redundant --args for the dev profile.
bootRunWithObservability already sets --spring.profiles.active=dev, so repeating it is unnecessary.

✏️ Suggested edit
-./gradlew server-app:bootRunWithObservability --args='--spring.profiles.active=dev'
+./gradlew server-app:bootRunWithObservability

Comment on lines +309 to +342
// Run with local observability stack (docker-compose.local-observability-stack-dev.yaml)
// See: docs/observability/
tasks.register('bootRunWithObservability') {
group = 'application'
description = 'Runs Tolgee with OpenTelemetry tracing, using the local Docker observability stack'

doFirst {
bootRun.configure {
// Spring profile
args '--spring.profiles.active=dev'

// OTEL configuration
environment 'OTEL_JAVAAGENT_ENABLED', 'true'
environment 'OTEL_SERVICE_NAME', 'tolgee-platform'
environment 'OTEL_EXPORTER_OTLP_ENDPOINT', 'http://localhost:4318'
environment 'OTEL_RESOURCE_ATTRIBUTES', 'deployment.environment=local-dev'
environment 'OTEL_LOGS_EXPORTER', 'none'
environment 'OTEL_METRICS_EXPORTER', 'none'
environment 'OTEL_INSTRUMENTATION_LOGBACK_MDC_ENABLED', 'true'
environment 'OTEL_SEMCONV_STABILITY_OPT_IN', 'http'

// Database configuration (use Docker stack's PostgreSQL/Redis)
environment 'spring.datasource.url', 'jdbc:postgresql://localhost:5432/tolgee'
environment 'spring.datasource.username', 'tolgee'
environment 'spring.datasource.password', 'tolgee'
environment 'spring.redis.host', 'localhost'
environment 'spring.redis.port', '6379'
environment 'spring.redis.password', 'tolgee'
environment 'tolgee.postgres-autostart.enabled', 'false'
}
}

finalizedBy bootRun
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, let's look at the build.gradle file to understand the context
cat -n backend/app/build.gradle | sed -n '300,350p'

Repository: tolgee/tolgee-platform

Length of output: 2513


🏁 Script executed:

# Also search for otelAgent configuration in the file
rg 'otelAgent|configurations' backend/app/build.gradle -A 2 -B 2

Repository: tolgee/tolgee-platform

Length of output: 634


🏁 Script executed:

# Check for any existing bootRun task configurations
rg 'bootRun' backend/app/build.gradle -B 3 -A 3

Repository: tolgee/tolgee-platform

Length of output: 814


🏁 Script executed:

# Search for OTEL_JAVAAGENT_ENABLED references in the codebase
rg 'OTEL_JAVAAGENT_ENABLED' --type gradle

Repository: tolgee/tolgee-platform

Length of output: 352


🏁 Script executed:

# Let's check the full bootRun task configuration to understand the timing
rg -B 10 'if \(System.getenv\("OTEL_JAVAAGENT_ENABLED"\)' backend/app/build.gradle

Repository: tolgee/tolgee-platform

Length of output: 353


🏁 Script executed:

# Verify the ordering - when does bootRun's configuration block execute?
# Check if there are any other similar patterns that might help understand the execution model
rg 'doFirst|doLast|configure' backend/app/build.gradle -B 1 -A 1 | head -50

Repository: tolgee/tolgee-platform

Length of output: 138


🏁 Script executed:

# Let me trace the exact task execution flow by looking at the complete bootRun and bootRunWithObservability context
sed -n '1,330p' backend/app/build.gradle | tail -100

Repository: tolgee/tolgee-platform

Length of output: 2893


🏁 Script executed:

# Check if there's any documentation or tests about how this should work
find . -name "*.md" -o -name "*.txt" | xargs grep -l "bootRunWithObservability\|OTEL_JAVAAGENT" 2>/dev/null | head -5

Repository: tolgee/tolgee-platform

Length of output: 221


🏁 Script executed:

# Let's check the observability documentation to see if there's any guidance on this
cat ./docs/observability/README.md | head -60

Repository: tolgee/tolgee-platform

Length of output: 3280


Add explicit Java agent attachment in bootRunWithObservability—environment variable alone won't trigger it.

The bootRun task checks System.getenv("OTEL_JAVAAGENT_ENABLED") at Gradle configuration time, but bootRunWithObservability sets that environment variable in doFirst at execution time. By then, the check has already run and jvmArgs was never added. The environment setting only affects the subprocess environment, not the Gradle process's System.getenv().

Fix
     doFirst {
         bootRun.configure {
             // Spring profile
             args '--spring.profiles.active=dev'

             // OTEL configuration
+            jvmArgs "-javaagent:${configurations.otelAgent.singleFile.absolutePath}"
             environment 'OTEL_JAVAAGENT_ENABLED', 'true'
             environment 'OTEL_SERVICE_NAME', 'tolgee-platform'
             environment 'OTEL_EXPORTER_OTLP_ENDPOINT', 'http://localhost:4318'
🤖 Prompt for AI Agents
In `@backend/app/build.gradle` around lines 309 - 342, The
bootRunWithObservability task currently only sets OTEL_* environment vars in
doFirst, but bootRun reads System.getenv("OTEL_JAVAAGENT_ENABLED") at
configuration time so the Java agent never gets added; update
bootRunWithObservability (and/or its doFirst block) to explicitly append the
javaagent JVM arg to bootRun.jvmArgs (e.g., add
"-javaagent:<path-to-opentelemetry-javaagent.jar>") so the agent is attached to
the JVM that runs the app, while keeping the existing environment(...) OTEL
settings; reference the bootRunWithObservability task and the bootRun.jvmArgs
property when making this change.

Comment on lines +34 to +37
| Method | Use Case | How |
|--------------------------------|---------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `./gradlew server-app:bootRun` | Local development, quick iteration | `docker compose -f docker-compose.local-observability-stack-dev.yaml up -d && ./gradlew server-app:bootRunWithObservability --args='--spring.profiles.active=dev'` |
| Docker (full stack) | Testing the full stack, CI, production-like | `docker compose -f docker-compose.local-observability-stack.yaml up -d` |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

cat -n docs/observability/README.md | head -50

Repository: tolgee/tolgee-platform

Length of output: 3363


Align the "Method" label with the command shown.

The Method column shows ./gradlew server-app:bootRun, but the command uses ./gradlew server-app:bootRunWithObservability. Update the Method label to match.

✏️ Suggested edit
-| `./gradlew server-app:bootRun` | Local development, quick iteration          | `docker compose -f docker-compose.local-observability-stack-dev.yaml up -d && ./gradlew server-app:bootRunWithObservability --args='--spring.profiles.active=dev'` |
+| `./gradlew server-app:bootRunWithObservability` | Local development, quick iteration          | `docker compose -f docker-compose.local-observability-stack-dev.yaml up -d && ./gradlew server-app:bootRunWithObservability --args='--spring.profiles.active=dev'` |
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
| Method | Use Case | How |
|--------------------------------|---------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `./gradlew server-app:bootRun` | Local development, quick iteration | `docker compose -f docker-compose.local-observability-stack-dev.yaml up -d && ./gradlew server-app:bootRunWithObservability --args='--spring.profiles.active=dev'` |
| Docker (full stack) | Testing the full stack, CI, production-like | `docker compose -f docker-compose.local-observability-stack.yaml up -d` |
| Method | Use Case | How |
|-----------------------------------------------------|---------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `./gradlew server-app:bootRunWithObservability` | Local development, quick iteration | `docker compose -f docker-compose.local-observability-stack-dev.yaml up -d && ./gradlew server-app:bootRunWithObservability --args='--spring.profiles.active=dev'` |
| Docker (full stack) | Testing the full stack, CI, production-like | `docker compose -f docker-compose.local-observability-stack.yaml up -d` |
🤖 Prompt for AI Agents
In `@docs/observability/README.md` around lines 34 - 37, Update the "Method"
column entry that currently reads `./gradlew server-app:bootRun` to match the
actual command used (`./gradlew server-app:bootRunWithObservability`) in the
table row where the How cell contains `./gradlew
server-app:bootRunWithObservability --args='--spring.profiles.active=dev'`, so
the Method label and the command string are consistent.

Copy link
Collaborator

@gabrielshanahan gabrielshanahan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just one nit, otherwise LGTM and :shipit:


// Copy OTEL agent to a predictable location for IntelliJ usage
// See: docs/observability/
tasks.register('copyOtelAgent', Copy) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see this actually used anywhere - it should imho either be called as part of something, mentioned in the docs, or removed

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's used by the IntelliJ IDEA runner in the other repo, though I'm not sure myself if it's required.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants