Skip to content

Commit 38f94be

Browse files
docs: add OpenTelemetry example (#211)
* docs: add open telemetry example * use published SDK version by default * add makefile * add top-level README * code cleanup * update dependabot * add gradle wrapper jar * Update examples/opentelemetry/build.gradle Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fix build, update otel deps --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
1 parent 597ecdc commit 38f94be

13 files changed

Lines changed: 1133 additions & 0 deletions

File tree

.github/dependabot.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,15 @@ updates:
2020
patterns:
2121
- "*"
2222

23+
- package-ecosystem: "gradle"
24+
directory: "/examples/opentelemetry"
25+
schedule:
26+
interval: "monthly"
27+
groups:
28+
dependencies:
29+
patterns:
30+
- "*"
31+
2332
- package-ecosystem: "github-actions"
2433
directory: "/"
2534
schedule:

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,9 @@ VERSION.txt
3030

3131
# VSCode IDE
3232
/.vscode
33+
34+
# env files
35+
.env
36+
37+
# mac
38+
.DS_Store

examples/README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
## Examples of using the OpenFGA Java SDK
2+
3+
A collection of examples demonstrating how to use the OpenFGA Java SDK in different scenarios.
4+
5+
### Available Examples
6+
7+
#### Basic Examples (`basic-examples/`)
8+
A simple example that creates a store, runs a set of calls against it including creating a model, writing tuples and checking for access. This example is implemented in both Java and Kotlin.
9+
10+
#### OpenTelemetry Examples
11+
- `opentelemetry/` - Demonstrates OpenTelemetry integration both via manual code configuration, as well as no-code instrumentation using the OpenTelemetry java agent
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# OpenFGA Configuration (REQUIRED)
2+
FGA_API_URL=api_url_here
3+
FGA_STORE_ID=store_id_here
4+
FGA_MODEL_ID=model_id_here
5+
6+
# Authentication (optional - for authenticated OpenFGA instances)
7+
FGA_CLIENT_ID=client_id_here
8+
FGA_CLIENT_SECRET=client_secret_here
9+
FGA_API_AUDIENCE=api_audience_here
10+
FGA_API_TOKEN_ISSUER=api_issuer_here
11+
12+
# OpenTelemetry Configuration (for manual configuration mode - ./gradlew run)
13+
# These are used when running with manual OpenTelemetry setup
14+
# Note: When using the Java agent (./gradlew runWithAgent),
15+
# these values are overridden by the JVM arguments in build.gradle
16+
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317
17+
OTEL_SERVICE_NAME=openfga-java-sdk-example
18+
OTEL_SERVICE_VERSION=1.0.0
19+

examples/opentelemetry/Makefile

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
all: build
2+
3+
openfga_version=latest
4+
5+
build:
6+
./gradlew build
7+
8+
run:
9+
./gradlew run
10+
11+
run-with-agent:
12+
./gradlew runWithAgent
13+
14+
run-openfga:
15+
docker pull docker.io/openfga/openfga:${openfga_version} && \
16+
docker run -p 8080:8080 docker.io/openfga/openfga:${openfga_version} run

examples/opentelemetry/README.md

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,206 @@
1+
# OpenTelemetry Example for OpenFGA Java SDK
2+
3+
This example demonstrates two approaches for using OpenTelemetry metrics with the OpenFGA Java SDK:
4+
5+
1. **Manual Configuration** (`./gradlew run`) - Code-based OpenTelemetry setup
6+
2. **Java Agent** (`./gradlew runWithAgent`) - Zero-code automatic instrumentation
7+
8+
Both approaches generate the same metrics:
9+
- `fga-client.request.duration` - Total request time for FGA requests
10+
- `fga-client.query.duration` - Time taken by FGA server to process requests
11+
- `fga-client.credentials.request` - Number of token requests (if using client credentials)
12+
13+
## SDK Version Configuration
14+
15+
**By default**, this example uses a published version of the OpenFGA Java SDK.
16+
17+
If you're contributing to the SDK or testing unreleased features:
18+
19+
1. **Enable local SDK** in `settings.gradle`:
20+
```gradle
21+
// Uncomment this line:
22+
includeBuild '../..'
23+
```
24+
25+
2. **Update dependency** in `build.gradle`:
26+
```gradle
27+
// Comment out the versioned dependency:
28+
// implementation("dev.openfga:openfga-sdk:$fgaSdkVersion")
29+
30+
// Uncomment the local dependency:
31+
implementation("dev.openfga:openfga-sdk")
32+
```
33+
34+
3. **Build the main SDK first** (from repository root):
35+
```bash
36+
cd ../..
37+
./gradlew build
38+
cd examples/opentelemetry
39+
```
40+
41+
## Prerequisites
42+
43+
- Java 11 or higher
44+
- Docker and Docker Compose
45+
- OpenFGA server running (or use the provided docker-compose setup)
46+
47+
## Quick Start
48+
49+
### 1. Start the OpenTelemetry Stack
50+
51+
```bash
52+
# Clone the OpenTelemetry Collector setup
53+
git clone https://github.com/ewanharris/opentelemetry-collector-dev-setup.git otel-collector
54+
cd otel-collector
55+
56+
# Start the services
57+
docker-compose up -d
58+
```
59+
60+
This provides:
61+
- **Jaeger** at http://localhost:16686 - Distributed tracing UI
62+
- **Prometheus** at http://localhost:9090 - Metrics collection and querying
63+
- **Grafana** at http://localhost:3001 - Metrics visualization (admin:admin)
64+
65+
### 2. Configure OpenFGA Connection
66+
67+
Copy and edit the environment file:
68+
```bash
69+
cp .env.example .env
70+
# Edit .env with your OpenFGA store details
71+
```
72+
73+
### 3. Choose Your Approach
74+
75+
#### Option A: Manual Configuration (./gradlew run)
76+
```bash
77+
./gradlew run
78+
```
79+
80+
**Pros:**
81+
- Full control over OpenTelemetry configuration
82+
- Can customize metrics, exporters, and resources in code
83+
- No external dependencies beyond your application
84+
85+
**Cons:**
86+
- Requires OpenTelemetry SDK dependencies in your application
87+
- More code to write and maintain
88+
89+
#### Option B: Java Agent (./gradlew runWithAgent)
90+
```bash
91+
./gradlew runWithAgent
92+
```
93+
94+
**Pros:**
95+
- Zero code changes required - completely automatic
96+
- No OpenTelemetry dependencies needed in your application
97+
- Easy to enable/disable by adding/removing the agent
98+
99+
**Cons:**
100+
- Less control over configuration
101+
- Requires downloading and managing the agent JAR
102+
103+
## Viewing Metrics
104+
105+
Both approaches export metrics to the same OTLP endpoint. View them in:
106+
107+
- **Prometheus**: http://localhost:9090/graph
108+
- Query: `fga_client_request_duration_bucket`
109+
- Query: `fga_client_query_duration_bucket`
110+
- Query: `fga_client_credentials_request_total`
111+
112+
- **Grafana**: http://localhost:3001 (admin:admin)
113+
- Import dashboard from `grafana/` directory
114+
- Or create custom dashboards with the FGA metrics
115+
116+
## Architecture
117+
118+
### Manual Configuration Mode
119+
```
120+
Your App → OpenTelemetry SDK → OTLP Exporter → Collector → Prometheus/Jaeger
121+
```
122+
123+
The application code:
124+
1. Configures OpenTelemetry SDK with OTLP exporter
125+
2. Creates OpenFGA client with default telemetry enabled
126+
3. Performs FGA operations which generate metrics
127+
4. Metrics are exported to the OTLP collector
128+
129+
### Java Agent Mode
130+
```
131+
Your App → OpenTelemetry Agent → OTLP Exporter → Collector → Prometheus/Jaeger
132+
```
133+
134+
The OpenTelemetry agent:
135+
1. Automatically detects and instruments the OpenFGA SDK
136+
2. Configures exporters based on system properties
137+
3. Collects metrics without any code changes
138+
4. Exports to the same OTLP collector
139+
140+
## Troubleshooting
141+
142+
### No Metrics Appearing
143+
1. Verify OTLP collector is running on localhost:4317
144+
2. Check the application logs for OpenTelemetry initialization messages
145+
3. Ensure FGA operations are actually being performed
146+
147+
### Manual Configuration Issues
148+
- Verify all OpenTelemetry dependencies are included
149+
- Check that `buildAndRegisterGlobal()` is called before creating the FGA client
150+
151+
### Java Agent Issues
152+
- Verify the agent JAR was downloaded successfully
153+
- Check that OTEL system properties are set correctly
154+
- Ensure the agent is being loaded (look for agent startup messages)
155+
156+
### Connection Issues
157+
- Verify your `.env` file has correct FGA_STORE_ID and FGA_MODEL_ID
158+
- Check that your OpenFGA server is accessible
159+
- Verify authentication credentials if using a protected OpenFGA instance
160+
161+
## Observing Metrics
162+
163+
### Prometheus (http://localhost:9090)
164+
165+
Query for OpenFGA metrics:
166+
- `fga_client_request_duration_bucket` - Request duration histogram
167+
- `fga_client_query_duration_bucket` - Query duration histogram
168+
- `fga_client_credentials_request_total` - Credentials request counter
169+
170+
Example queries:
171+
```promql
172+
# Average request duration by method
173+
rate(fga_client_request_duration_sum[5m]) / rate(fga_client_request_duration_count[5m])
174+
175+
# Request rate by HTTP status code
176+
rate(fga_client_request_duration_count[5m])
177+
178+
# 95th percentile request duration
179+
histogram_quantile(0.95, rate(fga_client_request_duration_bucket[5m]))
180+
```
181+
182+
### Grafana (http://localhost:3001)
183+
184+
Login with `admin:admin`. The collector setup includes pre-configured dashboards for OpenFGA metrics.
185+
186+
## Next Steps
187+
188+
- Explore the metrics in Grafana with custom dashboards
189+
- Try different telemetry configurations to see what works best for your use case
190+
- Consider which approach (manual vs agent) fits better with your deployment strategy
191+
192+
## Cleanup
193+
194+
To stop the OpenTelemetry stack:
195+
196+
```bash
197+
cd otel-collector
198+
docker-compose down
199+
```
200+
201+
## Learn More
202+
203+
- [OpenFGA Documentation](https://openfga.dev/docs)
204+
- [OpenFGA Java SDK Documentation](../../README.md)
205+
- [OpenTelemetry Java Documentation](https://opentelemetry.io/docs/languages/java/)
206+
- [OpenFGA Telemetry Documentation](../../docs/OpenTelemetry.md)
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
plugins {
2+
id 'application'
3+
id 'com.diffplug.spotless' version '7.2.1'
4+
}
5+
6+
application {
7+
mainClass = 'dev.openfga.sdk.example.opentelemetry.OpenTelemetryExample'
8+
}
9+
10+
// Override the default run task to pass manual config flag
11+
run {
12+
args = ['--mode=manual']
13+
}
14+
15+
// Task to download OpenTelemetry Java agent if not present
16+
task downloadAgent {
17+
group = 'setup'
18+
description = 'Download OpenTelemetry Java agent if not present'
19+
20+
doLast {
21+
def agentFile = file('opentelemetry-javaagent.jar')
22+
if (!agentFile.exists()) {
23+
println "Downloading OpenTelemetry Java agent..."
24+
def agentUrl = 'https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar'
25+
try {
26+
new URL(agentUrl).withInputStream { i ->
27+
agentFile.withOutputStream { it << i }
28+
}
29+
println "Downloaded opentelemetry-javaagent.jar"
30+
} catch (Exception e) {
31+
throw new GradleException("Failed to download OpenTelemetry agent: ${e.message}", e)
32+
}
33+
println "Downloaded opentelemetry-javaagent.jar"
34+
} else {
35+
println "OpenTelemetry agent already exists"
36+
}
37+
}
38+
}
39+
40+
// Task to run with OpenTelemetry agent (no-code approach)
41+
task runWithAgent(type: JavaExec) {
42+
group = 'application'
43+
description = 'Run the OpenTelemetry example with Java agent (no-code approach)'
44+
dependsOn downloadAgent
45+
classpath = sourceSets.main.runtimeClasspath
46+
mainClass = 'dev.openfga.sdk.example.opentelemetry.OpenTelemetryExample'
47+
48+
// Add JVM arguments for OpenTelemetry agent with configuration
49+
jvmArgs = [
50+
'-javaagent:opentelemetry-javaagent.jar',
51+
'-Dotel.service.name=openfga-java-sdk-agent-example',
52+
'-Dotel.service.version=1.0.0',
53+
'-Dotel.exporter.otlp.endpoint=http://localhost:4317',
54+
'-Dotel.exporter.otlp.protocol=grpc'
55+
]
56+
57+
// Pass agent mode flag to the application
58+
args = ['--mode=agent']
59+
60+
doFirst {
61+
println "🤖 Running with OpenTelemetry Java agent (no-code approach)..."
62+
println "Service Name: openfga-java-sdk-agent-example"
63+
println "Service Version: 1.0.0"
64+
println "Exporter Endpoint: http://localhost:4317"
65+
println "Exporter Protocol: grpc"
66+
println ""
67+
println "Make sure you have an OTLP collector running on localhost:4317"
68+
println "The agent automatically instruments the application - no code changes needed!"
69+
}
70+
}
71+
72+
repositories {
73+
mavenCentral()
74+
}
75+
76+
ext {
77+
fgaSdkVersion = "0.9.0"
78+
openTelemetryVersion = "1.53.0"
79+
openTelemetryAlphaVersion = "1.53.0-alpha"
80+
}
81+
82+
dependencies {
83+
// Core FGA SDK (always required)
84+
// By default, uses the published SDK from Maven Central
85+
implementation("dev.openfga:openfga-sdk:$fgaSdkVersion")
86+
87+
// For local development using the SDK source code:
88+
// 1. Uncomment the includeBuild line in settings.gradle
89+
// 2. Comment out the line above and uncomment the line below:
90+
// implementation("dev.openfga:openfga-sdk")
91+
92+
// OpenTelemetry SDK dependencies - ONLY NEEDED FOR MANUAL CONFIGURATION (./gradlew run)
93+
// When using the Java agent (./gradlew runWithAgent), these dependencies are not required
94+
// The agent provides all OpenTelemetry functionality automatically
95+
implementation("io.opentelemetry:opentelemetry-sdk:$openTelemetryVersion")
96+
implementation("io.opentelemetry:opentelemetry-exporter-prometheus:$openTelemetryAlphaVersion")
97+
implementation("io.opentelemetry:opentelemetry-exporter-otlp:$openTelemetryVersion")
98+
implementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure:$openTelemetryVersion")
99+
implementation("io.opentelemetry.semconv:opentelemetry-semconv:1.34.0")
100+
101+
// Environment variables for this example
102+
implementation("io.github.cdimascio:dotenv-java:3.2.0")
103+
}
104+
105+
// Use spotless plugin to automatically format code
106+
spotless {
107+
enforceCheck false
108+
java {
109+
palantirJavaFormat()
110+
removeUnusedImports()
111+
importOrder()
112+
}
113+
}
114+
115+
42.4 KB
Binary file not shown.

0 commit comments

Comments
 (0)