#
Setup Honeycomb
Prefer using the @workleap/telemetry umbrella package over this standalone library.
While we recommend using the @workleap/telemetry
umbrella package, Workleap's LogRocket instrumentation can also be used as a standalone @worleap/honeycomb package.
To set it up, follow these steps 👇
#
Install the packages
First, open a terminal at the root of the application and install the following packages:
pnpm add @workleap/honeycomb @opentelemetry/api
#
Register instrumentation
Then, update the application bootstrapping code to register Honeycomb instrumentation using the
import { registerHoneycombInstrumentation, HoneycombInstrumentationProvider, createTelemetryContext } from "@workleap/honeycomb/react";
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { App } from "./App.tsx";
const client = registerHoneycombInstrumentation("sample", "my-app", [/.+/g,], {
proxy: "https://sample-proxy",
telemetryContext: createTelemetryContext()
});
const root = createRoot(document.getElementById("root")!);
root.render(
<StrictMode>
<HoneycombInstrumentationProvider client={client}>
<App />
</HoneycombInstrumentationProvider>
</StrictMode>
);
Avoid using /.+/g,
in production, as it could expose customer data to third parties. Instead, ensure you specify values that accurately matches your application's backend URLs.
We recommend using an OpenTelemetry collector with an authenticated proxy over an ingestion API key, as API keys can expose Workleap to potential attacks.
#
Set custom user attributes
Most applications need to set custom attributes about the current user environment on all traces. To help with that,
import { useHoneycombInstrumentationClient } from "@workleap/honeycomb/react";
const client = useHoneycombInstrumentationClient();
client.setGlobalSpanAttributes({
"app.user_id": "123"
});
Now, every trace recorded after the execution of setGlobalSpanAttributes
will include the custom attribute app.user_id
:
#
Integrate with LogRocket
Starting with version 7.0
, attaching LogRocket session replays to Honeycomb traces requires providing a LogRocketInstrumentationClient
to the registration function:
import { registerHoneycombInstrumentation, HoneycombInstrumentationProvider, createTelemetryContext } from "@workleap/honeycomb/react";
import { registerLogRocketInstrumentation } from "@workleap/logrocket/react";
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { App } from "./App.tsx";
const logRocketInstrumentationClient = registerLogRocketInstrumentation("app-id");
const honeycombInstrumentationClient = registerHoneycombInstrumentation("sample", "my-app", [/.+/g,], {
proxy: "https://sample-proxy",
telemetryContext: createTelemetryContext(),
logRocketInstrumentationClient
});
const root = createRoot(document.getElementById("root")!);
root.render(
<StrictMode>
<HoneycombInstrumentationProvider client={client}>
<App />
</HoneycombInstrumentationProvider>
</StrictMode>
);
#
Custom traces
Applications are expected to use the OpenTelemetry API to send custom traces to Honeycomb:
import { useEffect } from "react";
import { trace } from "@opentelemetry/api";
const tracer = trace.getTracer("sample");
export function Page() {
useEffect(() => {
// OK, this is a pretty bad example.
const span = tracer.startSpan("sample-span");
span.end();
}, []);
return (
<div>Hello from a page!</div>
);
}
#
Try it 🚀
Start the application in a development environment using the dev
script. Render a page, then navigate to your Honeycomb instance. Go to the "Query" page and type name = HTTP GET
into the "Where" input. Run the query, select the "Traces" tab at the bottom of the page and view the detail of a trace. You should view information about the request.
#
Troubleshoot issues
If you are experiencing issues with this guide:
- Set the
verbose predefined option totrue
. - Open the DevTools console. Look for logs starting with
[honeycomb]
. - You should also see a log entry for every Honeycomb traces.
honeycombio/opentelemetry-web: Honeycomb link: https://ui.honeycomb.io/...
- Refer to the sample on GitHub.
#
Reference
#
registerHoneycombInstrumentation
Initializes an instance of Honeycomb Web SDK with Workleap's default settings.
const client = registerHoneycombInstrumentation(namespace, serviceName, apiServiceUrls: [string | Regex], options?: {
proxy?,
apiKey?,
instrumentations?,
spanProcessors?,
fetchInstrumentation?,
documentLoadInstrumentation?,
xmlHttpRequestInstrumentation?,
userInteractionInstrumentation?,
telemetryContext?,
logRocketInstrumentationClient?,
verbose?,
loggers?,
transformers?
})
#
Parameters
namespace
: The service namespace. Will be added to traces as aservice.namespace
custom attribute.serviceName
: Honeycomb application service name.apiServiceUrls
: ARegExp
orstring
that matches the URLs of the application's backend services. If unsure, start with the temporary regex/.+/g,
to match all URLs.options
: An optional object literal of options:proxy
: Set the URL to an OpenTelemetry collector proxy. Eitherproxy
orapiKey
option must be provided.apiKey
: Set an Honeycomb ingestion API key. Eitherproxy
orapiKey
option must be provided.instrumentations
: Append the provided instrumentation instances to the configuration.spanProcessors
: Append the provided span processor instances to the configuration.fetchInstrumentation
: Replace the default @opentelemetry/instrumentation-fetch options by providing a function that returns an object literal with the desired options. This function will receive an object literal containing the default options, which you can either extend or replace.documentLoadInstrumentation
: Replace the default @opentelemetry/instrumentation-document-load options by providing a function that returns an object literal with the desired options. This function will receive an object literal containing the default options, which you can either extend or replace.xmlHttpRequestInstrumentation
: By default, @opentelemetry/instrumentation-xml-http-request is disabled. To enable this instrumentation, provide a function that returns an object literal with the desired options. This function will receive an object literal of default options, which you can extend or replace as needed.userInteractionInstrumentation
: By default, @opentelemetryinstrumentation-user-interaction is disabled. To enable this instrumentation, provide a function that returns an object literal with the desired options. This function will receive an object literal of default options, which you can extend or replace as needed.telemetryContext
: ATelemetryContext
instance containing the telemetry correlation ids to attach to Honeycomb traces. Starting with version7.0
, if no telemetry context is provided, the correlation ids will not be attached to Honeycomb traces.logRocketInstrumentationClient
: ALogRocketInstrumentationClient
instance to integrate Honeycomb traces with LogRocket session replays. Starting with version7.0
, if no LogRocket instrumentation client is provided, the Honeycomb traces will not integrate with LogRocket session replays.verbose
: If nologgers
are configured, verbose mode will automatically send logs to the console. In some cases, enabling verbose mode also produces additional debug information.loggers
: An array of logger instances that will output messages.transformers
: An array of transformer functions to update the default LogRocket options.
#
Returns
A
#
Default instrumentation
The registerHoneycombInstrumentation
function registers the following OpenTelemetry instrumentations by default:
For more details, refer to the registerHoneycombInstrumentation.ts file on GitHub.
#
Use a proxy
import { registerHoneycombInstrumentation } from "@workleap/honeycomb/react";
const client = registerHoneycombInstrumentation("sample", "my-app", [/.+/g,], {
proxy: "https://sample-proxy"
});
When a proxy
option is provided, the current session credentials are automatically sent with the OTel trace requests.
#
Use an API key
Prefer using an OpenTelemetry collector with an authenticated proxy over an ingestion API key, as API keys can expose Workleap to potential attacks.
import { registerHoneycombInstrumentation } from "@workleap/honeycomb/react";
const client = registerHoneycombInstrumentation("sample", "my-app", [/.+/g,], {
apiKey: "123"
});
#
Use custom instrumentations
import { registerHoneycombInstrumentation } from "@workleap/honeycomb/react";
import { LongTaskInstrumentation } from "@opentelemetry/instrumentation-long-task";
const client = registerHoneycombInstrumentation("sample", "my-app", [/.+/g,], {
proxy: "https://sample-proxy",
instrumentations: [
new LongTaskInstrumentation()
]
});
#
Use custom span processors
export class CustomSpanProcessor implements SpanProcessor {
onStart(span: Span): void {
span.setAttributes({
"processor.name": "CustomSpanPressor"
});
}
onEnd(): void {}
forceFlush() {
return Promise.resolve();
}
shutdown() {
return Promise.resolve();
}
}
import { registerHoneycombInstrumentation } from "@workleap/honeycomb/react";
import { CustomSpanProcessor } from "./CustomSpanProcessor.ts";
const client = registerHoneycombInstrumentation("sample", "my-app", [/.+/g,], {
proxy: "https://sample-proxy",
spanProcessors: [
new CustomSpanProcessor()
]
});
#
Customize fetchInstrumentation
import { registerHoneycombInstrumentation } from "@workleap/honeycomb/react";
const client = registerHoneycombInstrumentation("sample", "my-app", [/.+/g,], {
proxy: "https://sample-proxy",
fetchInstrumentation: (defaultOptions) => {
return {
...defaultOptions,
ignoreNetworkEvents: false
}
}
});
To disable @opentelemetry/instrumentation-fetch, set the option to false
.
import { registerHoneycombInstrumentation } from "@workleap/honeycomb/react";
const client = registerHoneycombInstrumentation("sample", "my-app", [/.+/g,], {
proxy: "https://sample-proxy",
fetchInstrumentation: false
});
#
Customize documentLoadInstrumentation
import { registerHoneycombInstrumentation } from "@workleap/honeycomb/react";
const client = registerHoneycombInstrumentation("sample", "my-app", [/.+/g,], {
proxy: "https://sample-proxy",
documentLoadInstrumentation: (defaultOptions) => {
return {
...defaultOptions,
ignoreNetworkEvents: false
}
}
});
To disable @opentelemetry/instrumentation-document-load, set the option to false
.
import { registerHoneycombInstrumentation } from "@workleap/honeycomb/react";
const client = registerHoneycombInstrumentation("sample", "my-app", [/.+/g,], {
proxy: "https://sample-proxy",
documentLoadInstrumentation: (defaultOptions) => {
return {
...defaultOptions,
ignoreNetworkEvents: false
}
}
});
#
Customize xmlHttpRequestInstrumentation
import { registerHoneycombInstrumentation } from "@workleap/honeycomb/react";
const client = registerHoneycombInstrumentation("sample", "my-app", [/.+/g,], {
proxy: "https://sample-proxy",
xmlHttpRequestInstrumentation: (defaultOptions) => {
return {
...defaultOptions,
ignoreNetworkEvents: false
}
}
});
Or set the option to true
to enable @opentelemetry/instrumentation-xml-http-request with the default options.
import { registerHoneycombInstrumentation } from "@workleap/honeycomb/react";
const client = registerHoneycombInstrumentation("sample", "my-app", [/.+/g,], {
proxy: "https://sample-proxy",
xmlHttpRequestInstrumentation: true
});
#
Customize userInteractionInstrumentation
import { registerHoneycombInstrumentation } from "@workleap/honeycomb/react";
const client = registerHoneycombInstrumentation("sample", "my-app", [/.+/g,], {
proxy: "https://sample-proxy",
userInteractionInstrumentation: (defaultOptions) => {
return {
...defaultOptions,
eventNames: ["submit", "click", "keypress"]
}
}
});
Or set the option to true
to enable @opentelemetryinstrumentation-user-interaction with the default options.
import { registerHoneycombInstrumentation } from "@workleap/honeycomb/react";
const client = registerHoneycombInstrumentation("sample", "my-app", [/.+/g,], {
proxy: "https://sample-proxy",
userInteractionInstrumentation: true
});
#
Use a telemetry context
import { registerHoneycombInstrumentation, createTelemetryContext } from "@workleap/honeycomb/react";
const telemetryContext = createTelemetryContext();
const client = registerHoneycombInstrumentation("sample", "my-app", [/.+/g,], {
proxy: "https://sample-proxy"
});
#
Integrate with LogRocket
import { registerHoneycombInstrumentation, createTelemetryContext } from "@workleap/honeycomb/react";
import { registerLogRocketInstrumentation } from "@workleap/logrocket/react";
const logRocketInstrumentationClient = registerLogRocketInstrumentation("my-app-id");
const honeycombClient = registerHoneycombInstrumentation("sample", "my-app", [/.+/g,], {
proxy: "https://sample-proxy",
logRocketInstrumentationClient
});
#
Verbose mode
import { registerHoneycombInstrumentation } from "@workleap/honeycomb/react";
const client = registerHoneycombInstrumentation("sample", "my-app", [/.+/g,], {
proxy: "https://sample-proxy",
verbose: true
});
#
Use loggers
import { registerHoneycombInstrumentation } from "@workleap/honeycomb/react";
import { LogRocketLogger } from "@workleap/logrocket";
import { BrowserConsoleLogger, LogLevel } from "@workleap/logging";
const client = registerHoneycombInstrumentation("sample", "my-app", [/.+/g,], {
loggers: [new BrowserConsoleLogger(), new LogRocketLogger({ logLevel: LogLevel.information })]
});
#
Use transformer functions
The predefined options are useful to quickly customize the default configuration of the Honeycomb Web SDK, but only covers a subset of the options. If you need full control over the configuration, you can provide configuration transformer functions through the transformers
option of the registerHoneycombInstrumentation
function. Remember, no locked in ❤️✌️.
To view the default configuration of
import { registerHoneycombInstrumentation, type HoneycombSdkOptionsTransformer } from "@workleap/honeycomb/react";
const skipOptionsValidationTransformer: HoneycombSdkOptionsTransformer = config => {
config.skipOptionsValidation = true;
return config;
};
const client = registerHoneycombInstrumentation("sample", "my-app", [/.+/g,], {
proxy: "https://sample-proxy",
transformers: [skipOptionsValidationTransformer]
});
Generic transformers can use the context
argument to gather additional information about their execution context:
import type { HoneycombSdkOptionsTransformer } from "@workleap/honeycomb/react";
const debugTransformer: HoneycombSdkOptionsTransformer = (config, context) => {
if (context.verbose) {
config.debug = true;
context.logger.debug("Debug mode has been activated.");
}
return config;
}
#
HoneycombInstrumentationClient
A lightweight client providing access to Honeycomb instrumentation utilities.
const client = new HoneycombInstrumentationClient(globalAttributeSpanProcessor?, fetchRequestPipeline?)
#
Parameters
globalAttributeSpanProcessor
: A SpanProcessor to attach global attributes to all traces.fetchRequestPipeline
: A pipeline instance to dynamically add @opentelemetry/instrumentation-fetch request hooks.
#
Methods
setGlobalSpanAttribute(key, value)
: Set a single global attribute to be included in all traces.setGlobalSpanAttributes(attributes)
: Set a single or multiple global attributes to be included in all traces.registerFetchRequestHook(hook)
: Dynamically registers fetch request hook at the end of the pipeline.registerFetchRequestHookAtStart(hook)
: Dynamically registers a fetch request hook at the start of the pipeline.
#
Register global attributes
import { useHoneycombInstrumentationClient } from "@workleap/honeycomb/react";
const client = useHoneycombInstrumentationClient();
client.setGlobalSpanAttributes({
"app.user_id": "123"
});
#
Register a dynamic request hook
import { useHoneycombInstrumentationClient } from "@workleap/honeycomb/react";
const client = useHoneycombInstrumentationClient();
client.registerFetchRequestHook((requestSpan, request) => {
let headers: Headers;
if (request instanceof Request) {
const moduleId = request.headers.get("x-module-id");
if (moduleId) {
requestSpan.setAttribute("app.module_id", moduleId);
}
}
});
#
Register a dynamic request hook to be executed first
import { useHoneycombInstrumentationClient } from "@workleap/honeycomb/react";
const client = useHoneycombInstrumentationClient();
client.registerFetchRequestHookAtStart((requestSpan, request) => {
let headers: Headers;
if (request instanceof Request) {
const moduleId = request.headers.get("x-module-id");
if (moduleId) {
requestSpan.setAttribute("app.module_id", moduleId);
}
}
});
#
Prevent the execution of subsequent request hooks
A dynamic request hook can stop the execution of subsequent request hooks by returning true
.
import { useHoneycombInstrumentationClient } from "@workleap/honeycomb/react";
const client = useHoneycombInstrumentationClient();
client.registerFetchRequestHookAtStart((requestSpan, request) => {
let headers: Headers;
if (request instanceof Request) {
const moduleId = request.headers.get("x-module-id");
if (moduleId) {
requestSpan.setAttribute("app.module_id", moduleId);
// Indicates to not propagate the requests to the subsequent hooks.
return true;
}
}
});
#
HoneycombInstrumentationProvider
React provider to share a HoneycombInstrumentationProvider
instance with the application code.
<HoneycombInstrumentationProvider client={client}>
<App />
</HoneycombInstrumentationProvider>
#
Properties
client
: AHoneycombInstrumentationClient instance.
#
Provide a client instance
import { registerHoneycombInstrumentation, HoneycombInstrumentationProvider } from "@workleap/honeycomb/react";
import { createRoot } from "react-dom/client";
import { App } from "./App.tsx";
const client = registerHoneycombInstrumentation("sample", "my-app", [/.+/g,], {
proxy: "https://sample-proxy"
});
const root = createRoot(document.getElementById("root"));
root.render(
<HoneycombInstrumentationProvider client={client}>
<App />
</HoneycombInstrumentationProvider>
);
#
Retrieve a client instance
import { useHoneycombInstrumentationClient } from "@workleap/honeycomb/react";
const client = useHoneycombInstrumentationClient();
client.setGlobalSpanAttributes({
"app.user_id": "123"
});
#
useHoneycombInstrumentationClient
Retrieve a HoneycombInstrumentationClient
instance.
const client = useHoneycombInstrumentationClient()
#
Parameters
None
#
Returns
A
#
Usage
import { useHoneycombInstrumentationClient } from "@workleap/honeycomb/react";
const client = useHoneycombInstrumentationClient();
client.setGlobalSpanAttributes({
"app.user_id": "123"
});
#
createTelemetryContext
Creates a TelemetryContext
instance containing the telemetry correlation ids.
const telemetryContext = createTelemetryContext(options?: { identityCookieExpiration?, identityCookieDomain?, verbose?, loggers? })
#
Parameters
options
: An optional object literal of options:identityCookieExpiration
: The expiration date of thewl-identity
cookie if the cookie hasn't been already written. The default value is 365 days.identityCookieDomain
: The domain of thewl-identity
cookie if the cookie hasn't been already written. The default value is*.workleap
verbose
: If no loggers are configured, verbose mode will automatically send logs to the console. In some cases, enabling verbose mode also produces additional debug information.loggers
: An optional array ofLogger
instances.
#
Returns
A TelemetryContext
instance.
#
Create a telemetry context
import { createTelemetryContext } from "@workleap/honeycomb/react";
const context = createTelemetryContext();
#
Set a custom cookie expiration
import { createTelemetryContext } from "@workleap/honeycomb/react";
const context = createTelemetryContext({
identityCookieExpiration: new Date(Date.now() + 14 * 24 * 60 * 60 * 1000);
});
#
Set a custom cookie domain
import { createTelemetryContext } from "@workleap/honeycomb/react";
const context = createTelemetryContext({
identityCookieDomain: ".contso.com";
});
#
Verbose mode
import { createTelemetryContext } from "@workleap/honeycomb/react";
const context = createTelemetryContext({
verbose: true
});
#
Loggers
import { createTelemetryContext, LogRocketLogger } from "@workleap/honeycomb/react";
import { BrowserConsoleLogger, LogLevel } from "@workleap/logging";
const context = createTelemetryContext({
loggers: [new BrowserConsoleLogger(), new LogRocketLogger({ logLevel: LogLevel.information })]
});