Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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 '../..'
```

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)
115 changes: 115 additions & 0 deletions examples/opentelemetry/build.gradle
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.
Loading
Loading