Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/dependabot.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ updates:
patterns:
- "*"

- package-ecosystem: "gradle"
directory: "/examples/opentelemetry"
schedule:
interval: "monthly"
groups:
dependencies:
patterns:
- "*"

- package-ecosystem: "github-actions"
directory: "/"
schedule:
Expand Down
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,9 @@ VERSION.txt

# VSCode IDE
/.vscode

# env files
.env

# mac
.DS_Store
11 changes: 11 additions & 0 deletions examples/README.md
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
19 changes: 19 additions & 0 deletions examples/opentelemetry/.env.example
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

16 changes: 16 additions & 0 deletions examples/opentelemetry/Makefile
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
206 changes: 206 additions & 0 deletions examples/opentelemetry/README.md
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 '../..'
```
Comment thread
jimmyjames marked this conversation as resolved.

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)
110 changes: 110 additions & 0 deletions examples/opentelemetry/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
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'
new URL(agentUrl).withInputStream { i ->
agentFile.withOutputStream { it << i }
}
Comment thread
jimmyjames marked this conversation as resolved.
Outdated
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.32.0"
openTelemetryAlphaVersion = "1.32.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.21.0-alpha")

// 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.
Loading
Loading