@fiberplane/hono-otel
Version:
Hono middleware to forward OpenTelemetry traces to a local instance of @fiberplane/studio
209 lines (136 loc) • 7.07 kB
Markdown
# Fiberplane Hono OpenTelemetry Library
This is a client library that will send telemetry data to a *local* Fiberplane Studio server upon every incoming request and outgoing response, in order to be visualized in the Studio UI.
Under the hood, it uses [OpenTelemetry](https://opentelemetry.io/) traces to collect telemetry data and send it to a local FPX server.
By default, it proxies `console.*` functions to send logging data to a local Fiberplane Studio server,
so any time you use a `console.log`, `console.error`, etc., in your app, it will also send those log messages to FPX.
Likewise, any time your app makes a `fetch` request, it will create a trace for that request. This behavior is configurable.
The library is a no-op when the `FIBERPLANE_OTEL_ENDPOINT` environment variable is not present.
## Quick Start
Create Hono project
```sh
# Create a hono project, using cloudflare-workers runtime
npm create hono my-hono-project
# > cloudflare-workers
```
Install the Fiberplane Hono Opentelemetry Library
```sh
npm i /hono-otel
```
Wrap your Hono app with the `instrument` function:
```ts
import { Hono } from "hono";
import { instrument } from "@fiberplane/hono-otel";
const app = new Hono();
app.get("/", (c) => c.text("Hello, Hono!"));
export default instrument(app);
```
Set the `FIBERPLANE_OTEL_ENDPOINT` environment variable to the URL of an OpenTelemetry collector.
> To test with an OpenTelemetry collector, you can use the [Fiberplane otel-worker](https://github.com/fiberplane/otel-worker) which can also be deployed locally.
>
> In this case, you would set the `FIBERPLANE_OTEL_ENDPOINT` to `http://localhost:24318/v1/traces` and the `FIBERPLANE_OTEL_TOKEN` to the token of the otel-worker.
## Usage
This section takes you through:
- Installing the Fiberplane Hono OpenTelemetry Library
- Configuring the library
- Advanced usage with custom spans
It assumes you already have a Hono app running locally.
### Installation
Install the library in your project. If you're feeling adventurous, you can install the `canary` version:
```bash
npm install /hono-otel
# or
npm install /hono-otel
```
Wrap your Hono app with the `instrument` function:
```typescript
import { Hono } from "hono";
import { instrument } from "@fiberplane/hono-otel";
const app = new Hono();
app.get("/", (c) => c.text("Hello, Hono!"));
// Other routes and middleware can be added here
export default instrument(app);
```
### Configuration
If you're running in Cloudflare Workers, enable nodejs compatibility mode.
```toml
# Add this to the top level of your wrangler.toml
compatibility_flags = [ "nodejs_compat" ]
```
#### The `FIBERPLANE_OTEL_ENDPOINT` Environment Variable
When your app is running, the `FIBERPLANE_OTEL_ENDPOINT` environment variable controls where the client library sends telemetry data.
If `FIBERPLANE_OTEL_ENDPOINT` is not defined, the middleware will do nothing.
If the endpoint is a local address, the client library will collect as much data as possible for each request. Otherwise, sensitive information will be removed from the telemetry data.
You can control this behavior by setting the `FIBERPLANE_ENVIRONMENT` env variable to `"local"` to force the library to send as much data as possible, or `"production"` to force the library to send only essential data.
As mentioned earlier, there is an open source [otel-worker](https://github.com/fiberplane/otel-worker) that you can run either locally on on Cloudflare to collect telemetry data from your app.
When using the otel-worker locally, your `.dev.vars` file would look like this:
```sh
FIBERPLANE_OTEL_ENDPOINT=http://localhost:24318/v1/traces
FIBERPLANE_OTEL_TOKEN="your-secret-token-here"
```
#### Additional Configuration
When you instrument your app, you can also pass in a configuration object to override the default behavior of the `instrument` function.
The options are:
- `monitor.fetch`: Whether to create traces for all fetch requests. (Default: `true`)
- `monitor.logging`: Whether to proxy `console.*` functions to send logging data to a local Fiberplane Studio server. (Default: `true`)
- `monitor.cfBindings`: Whether to proxy Cloudflare bindings (D1, R2, KV, AI) to add instrumentation to them. (Default: `true`)
- `redactedHeaders`: Headers whose values should always be redacted.
- `redactedQueryParams`: Query params whose values should always be redacted.
- `libraryDebugMode`: Whether to enable debug logging in the library. (Default: `false`)
Here is an example:
```typescript
import { Hono } from "hono";
import { instrument } from "@fiberplane/hono-otel";
const app = new Hono();
app.get("/", (c) => c.text("Hello, Hono!"));
export default instrument(app, {
// Enable debug logging in the library
libraryDebugMode: true,
monitor: {
// Do not create traces for fetch requests
fetch: false,
// Do not proxy `console.*` functions to send logging data to a local FPX server
logging: false,
// Do not proxy Cloudflare bindings (D1, R2, KV, AI, Service Bindings) to add instrumentation to them
cfBindings: false,
},
});
```
#### Redacting Headers and Query Params
You can redact headers and query params by setting the `redactedHeaders` and `redactedQueryParams` options.
```typescript
import { Hono } from "hono";
import { instrument } from "@fiberplane/hono-otel";
const app = new Hono();
app.get("/", (c) => c.text("Hello, Hono!"));
export default instrument(app, {
redactedHeaders: ["x-mycompany-api-key"],
redactedQueryParams: ["my_api_key"],
});
```
These values will **not** be recorded inside spans, and their values will show up as `"REDACTED"`.
We merge any `redactedHeaders` and `redactedQueryParams` values with a list of sensible defaults, which are exported by the library as `DEFAULT_REDACTED_HEADERS` and `DEFAULT_REDACTED_QUERY_PARAMS`.
#### The `FIBERPLANE_OTEL_LOG_LEVEL` Environment Variable
The `FIBERPLANE_OTEL_LOG_LEVEL` environment variable controls the verbosity of the library's logging.
The possible values are: `debug`, `info`, `warn`, and `error`.
The default value is `warn`.
The `libraryDebugMode` option (documented in the previous section), takes precedence over this environment variable.
### Advanced Usage: Custom Spans with `measure`
The library also allows you to create custom spans for any function in your app.
To make use of this feature, you need to import the `measure` function from the library and wrap your function with it.
```typescript
import { instrument, measure } from "@fiberplane/hono-otel";
const app = new Hono();
// Create a loop function that will get recorded as a span inside the trace for a incoming given request
const loop = measure("loop", (n: number) => {
for (let i = 0; i < n; i++) {
console.log(`Loop iteration: ${i}`);
}
});
app.get("/", (c) => {
loop(100);
return c.text("Hello, Hono!");
});
export default instrument(app);
```
## Development
See [DEVELOPMENT.md](./DEVELOPMENT.md) for instructions on how to develop this library.