-
Notifications
You must be signed in to change notification settings - Fork 20
docs: add OpenTelemetry example #211
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
997664c
docs: add open telemetry example
jimmyjames 640cf9c
use published SDK version by default
jimmyjames 3d61cc0
add makefile
jimmyjames 4cb1be5
add top-level README
jimmyjames c1a3b8f
code cleanup
jimmyjames 826cdd8
update dependabot
jimmyjames 11271b0
add gradle wrapper jar
jimmyjames 24883ee
Update examples/opentelemetry/build.gradle
jimmyjames c589608
fix build, update otel deps
jimmyjames File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -30,3 +30,9 @@ VERSION.txt | |
|
||
# VSCode IDE | ||
/.vscode | ||
|
||
# env files | ||
.env | ||
|
||
# mac | ||
.DS_Store |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
## Examples of using the OpenFGA Java SDK | ||
|
||
A collection of examples demonstrating how to use the OpenFGA Java SDK in different scenarios. | ||
|
||
### Available Examples | ||
|
||
#### Basic Examples (`basic-examples/`) | ||
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. | ||
|
||
#### OpenTelemetry Examples | ||
- `opentelemetry/` - Demonstrates OpenTelemetry integration both via manual code configuration, as well as no-code instrumentation using the OpenTelemetry java agent |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
# OpenFGA Configuration (REQUIRED) | ||
FGA_API_URL=api_url_here | ||
FGA_STORE_ID=store_id_here | ||
FGA_MODEL_ID=model_id_here | ||
|
||
# Authentication (optional - for authenticated OpenFGA instances) | ||
FGA_CLIENT_ID=client_id_here | ||
FGA_CLIENT_SECRET=client_secret_here | ||
FGA_API_AUDIENCE=api_audience_here | ||
FGA_API_TOKEN_ISSUER=api_issuer_here | ||
|
||
# OpenTelemetry Configuration (for manual configuration mode - ./gradlew run) | ||
# These are used when running with manual OpenTelemetry setup | ||
# Note: When using the Java agent (./gradlew runWithAgent), | ||
# these values are overridden by the JVM arguments in build.gradle | ||
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317 | ||
OTEL_SERVICE_NAME=openfga-java-sdk-example | ||
OTEL_SERVICE_VERSION=1.0.0 | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
all: build | ||
|
||
openfga_version=latest | ||
|
||
build: | ||
./gradlew build | ||
|
||
run: | ||
./gradlew run | ||
|
||
run-with-agent: | ||
./gradlew runWithAgent | ||
|
||
run-openfga: | ||
docker pull docker.io/openfga/openfga:${openfga_version} && \ | ||
docker run -p 8080:8080 docker.io/openfga/openfga:${openfga_version} run |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,206 @@ | ||
# OpenTelemetry Example for OpenFGA Java SDK | ||
|
||
This example demonstrates two approaches for using OpenTelemetry metrics with the OpenFGA Java SDK: | ||
|
||
1. **Manual Configuration** (`./gradlew run`) - Code-based OpenTelemetry setup | ||
2. **Java Agent** (`./gradlew runWithAgent`) - Zero-code automatic instrumentation | ||
|
||
Both approaches generate the same metrics: | ||
- `fga-client.request.duration` - Total request time for FGA requests | ||
- `fga-client.query.duration` - Time taken by FGA server to process requests | ||
- `fga-client.credentials.request` - Number of token requests (if using client credentials) | ||
|
||
## SDK Version Configuration | ||
|
||
**By default**, this example uses a published version of the OpenFGA Java SDK. | ||
|
||
If you're contributing to the SDK or testing unreleased features: | ||
|
||
1. **Enable local SDK** in `settings.gradle`: | ||
```gradle | ||
// Uncomment this line: | ||
includeBuild '../..' | ||
``` | ||
|
||
2. **Update dependency** in `build.gradle`: | ||
```gradle | ||
// Comment out the versioned dependency: | ||
// implementation("dev.openfga:openfga-sdk:$fgaSdkVersion") | ||
|
||
// Uncomment the local dependency: | ||
implementation("dev.openfga:openfga-sdk") | ||
``` | ||
|
||
3. **Build the main SDK first** (from repository root): | ||
```bash | ||
cd ../.. | ||
./gradlew build | ||
cd examples/opentelemetry | ||
``` | ||
|
||
## Prerequisites | ||
|
||
- Java 11 or higher | ||
- Docker and Docker Compose | ||
- OpenFGA server running (or use the provided docker-compose setup) | ||
|
||
## Quick Start | ||
|
||
### 1. Start the OpenTelemetry Stack | ||
|
||
```bash | ||
# Clone the OpenTelemetry Collector setup | ||
git clone https://github.com/ewanharris/opentelemetry-collector-dev-setup.git otel-collector | ||
cd otel-collector | ||
|
||
# Start the services | ||
docker-compose up -d | ||
``` | ||
|
||
This provides: | ||
- **Jaeger** at http://localhost:16686 - Distributed tracing UI | ||
- **Prometheus** at http://localhost:9090 - Metrics collection and querying | ||
- **Grafana** at http://localhost:3001 - Metrics visualization (admin:admin) | ||
|
||
### 2. Configure OpenFGA Connection | ||
|
||
Copy and edit the environment file: | ||
```bash | ||
cp .env.example .env | ||
# Edit .env with your OpenFGA store details | ||
``` | ||
|
||
### 3. Choose Your Approach | ||
|
||
#### Option A: Manual Configuration (./gradlew run) | ||
```bash | ||
./gradlew run | ||
``` | ||
|
||
**Pros:** | ||
- Full control over OpenTelemetry configuration | ||
- Can customize metrics, exporters, and resources in code | ||
- No external dependencies beyond your application | ||
|
||
**Cons:** | ||
- Requires OpenTelemetry SDK dependencies in your application | ||
- More code to write and maintain | ||
|
||
#### Option B: Java Agent (./gradlew runWithAgent) | ||
```bash | ||
./gradlew runWithAgent | ||
``` | ||
|
||
**Pros:** | ||
- Zero code changes required - completely automatic | ||
- No OpenTelemetry dependencies needed in your application | ||
- Easy to enable/disable by adding/removing the agent | ||
|
||
**Cons:** | ||
- Less control over configuration | ||
- Requires downloading and managing the agent JAR | ||
|
||
## Viewing Metrics | ||
|
||
Both approaches export metrics to the same OTLP endpoint. View them in: | ||
|
||
- **Prometheus**: http://localhost:9090/graph | ||
- Query: `fga_client_request_duration_bucket` | ||
- Query: `fga_client_query_duration_bucket` | ||
- Query: `fga_client_credentials_request_total` | ||
|
||
- **Grafana**: http://localhost:3001 (admin:admin) | ||
- Import dashboard from `grafana/` directory | ||
- Or create custom dashboards with the FGA metrics | ||
|
||
## Architecture | ||
|
||
### Manual Configuration Mode | ||
``` | ||
Your App β OpenTelemetry SDK β OTLP Exporter β Collector β Prometheus/Jaeger | ||
``` | ||
|
||
The application code: | ||
1. Configures OpenTelemetry SDK with OTLP exporter | ||
2. Creates OpenFGA client with default telemetry enabled | ||
3. Performs FGA operations which generate metrics | ||
4. Metrics are exported to the OTLP collector | ||
|
||
### Java Agent Mode | ||
``` | ||
Your App β OpenTelemetry Agent β OTLP Exporter β Collector β Prometheus/Jaeger | ||
``` | ||
|
||
The OpenTelemetry agent: | ||
1. Automatically detects and instruments the OpenFGA SDK | ||
2. Configures exporters based on system properties | ||
3. Collects metrics without any code changes | ||
4. Exports to the same OTLP collector | ||
|
||
## Troubleshooting | ||
|
||
### No Metrics Appearing | ||
1. Verify OTLP collector is running on localhost:4317 | ||
2. Check the application logs for OpenTelemetry initialization messages | ||
3. Ensure FGA operations are actually being performed | ||
|
||
### Manual Configuration Issues | ||
- Verify all OpenTelemetry dependencies are included | ||
- Check that `buildAndRegisterGlobal()` is called before creating the FGA client | ||
|
||
### Java Agent Issues | ||
- Verify the agent JAR was downloaded successfully | ||
- Check that OTEL system properties are set correctly | ||
- Ensure the agent is being loaded (look for agent startup messages) | ||
|
||
### Connection Issues | ||
- Verify your `.env` file has correct FGA_STORE_ID and FGA_MODEL_ID | ||
- Check that your OpenFGA server is accessible | ||
- Verify authentication credentials if using a protected OpenFGA instance | ||
|
||
## Observing Metrics | ||
|
||
### Prometheus (http://localhost:9090) | ||
|
||
Query for OpenFGA metrics: | ||
- `fga_client_request_duration_bucket` - Request duration histogram | ||
- `fga_client_query_duration_bucket` - Query duration histogram | ||
- `fga_client_credentials_request_total` - Credentials request counter | ||
|
||
Example queries: | ||
```promql | ||
# Average request duration by method | ||
rate(fga_client_request_duration_sum[5m]) / rate(fga_client_request_duration_count[5m]) | ||
|
||
# Request rate by HTTP status code | ||
rate(fga_client_request_duration_count[5m]) | ||
|
||
# 95th percentile request duration | ||
histogram_quantile(0.95, rate(fga_client_request_duration_bucket[5m])) | ||
``` | ||
|
||
### Grafana (http://localhost:3001) | ||
|
||
Login with `admin:admin`. The collector setup includes pre-configured dashboards for OpenFGA metrics. | ||
|
||
## Next Steps | ||
|
||
- Explore the metrics in Grafana with custom dashboards | ||
- Try different telemetry configurations to see what works best for your use case | ||
- Consider which approach (manual vs agent) fits better with your deployment strategy | ||
|
||
## Cleanup | ||
|
||
To stop the OpenTelemetry stack: | ||
|
||
```bash | ||
cd otel-collector | ||
docker-compose down | ||
``` | ||
|
||
## Learn More | ||
|
||
- [OpenFGA Documentation](https://openfga.dev/docs) | ||
- [OpenFGA Java SDK Documentation](../../README.md) | ||
- [OpenTelemetry Java Documentation](https://opentelemetry.io/docs/languages/java/) | ||
- [OpenFGA Telemetry Documentation](../../docs/OpenTelemetry.md) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
plugins { | ||
id 'application' | ||
id 'com.diffplug.spotless' version '7.2.1' | ||
} | ||
|
||
application { | ||
mainClass = 'dev.openfga.sdk.example.opentelemetry.OpenTelemetryExample' | ||
} | ||
|
||
// Override the default run task to pass manual config flag | ||
run { | ||
args = ['--mode=manual'] | ||
} | ||
|
||
// Task to download OpenTelemetry Java agent if not present | ||
task downloadAgent { | ||
group = 'setup' | ||
description = 'Download OpenTelemetry Java agent if not present' | ||
|
||
doLast { | ||
def agentFile = file('opentelemetry-javaagent.jar') | ||
if (!agentFile.exists()) { | ||
println "Downloading OpenTelemetry Java agent..." | ||
def agentUrl = 'https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar' | ||
try { | ||
new URL(agentUrl).withInputStream { i -> | ||
agentFile.withOutputStream { it << i } | ||
} | ||
println "Downloaded opentelemetry-javaagent.jar" | ||
} catch (Exception e) { | ||
throw new GradleException("Failed to download OpenTelemetry agent: ${e.message}", e) | ||
} | ||
println "Downloaded opentelemetry-javaagent.jar" | ||
} else { | ||
println "OpenTelemetry agent already exists" | ||
} | ||
} | ||
} | ||
|
||
// Task to run with OpenTelemetry agent (no-code approach) | ||
task runWithAgent(type: JavaExec) { | ||
group = 'application' | ||
description = 'Run the OpenTelemetry example with Java agent (no-code approach)' | ||
dependsOn downloadAgent | ||
classpath = sourceSets.main.runtimeClasspath | ||
mainClass = 'dev.openfga.sdk.example.opentelemetry.OpenTelemetryExample' | ||
|
||
// Add JVM arguments for OpenTelemetry agent with configuration | ||
jvmArgs = [ | ||
'-javaagent:opentelemetry-javaagent.jar', | ||
'-Dotel.service.name=openfga-java-sdk-agent-example', | ||
'-Dotel.service.version=1.0.0', | ||
'-Dotel.exporter.otlp.endpoint=http://localhost:4317', | ||
'-Dotel.exporter.otlp.protocol=grpc' | ||
] | ||
|
||
// Pass agent mode flag to the application | ||
args = ['--mode=agent'] | ||
|
||
doFirst { | ||
println "π€ Running with OpenTelemetry Java agent (no-code approach)..." | ||
println "Service Name: openfga-java-sdk-agent-example" | ||
println "Service Version: 1.0.0" | ||
println "Exporter Endpoint: http://localhost:4317" | ||
println "Exporter Protocol: grpc" | ||
println "" | ||
println "Make sure you have an OTLP collector running on localhost:4317" | ||
println "The agent automatically instruments the application - no code changes needed!" | ||
} | ||
} | ||
|
||
repositories { | ||
mavenCentral() | ||
} | ||
|
||
ext { | ||
fgaSdkVersion = "0.9.0" | ||
openTelemetryVersion = "1.53.0" | ||
openTelemetryAlphaVersion = "1.53.0-alpha" | ||
} | ||
|
||
dependencies { | ||
// Core FGA SDK (always required) | ||
// By default, uses the published SDK from Maven Central | ||
implementation("dev.openfga:openfga-sdk:$fgaSdkVersion") | ||
|
||
// For local development using the SDK source code: | ||
// 1. Uncomment the includeBuild line in settings.gradle | ||
// 2. Comment out the line above and uncomment the line below: | ||
// implementation("dev.openfga:openfga-sdk") | ||
|
||
// OpenTelemetry SDK dependencies - ONLY NEEDED FOR MANUAL CONFIGURATION (./gradlew run) | ||
// When using the Java agent (./gradlew runWithAgent), these dependencies are not required | ||
// The agent provides all OpenTelemetry functionality automatically | ||
implementation("io.opentelemetry:opentelemetry-sdk:$openTelemetryVersion") | ||
implementation("io.opentelemetry:opentelemetry-exporter-prometheus:$openTelemetryAlphaVersion") | ||
implementation("io.opentelemetry:opentelemetry-exporter-otlp:$openTelemetryVersion") | ||
implementation("io.opentelemetry:opentelemetry-sdk-extension-autoconfigure:$openTelemetryVersion") | ||
implementation("io.opentelemetry.semconv:opentelemetry-semconv:1.34.0") | ||
|
||
// Environment variables for this example | ||
implementation("io.github.cdimascio:dotenv-java:3.2.0") | ||
} | ||
|
||
// Use spotless plugin to automatically format code | ||
spotless { | ||
enforceCheck false | ||
java { | ||
palantirJavaFormat() | ||
removeUnusedImports() | ||
importOrder() | ||
} | ||
} | ||
|
||
|
Binary file not shown.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.