Skip to content

Commit c53df5f

Browse files
authored
chore(js-sdk): add opentelemetry example app (#397)
2 parents c0b75fc + 440bf14 commit c53df5f

File tree

12 files changed

+213
-6
lines changed

12 files changed

+213
-6
lines changed

config/clients/js/config.overrides.json

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,11 +119,22 @@
119119
"destinationFilename": "example/example1/package.json",
120120
"templateType": "SupportingFiles"
121121
},
122+
"example/opentelemetry/.npmrc": {},
123+
"example/opentelemetry/opentelemetry.mjs": {},
124+
"example/opentelemetry/README.md": {},
125+
"example/opentelemetry/instrumentation.mjs": {},
126+
"example/opentelemetry/package.json.mustache": {
127+
"destinationFilename": "example/opentelemetry/package.json",
128+
"templateType": "SupportingFiles"
129+
},
122130
".madgerc": {},
123131
"telemetry.mustache": {
124132
"destinationFilename": "telemetry.ts",
125133
"templateType": "SupportingFiles"
126134
},
127-
"docs/opentelemetry.md": {}
135+
"docs/opentelemetry.md.mustache": {
136+
"destinationFilename": "docs/opentelemetry.md",
137+
"templateType": "SupportingFiles"
138+
}
128139
}
129140
}

config/clients/js/template/.github/workflows/main.yaml.mustache

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ jobs:
2424
fetch-depth: 0
2525

2626
- name: Set up node
27-
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
27+
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
2828
with:
2929
node-version: ${{ matrix.node-version }}
3030
registry-url: "https://registry.npmjs.org"
@@ -47,7 +47,7 @@ jobs:
4747
fetch-depth: 0
4848

4949
- name: Set up node
50-
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
50+
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
5151
with:
5252
node-version: 20
5353
cache: "npm"
@@ -86,7 +86,7 @@ jobs:
8686
fetch-depth: 0
8787

8888
- name: Set up node
89-
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
89+
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b # v4.0.3
9090
with:
9191
node-version: 20
9292
registry-url: "https://registry.npmjs.org"

config/clients/js/template/docs/opentelemetry.md renamed to config/clients/js/template/docs/opentelemetry.md.mustache

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,8 @@ In cases when metrics events are sent, they will not be viewable outside of infr
2828
| `fga-client.user` | `string` | The user that is associated with the action of the request for check and list users |
2929
| `http.status_code ` | `int` | The status code of the response |
3030
| `http.method` | `string` | The HTTP method for the request |
31-
| `http.host` | `string` | Host identifier of the origin the request was sent to |
31+
| `http.host` | `string` | Host identifier of the origin the request was sent to |
32+
33+
## Example
34+
35+
There is an [example project](https://{{gitHost}}/{{gitUserId}}/{{gitRepoId}}/blob/main/example/opentelemetry) that provides some guidance on how to configure OpenTelemetry available in the examples directory.

config/clients/js/template/example/README.md.mustache

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ A set of Examples on how to call the OpenFGA JS SDK
66
Example 1:
77
A bare-bones example. It creates a store, and runs a set of calls against it including creating a model, writing tuples and checking for access.
88

9+
OpenTelemetry:
10+
An example that demonstrates how to integrate the OpenFGA JS SDK with OpenTelemetry.
11+
912
### Running the Examples
1013

1114
Prerequisites:
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# Configuration for OpenFGA
2+
FGA_CLIENT_ID=
3+
FGA_API_TOKEN_ISSUER=
4+
FGA_API_AUDIENCE=
5+
FGA_CLIENT_SECRET=
6+
FGA_STORE_ID=
7+
FGA_AUTHORIZATION_MODEL_ID=
8+
FGA_API_URL="http://localhost:8080"
9+
10+
# Configuration for OpenTelemetry
11+
OTEL_SERVICE_NAME="openfga-opentelemetry-example"
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
package-lock=false
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# OpenTelemetry usage with OpenFGA's JS SDK
2+
3+
This example demonstrates how you can use OpenTelemetry with OpenFGA's JS SDK.
4+
5+
## Prerequisites
6+
7+
If you do not already have an OpenFGA instance running, you can start one using the following command:
8+
9+
```bash
10+
docker run -d -p 8080:8080 openfga/openfga
11+
```
12+
13+
You need to have an OpenTelemetry collector running to receive data. A pre-configured collector is available using Docker:
14+
15+
```bash
16+
git clone https://github.com/ewanharris/opentelemetry-collector-dev-setup.git
17+
cd opentelemetry-collector-dev-setup
18+
docker-compose up -d
19+
```
20+
21+
## Configure the example
22+
23+
You need to configure the example for your environment:
24+
25+
```bash
26+
cp .env.example .env
27+
```
28+
29+
Now edit the `.env` file and set the values as appropriate.
30+
31+
## Running the example
32+
33+
Begin by installing the required dependencies:
34+
35+
```bash
36+
npm i
37+
```
38+
39+
Next, run the example:
40+
41+
```bash
42+
npm start
43+
```
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import "dotenv/config";
2+
import { NodeSDK } from "@opentelemetry/sdk-node";
3+
import { PeriodicExportingMetricReader } from "@opentelemetry/sdk-metrics";
4+
import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-proto";
5+
import process from "process";
6+
7+
const sdk = new NodeSDK({
8+
metricReader: new PeriodicExportingMetricReader({
9+
exportIntervalMillis: 5000,
10+
exporter: new OTLPMetricExporter({
11+
concurrencyLimit: 1,
12+
}),
13+
}),
14+
});
15+
sdk.start();
16+
17+
process.on("exit", () => {
18+
sdk
19+
.shutdown()
20+
.then(
21+
() => console.log("SDK shut down successfully"),
22+
(err) => console.log("Error shutting down SDK", err)
23+
)
24+
.finally(() => process.exit(0));
25+
});
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import "dotenv/config";
2+
import { CredentialsMethod, FgaApiValidationError, OpenFgaClient } from "@openfga/sdk";
3+
4+
let credentials;
5+
if (process.env.FGA_CLIENT_ID) {
6+
credentials = {
7+
method: CredentialsMethod.ClientCredentials,
8+
config: {
9+
clientId: process.env.FGA_CLIENT_ID,
10+
clientSecret: process.env.FGA_CLIENT_SECRET,
11+
apiAudience: process.env.FGA_API_AUDIENCE,
12+
apiTokenIssuer: process.env.FGA_API_TOKEN_ISSUER
13+
}
14+
};
15+
}
16+
17+
const fgaClient = new OpenFgaClient({
18+
apiUrl: process.env.FGA_API_URL,
19+
storeId: process.env.FGA_STORE_ID,
20+
authorizationModelId: process.env.FGA_MODEL_ID,
21+
credentials
22+
});
23+
24+
async function main () {
25+
26+
setTimeout(async () => {
27+
try {
28+
await main();
29+
} catch (error) {
30+
console.log(error);
31+
}
32+
}, 20000);
33+
34+
console.log("Reading Authorization Models");
35+
const { authorization_models } = await fgaClient.readAuthorizationModels();
36+
console.log(`Models Count: ${authorization_models.length}`);
37+
38+
console.log("Reading Tuples");
39+
const { tuples } = await fgaClient.read();
40+
console.log(`Tuples count: ${tuples.length}`);
41+
42+
43+
const checkRequests = Math.floor(Math.random() * 10);
44+
console.log(`Making ${checkRequests} checks`);
45+
for (let index = 0; index < checkRequests; index++) {
46+
console.log("Checking for access" + index);
47+
try {
48+
const { allowed } = await fgaClient.check({
49+
user: "user:anne",
50+
relation: "owner",
51+
object: "folder:foo"
52+
});
53+
console.log(`Allowed: ${allowed}`);
54+
} catch (error) {
55+
if (error instanceof FgaApiValidationError) {
56+
console.log(`Failed due to ${error.apiErrorMessage}`);
57+
} else {
58+
throw error;
59+
}
60+
}
61+
}
62+
63+
console.log("writing tuple");
64+
await fgaClient.write({
65+
writes: [
66+
{
67+
user: "user:anne",
68+
relation: "owner",
69+
object: "folder:date-"+Date.now(),
70+
}
71+
]
72+
});
73+
}
74+
75+
76+
main()
77+
.catch(error => {
78+
console.error(`error: ${error}`);
79+
process.exitCode = 1;
80+
});
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{
2+
"name": "openfga-opentelemetry-example",
3+
"private": "true",
4+
"version": "1.0.0",
5+
"description": "A bare bones example of using the OpenFGA SDK with OpenTelemetry metrics reporting",
6+
"author": "OpenFGA",
7+
"license": "Apache-2.0",
8+
"scripts": {
9+
"start": "node --import ./instrumentation.mjs opentelemetry.mjs"
10+
},
11+
"dependencies": {
12+
"@openfga/sdk": "^{{packageVersion}}",
13+
"@opentelemetry/exporter-metrics-otlp-proto": "^0.52.1",
14+
"@opentelemetry/exporter-prometheus": "^0.52.1",
15+
"@opentelemetry/sdk-metrics": "^1.25.1",
16+
"@opentelemetry/sdk-node": "^0.52.1",
17+
"dotenv": "^16.4.5"
18+
},
19+
"engines": {
20+
"node": ">=16.13.0"
21+
}
22+
}

0 commit comments

Comments
 (0)