# API Changelog Source: https://docs.honeycomb.io/api-changelog # Get a Signal Source: https://docs.honeycomb.io/api/anomaly-detection/get-a-signal /api/openapi-public.yaml get /1/signals/{id} Fetch a Signal by ID, including the Recipients assigned to it. # List All Signals Source: https://docs.honeycomb.io/api/anomaly-detection/list-all-signals /api/openapi-public.yaml get /1/signals List Signals in the environment associated with your API key. Signals are returned in cursor-paginated pages and can be filtered by service, dataset, kind, status, and whether they are currently anomalous. # List Historical Anomalies Source: https://docs.honeycomb.io/api/anomaly-detection/list-historical-anomalies /api/openapi-public.yaml get /1/signals/{id}/historical_anomalies List anomalies that a Signal has resolved within a bounded time window. Anomalies are returned in cursor-paginated pages, most recent first. `start_time` and `end_time` are required and must span no more than 30 days. # Update a Signal Source: https://docs.honeycomb.io/api/anomaly-detection/update-a-signal /api/openapi-public.yaml put /1/signals/{id} Update a Signal by ID. All fields in the body are optional; only the fields you supply are applied. - `enabled`: Toggles the Signal on or off. Re-enabling a Signal that has already trained puts it back into `normal`; otherwise it returns to `onboarding`. - `sensitivity`: Sets how far a measurement must deviate from the trained normal band before the Signal fires. Not applicable to `presence` Signals, and cannot be set on a Signal that has not yet trained. - `recipients`: Replaces the Signal's Recipient set. An empty array clears all Recipients. Modifying Recipients requires the **Manage Recipients** permission in addition to **Manage Signals**. # List Authorizations Source: https://docs.honeycomb.io/api/auth/list-authorizations /api/openapi-public.yaml get /1/auth Returns metadata about the API Key used to call the API. Note: a Honeycomb Classic API key will return an empty string for both of the `environment` values. # List Authorizations V2 Source: https://docs.honeycomb.io/api/auth/list-authorizations-v2 /api/openapi-public.yaml get /2/auth Returns metadata about the Management API Key used to call the API. # Authentication Source: https://docs.honeycomb.io/api/authentication Authenticate Honeycomb API requests with API keys. Find out which key type each endpoint requires. All Honeycomb API requests require an API key. The type of key you use depends on what you're doing. ## Honeycomb Resource Hierarchy Honeycomb organizes resources hierarchically: Teams contain Environments, and Environments contain Datasets and other resources. API keys operate at different levels of this hierarchy, which determines what they can access. * **Environment-level keys** access a single Environment and its Datasets. These include Ingest and Configuration Keys. * **Team-level keys** access all Environments and Team settings. These are Management Keys. If you use Honeycomb Classic, your account doesn't have Environments. Classic API keys operate at the Team level and access all your Classic Datasets directly. ## API Key Format On creation, every API key is assigned a Key ID, which is a label used to identify the Key in the Honeycomb UI. Key IDs include a prefix that identifies the key type: * `hc[x]ik_`: Ingest Key * `hc[x]lk_`: Configuration Key * `hc[x]mk_`: Management Key The character shown as `[x]` varies and is assigned at key creation. For Ingest and Management Keys, you will also have a Secret, which is a separate credential that combines with the Key ID to form the value you pass in API requests. Configuration Keys have a Token. You can retrieve the Token from the Honeycomb UI at any time. ## API Key Types Honeycomb has three types of API keys, each designed for a specific purpose and scope. | Key Type | Scope | Use | Header | Via the UI | Via the API | | ------------- | ----------- | ---------------------------- | ----------------------- | ----------------------------- | ------------------------------------ | | Ingest | Environment | Send telemetry data | `X-Honeycomb-Team` | **Ingest Key** | `data.id` + `data.attributes.secret` | | Configuration | Environment | Manage Environment resources | `X-Honeycomb-Team` | **Token** | `data.attributes.secret` | | Management | Team | Manage keys and Environments | `Authorization: Bearer` | **Key ID** + `:` + **Secret** | N/A | When creating an Ingest Key through the UI, Honeycomb returns the complete key value. You only need to construct it from `data.id` and `data.attributes.secret` when using the [Create an API Key endpoint](/api/key-management/create-an-api-key). ### Ingest Keys Ingest Keys send data to Honeycomb. Pass an Ingest Key in the `X-Honeycomb-Team` header. The key value is the **Key ID** and **Secret** concatenated with no separator. If you created your key through the UI, Honeycomb provides the complete value as the **Ingest Key**. If you created it via the API, concatenate `data.id` and `data.attributes.secret` with no separator. ```http theme={} X-Honeycomb-Team: hc[x]ik_1234567890123456789012345612345678901234567890123456789012 ``` Ingest Keys can optionally be granted permission to create new Datasets automatically. If you created your Ingest Key through the UI, store the complete **Ingest Key** securely; Honeycomb displays the concatenated value only when you create the key. If you created your Ingest Key via the API, store `data.attributes.secret` securely; Honeycomb returns it only upon creation. ### Configuration Keys Configuration Keys read and manage resources within a specific Environment, such as Datasets, queries, Boards, Triggers, and SLOs. Pass the **Token** in the `X-Honeycomb-Team` header. If you created your Configuration Key via the API, use `data.attributes.secret`; this is the same value as the **Token** in the UI. ```http theme={} X-Honeycomb-Team: 1234567890123456789012 ``` Each Configuration Key has a set of permissions that control which actions it can perform. You assign these permissions when you create or update the key. ### Management Keys Management Keys handle Team-level operations, including managing Environments and API keys. Pass a Management Key as a Bearer token in the `Authorization` header. Construct the key value by joining the **Key ID** and **Secret** with a colon (`:`). Management Keys can only be created through the UI. ```http theme={} Authorization: Bearer hc[x]mk_12345678901234567890123456:12345678901234567890123456789012 ``` Store the **Secret** securely when you create the key; Honeycomb returns it only upon creation. ## Validating a Key Use the [Auth endpoint](/api/auth/list-authorizations) to confirm which key you are using, check its permissions, and identify the Team and Environment it belongs to. If you use Honeycomb Classic, the `environment.name` and `environment.slug` fields in the [Auth endpoint](/api/auth) response will return empty strings. This is expected behavior. ## Managing API Keys To create, update, or revoke keys, navigate to **Account** > **Team Settings** > **API Keys** in Honeycomb, or use the [Key Management API](/api/key-management). For best practices, including rotation and least-privilege recommendations, see [API Key Best Practices](/get-started/best-practices/api-keys/). # Create a Board Source: https://docs.honeycomb.io/api/boards/create-a-board /api/openapi-public.yaml post /1/boards Create a Board comprised of one or more Panels (Query, SLO, or Text). **Note**: Each board is limited to a maximum of 5 preset filters. # Create a Board View Source: https://docs.honeycomb.io/api/boards/create-a-board-view /api/openapi-public.yaml post /1/boards/{boardId}/views Create a new view for a board with the specified filters. **Note**: Each board is limited to a maximum of 50 views. Attempting to create more than 50 views will result in an error. # Delete a Board Source: https://docs.honeycomb.io/api/boards/delete-a-board /api/openapi-public.yaml delete /1/boards/{boardId} Delete a public Board by specifying its ID. # Delete a Board View Source: https://docs.honeycomb.io/api/boards/delete-a-board-view /api/openapi-public.yaml delete /1/boards/{boardId}/views/{viewId} Delete a Board View by specifying its ID. # Get a Board Source: https://docs.honeycomb.io/api/boards/get-a-board /api/openapi-public.yaml get /1/boards/{boardId} Get a single Board by ID. # Get a Board View Source: https://docs.honeycomb.io/api/boards/get-a-board-view /api/openapi-public.yaml get /1/boards/{boardId}/views/{viewId} Retrieve a single Board View by ID. # List All Boards Source: https://docs.honeycomb.io/api/boards/list-all-boards /api/openapi-public.yaml get /1/boards Retrieves a list of all non-secret Boards within an environment. **Note**: For Honeycomb Classic users, all boards within Classic will be returned. # List Board Views Source: https://docs.honeycomb.io/api/boards/list-board-views /api/openapi-public.yaml get /1/boards/{boardId}/views Retrieve a list of all views for a board. **Note**: Each board is limited to a maximum of 50 views. # Update a Board Source: https://docs.honeycomb.io/api/boards/update-a-board /api/openapi-public.yaml put /1/boards/{boardId} Update a Board by specifying its ID and full details. **Note**: Queries can be added to, removed from, and re-ordered by updating the board itself. It is not possible to reference individual queries via the API. **Note**: Each board is limited to a maximum of 5 preset filters. Attempting to update a board with more than 5 preset filters will result in an error. # Update a Board View Source: https://docs.honeycomb.io/api/boards/update-a-board-view /api/openapi-public.yaml put /1/boards/{boardId}/views/{viewId} Update a Board View by specifying its ID and full details. # Create a Burn Alert Source: https://docs.honeycomb.io/api/burn-alerts/create-a-burn-alert /api/openapi-public.yaml post /1/burn_alerts/{datasetSlug} Create a Burn Alert against a specified SLO. # Delete a Burn Alert Source: https://docs.honeycomb.io/api/burn-alerts/delete-a-burn-alert /api/openapi-public.yaml delete /1/burn_alerts/{datasetSlug}/{burnAlertId} Delete a Burn Alert by specifying its ID. # Get a Burn Alert Source: https://docs.honeycomb.io/api/burn-alerts/get-a-burn-alert /api/openapi-public.yaml get /1/burn_alerts/{datasetSlug}/{burnAlertId} Get a single Burn Alert by ID. # List All Burn Alerts for an SLO Source: https://docs.honeycomb.io/api/burn-alerts/list-all-burn-alerts-for-an-slo /api/openapi-public.yaml get /1/burn_alerts/{datasetSlug} Get all burn alerts associated with the SLO specified in the `slo_id` query param. It is not currently possible to retrieve all burn alerts for a dataset, environment, or team. # Update a Burn Alert Source: https://docs.honeycomb.io/api/burn-alerts/update-a-burn-alert /api/openapi-public.yaml put /1/burn_alerts/{datasetSlug}/{burnAlertId} Update a Burn Alert by specifying its ID and full details. # Create a Calculated Field Source: https://docs.honeycomb.io/api/calculated-fields/create-a-calculated-field /api/openapi-public.yaml post /1/derived_columns/{datasetSlug} Create a Calculated Field (also called a Derived Column). Calculated Fields allow you to run queries based on the value of an expression that is calculated from the fields in an event. # Delete a Calculated Field Source: https://docs.honeycomb.io/api/calculated-fields/delete-a-calculated-field /api/openapi-public.yaml delete /1/derived_columns/{datasetSlug}/{derivedColumnId} Delete a Calculated Field (also called a Derived Column). **Note**: A Calculated Field used by a SLO, Trigger, or Board cannot be deleted without removing or modifying the SLO, Trigger, or Board first. # Get a Calculated Field Source: https://docs.honeycomb.io/api/calculated-fields/get-a-calculated-field /api/openapi-public.yaml get /1/derived_columns/{datasetSlug}/{derivedColumnId} # List all Calculated Fields Source: https://docs.honeycomb.io/api/calculated-fields/list-all-calculated-fields /api/openapi-public.yaml get /1/derived_columns/{datasetSlug} Get all the Calculated Fields (also called Derived Columns) in a dataset or environment. With the `?alias=X` query parameter, can return a single Calculated Field by its `alias`. # Update a Calculated Field Source: https://docs.honeycomb.io/api/calculated-fields/update-a-calculated-field /api/openapi-public.yaml put /1/derived_columns/{datasetSlug}/{derivedColumnId} Update a Calculated Field (also called a Derived Column). # Create a Column Source: https://docs.honeycomb.io/api/columns/create-a-column /api/openapi-public.yaml post /1/columns/{datasetSlug} Create a column by providing corresponding details for that type. # Delete a Column Source: https://docs.honeycomb.io/api/columns/delete-a-column /api/openapi-public.yaml delete /1/columns/{datasetSlug}/{columnId} Delete a column. **Note**: Deleted columns are no longer queryable, but data in existing permalinks (query results and trace views) will remain stored and available at those links. # Get a Column Source: https://docs.honeycomb.io/api/columns/get-a-column /api/openapi-public.yaml get /1/columns/{datasetSlug}/{columnId} # List all Columns Source: https://docs.honeycomb.io/api/columns/list-all-columns /api/openapi-public.yaml get /1/columns/{datasetSlug} Get all the Columns in a dataset or environment. Use `__all__` as the dataset slug to retrieve all Columns across all datasets in the environment (not available for classic environments). # Update a Column Source: https://docs.honeycomb.io/api/columns/update-a-column /api/openapi-public.yaml put /1/columns/{datasetSlug}/{columnId} Update a column # Get all Dataset Definitions Source: https://docs.honeycomb.io/api/dataset-definitions/get-all-dataset-definitions /api/openapi-public.yaml get /1/dataset_definitions/{datasetSlug} Get all definitions for a Dataset. The response returns an object with a Dataset Definition for each set Dataset Definition type. # Set or Update Dataset Definitions Source: https://docs.honeycomb.io/api/dataset-definitions/set-or-update-dataset-definitions /api/openapi-public.yaml patch /1/dataset_definitions/{datasetSlug} Set or update one or more definitions for a Dataset. **Note**: While the PATCH payload can include the `column_type`, Honeycomb does not use this field when updating Dataset Definitions. # Create a Dataset Source: https://docs.honeycomb.io/api/datasets/create-a-dataset /api/openapi-public.yaml post /1/datasets Create a Dataset in the environment associated with your API key. If a Dataset already exists by that name (or slug), then the existing dataset will be returned. # Delete a Dataset Source: https://docs.honeycomb.io/api/datasets/delete-a-dataset /api/openapi-public.yaml delete /1/datasets/{datasetSlug} Deletes the Dataset. This is an irreversible operation. It may take several minutes for the deletion process to complete. **WARNING**: This endpoint will allow anyone with an API key that has the manage dataset permission to delete any dataset in the environment (or any dataset in the whole team for Classic customers). Datasets with Deletion Protection enabled cannot be deleted. To delete a Dataset with Deletion Protection enabled, first disable Deletion Protection by updating the Dataset with `settings.delete_protected = false`. # Get a Dataset Source: https://docs.honeycomb.io/api/datasets/get-a-dataset /api/openapi-public.yaml get /1/datasets/{datasetSlug} Get a single Dataset by slug. # List All Datasets Source: https://docs.honeycomb.io/api/datasets/list-all-datasets /api/openapi-public.yaml get /1/datasets Lists all Datasets for an environment. **Note**: For Honeycomb Classic users, all datasets in Classic are returned. # Update a Dataset Source: https://docs.honeycomb.io/api/datasets/update-a-dataset /api/openapi-public.yaml put /1/datasets/{datasetSlug} Update a Dataset's settings. # Create an Environment Source: https://docs.honeycomb.io/api/environments/create-an-environment /api/openapi-public.yaml post /2/teams/{teamSlug}/environments # Delete an Environment Source: https://docs.honeycomb.io/api/environments/delete-an-environment /api/openapi-public.yaml delete /2/teams/{teamSlug}/environments/{ID} This deletes and immediately deactivates the Environment. This is an irreversible operation. Environments with Deletion Protection enabled cannot be deleted. To delete an Environment with Deletion Protection enabled, first disable Deletion Protection by updating the Environment with `settings.delete_protected = false`. # Get an Environment Source: https://docs.honeycomb.io/api/environments/get-an-environment /api/openapi-public.yaml get /2/teams/{teamSlug}/environments/{ID} # List all Environments Source: https://docs.honeycomb.io/api/environments/list-all-environments /api/openapi-public.yaml get /2/teams/{teamSlug}/environments # Update an Environment Source: https://docs.honeycomb.io/api/environments/update-an-environment /api/openapi-public.yaml patch /2/teams/{teamSlug}/environments/{ID} # Errors Source: https://docs.honeycomb.io/api/errors Handle Honeycomb API errors using standard HTTP status codes and structured error responses. The Honeycomb API uses standard HTTP status codes and returns structured error responses that describe what went wrong. The response format depends on which API version the endpoint uses. ## Error Response Formats Honeycomb uses two error formats depending on the API version. V1 endpoints return errors in RFC7807 Problem Detail format: ```json theme={} { "status": 404, "type": "https://api.honeycomb.io/problems/not-found", "title": "The requested resource cannot be found.", "error": "Dataset not found", "detail": "Dataset not found" } ``` | Field | Description | | -------- | ----------------------------------------------------- | | `status` | HTTP status code. | | `type` | URI that identifies the error type. | | `title` | Human-readable summary of the error type. | | `error` | Description of the error. | | `detail` | Additional detail about this specific error instance. | Some V1 endpoints return a simpler legacy format with only an `error` field: ```json theme={} { "error": "unknown API key - check your credentials" } ``` V2 endpoints return errors in JSON:API format: ```json theme={} { "errors": [ { "id": "06dcdd6508ca822f0e7e2bb4121c1f52", "code": "invalid", "title": "request body could not be parsed", "detail": "invalid gzip data" } ] } ``` | Field | Description | | -------- | ----------------------------------------------------- | | `id` | A unique identifier for this error instance. | | `code` | A machine-readable error code. | | `title` | A human-readable summary of the error. | | `detail` | Additional detail about this specific error instance. | ## HTTP Status Codes | Status | Name | Description | | ------ | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | | `400` | Bad Request | The request body could not be parsed or is invalid. Check the request format and content type. | | `401` | Unauthorized | The API key is missing or invalid. Check your credentials. | | `403` | Forbidden | The API key does not have permission for this operation. Check the key's permissions or scopes. | | `404` | Not Found | The requested resource does not exist. Check the resource identifier in your request. | | `409` | Conflict | The request conflicts with the current state of the resource, such as a duplicate name. | | `413` | Payload Too Large | The request body exceeds the maximum allowed size of 100,000 bytes. | | `415` | Unsupported Media Type | The `Content-Type` header does not match what the endpoint expects. Check the [content type](/api/introduction#content-types) for this endpoint. | | `422` | Validation Failed | The request was valid but contained invalid values. The response body includes details about which fields failed validation. | | `429` | Rate Limited | You have exceeded the rate limit. For details, visit [Rate Limits](/api/rate-limit). | | `500` | Internal Server Error | An unexpected error occurred on Honeycomb's side. If this persists, contact [Honeycomb Support](https://support.honeycomb.io/). | ## Validation Errors `422` responses include a `type_detail` array that identifies which fields failed and why: ```json theme={} { "status": 422, "type": "https://api.honeycomb.io/problems/validation-failed", "title": "The provided input is invalid.", "error": "The provided input is invalid.", "type_detail": [ { "field": "type", "code": "invalid", "description": "type: must be a valid value" } ] } ``` | Validation code | Meaning | | ---------------- | ---------------------------------------------- | | `invalid` | The field value is not acceptable. | | `missing` | A required field was not provided. | | `incorrect_type` | The field value is the wrong data type. | | `already_exists` | The value conflicts with an existing resource. | # Create an Event Source: https://docs.honeycomb.io/api/events/create-an-event /api/openapi-public.yaml post /1/events/{datasetSlug} Using this endpoint for anything more than testing is highly discouraged. Sending events in batches will be much more efficient and should be preferred if at all possible. # Create Events Source: https://docs.honeycomb.io/api/events/create-events /api/openapi-public.yaml post /1/batch/{datasetSlug} Supports batch creation of events. Dataset names are case insensitive. `POST` requests to "MyDatasET" will land in the same dataset as "mydataset". Names may contain URL-encoded spaces or other special characters, but not URL-encoded slashes. For example, "My%20Dataset" will show up in the UI as "My Dataset". The first event received for a dataset determines the casing of the displayed name. All subsequent variations in casing will use the originally specified case. # Honeycomb API Reference Source: https://docs.honeycomb.io/api/introduction Build integrations and automate workflows with the Honeycomb API. Programmatically manage datasets, queries, triggers, SLOs, environments, API keys, and more. ## Overview The Honeycomb API gives you programmatic access to manage resources, automate workflows, and integrate Honeycomb into your systems. Use it to manage datasets, queries, triggers, SLOs, environments, API keys, and more. You can download the Honeycomb OpenAPI spec to use with your own tooling. ## Base URLs Honeycomb stores your data in either a US or EU region, depending on the region you sign up in. | Data Storage Region | Base API URL | Base UI/Signup URL | | ------------------- | ------------------------------ | ----------------------------- | | US | `https://api.honeycomb.io` | `https://ui.honeycomb.io` | | EU | `https://api.eu1.honeycomb.io` | `https://ui.eu1.honeycomb.io` | Use the base URL that matches your account region for all requests. ## API Versions Honeycomb's API uses versioned path prefixes. The version appears at the start of every endpoint path. | Version | Path prefix | Used for | | ------- | ----------- | ---------------------------------------------------------- | | V1 | `/1/` | Event ingestion, queries, Datasets, and other resources | | V2 | `/2/` | Team-level management: Environments, API keys, and markers | ## Content Types The content type you use depends on the API version. | Version | Request content type | Response content type | | ------- | -------------------------- | -------------------------- | | V1 | `application/json` | `application/json` | | V2 | `application/vnd.api+json` | `application/vnd.api+json` | Set the `Content-Type` header to match the endpoint you are calling. Sending the wrong content type returns a `415 Unsupported Media Type` error. ## Support Found a discrepancy between this documentation and actual API behavior? Let us know in [Pollinators Slack](/troubleshoot/community/) or contact [Honeycomb Support](https://support.honeycomb.io/). # Create an API Key Source: https://docs.honeycomb.io/api/key-management/create-an-api-key /api/openapi-public.yaml post /2/teams/{teamSlug}/api-keys This creates an API Key, which will return the API Key components in the response. The Key ID will be found at `data.id` and the Key Secret will be found at `data.attributes.secret`. For security reasons the Key Secret will only be available during creation so make sure to save it. To use a newly-created Ingest Key it should be passed in the `X-Honeycomb-Team` header with the API Key's ID and secret concatenated (and with no separator). For example, `X-Honeycomb-Team: hcxik_1234567890123456789012345612345678901234567890123456789012` Check out our [best practices for API Keys](https://docs.honeycomb.io/get-started/best-practices/api-keys/#ingest-keys). # Delete an API Key Source: https://docs.honeycomb.io/api/key-management/delete-an-api-key /api/openapi-public.yaml delete /2/teams/{teamSlug}/api-keys/{ID} This deletes and immediately deactivates the API Key. This is an irreversible operation. # Get an API Key Source: https://docs.honeycomb.io/api/key-management/get-an-api-key /api/openapi-public.yaml get /2/teams/{teamSlug}/api-keys/{ID} Fetches an environment API Key, either a key of type `ingest` or type `configuration` based on the ID given. # List all API Keys Source: https://docs.honeycomb.io/api/key-management/list-all-api-keys /api/openapi-public.yaml get /2/teams/{teamSlug}/api-keys List all API Keys for a Team. # Update an API Key Source: https://docs.honeycomb.io/api/key-management/update-an-api-key /api/openapi-public.yaml patch /2/teams/{teamSlug}/api-keys/{ID} Updates an API Key. The expected attributes depend on the key type: - **Ingest Keys** (prefix `hcxik_`): Support `name` and `enabled` attributes - **Configuration Keys** (prefix `hcxlk_`): Support `name`, `enabled`, and `permissions` attributes # Create Kinesis Events Source: https://docs.honeycomb.io/api/kinesis-events/create-kinesis-events /api/openapi-public.yaml post /1/kinesis_events/{datasetSlug} This endpoint processes events and metrics coming from AWS through Kinesis Firehose. # Create a Marker Setting Source: https://docs.honeycomb.io/api/marker-settings/create-a-marker-setting /api/openapi-public.yaml post /1/marker_settings/{datasetSlug} # Delete a Marker Setting Source: https://docs.honeycomb.io/api/marker-settings/delete-a-marker-setting /api/openapi-public.yaml delete /1/marker_settings/{datasetSlug}/{markerSettingId} # Get a Marker Setting Source: https://docs.honeycomb.io/api/marker-settings/get-a-marker-setting /api/openapi-public.yaml get /1/marker_settings/{datasetSlug} # Update a Marker Setting Source: https://docs.honeycomb.io/api/marker-settings/update-a-marker-setting /api/openapi-public.yaml put /1/marker_settings/{datasetSlug}/{markerSettingId} A marker setting's `type` may not be changed after creation. # Create a Marker Source: https://docs.honeycomb.io/api/markers/create-a-marker /api/openapi-public.yaml post /1/markers/{datasetSlug} Create a Marker in the specified dataset. To create an environment marker, use the `__all__` keyword and an API key associated with the desired environment. # Delete a Marker Source: https://docs.honeycomb.io/api/markers/delete-a-marker /api/openapi-public.yaml delete /1/markers/{datasetSlug}/{markerId} # List All Markers Source: https://docs.honeycomb.io/api/markers/list-all-markers /api/openapi-public.yaml get /1/markers/{datasetSlug} Lists all Markers for a dataset. # Update a Marker Source: https://docs.honeycomb.io/api/markers/update-a-marker /api/openapi-public.yaml put /1/markers/{datasetSlug}/{markerId} Update a Marker in the specified dataset. To update an environment marker, use the `__all__` keyword and an API key associated with the desired environment. # Pagination Source: https://docs.honeycomb.io/api/pagination Navigate paginated Honeycomb API responses using cursor-based pagination. V2 endpoints that return lists use cursor-based pagination. This approach is more reliable than offset pagination for large or frequently changing datasets, since a cursor tracks your exact position in the result set. ## Parameters Include these query parameters to page through results: | Parameter | Description | | ------------- | ----------------------------------------------------------------------------------------- | | `page[size]` | Number of results per page. Default: `20`. Maximum: `100`. | | `page[after]` | Cursor pointing to the start of the next page. Omit this parameter on your first request. | ## How It Works When a response includes more results than fit on a single page, the response includes a `links.next` value containing a cursor. Pass the cursor from that value as `page[after]` in your next request. 1. Make your first request: ``` GET /2/teams/{teamSlug}/api-keys?page[size]=20 ``` 2. Check the response for `links.next`: ```json theme={} { "links": { "next": "/2/teams/my-team/api-keys?page[after]=eyxJjcmAVhdGVkX&page[size]=20" } } ``` 3. Pass the cursor from `links.next` as `page[after]` in your next request: ``` GET /2/teams/{teamSlug}/api-keys?page[after]=eyxJjcmAVhdGVkX&page[size]=20 ``` 4. Repeat until `links.next` is `null`, which indicates that you have reached the last page. ## Working with Cursors * Cursors are opaque strings. Treat them as values to pass through, not as values to parse or construct. * Cursors are not guaranteed to be stable across sessions. Retrieve a fresh cursor for each pagination sequence. ## Paginated Endpoints The following V2 endpoints support pagination: * [Get Map Dependencies](/api/service-maps/get-map-dependencies) * [List all API Keys](/api/key-management/list-all-api-keys) * [List all Environments](/api/environments/list-all-environments) # Permissions Source: https://docs.honeycomb.io/api/permissions Reference for required API key types and permission scopes for each Honeycomb API endpoint group This page is a temporary reference while per-endpoint permission requirements are added to the individual endpoint pages. It will be removed once that work is complete. Each Honeycomb API endpoint requires a specific key type and permission or scope. Use this page to confirm what your key needs before making a request. For help choosing a key type or setting up authentication, see [Authentication](/api/authentication). ## Configuration Key Permissions These endpoints require a **Configuration Key** passed in the `X-Honeycomb-Team` header. Each endpoint group requires a specific permission assigned to the key. | Endpoint Group | Required Permission | Notes | | --------------------------- | --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | | Auth (V1) | Any valid Ingest or Configuration Key | No specific permission required. | | Boards and Board Views | Manage Public Boards | | | Burn Alerts | Manage SLOs | | | Calculated Fields | Manage Queries and Columns | | | Columns | Manage Queries and Columns | | | Dataset Definitions | Create Datasets | | | Datasets | Create Datasets | | | Events | Send Events | Ingest Key recommended. Configuration Key with Send Events permission also works. | | Kinesis Events | Send Events | Ingest Key recommended. Configuration Key with Send Events permission also works. | | Markers and Marker Settings | Manage Markers | | | Queries | Manage Queries and Columns | | | Query Annotations | Manage Queries and Columns | | | Query Data | Manage Queries and Columns, Run Queries | Both permissions required. | | Recipients | Manage Recipients | Recipients are team-wide, not Environment-specific. A key with this permission can modify recipients across all Environments in your Team. | | Reporting | Manage SLOs | | | Service Maps | Read Service Maps | | | SLOs | Manage SLOs | | | Triggers | Manage Triggers | | ## Management Key Scopes These endpoints require a **Management Key** passed as a Bearer token in the `Authorization` header. Each endpoint requires a specific scope assigned to the key. | Endpoint Group | Required Scope | Notes | | -------------- | ------------------------------------------------------------------------------------ | ------------------------------------------ | | Auth (V2) | Any valid Management Key | | | Environments | `environments:read` (read operations), `environments:write` (create, update, delete) | | | Key Management | `api-keys:read` (read operations), `api-keys:write` (create, update, delete) | Supports both Ingest Keys and Config Keys. | # Create a Query Source: https://docs.honeycomb.io/api/queries/create-a-query /api/openapi-public.yaml post /1/queries/{datasetSlug} Create a query from a specification. DOES NOT run the query to retrieve results. # Get a Query Source: https://docs.honeycomb.io/api/queries/get-a-query /api/openapi-public.yaml get /1/queries/{datasetSlug}/{queryId} Retrieve a query by its ID. # Create a Query Annotation Source: https://docs.honeycomb.io/api/query-annotations/create-a-query-annotation /api/openapi-public.yaml post /1/query_annotations/{datasetSlug} Create a Query Annotation for the specified query ID. # Delete a Query Annotation Source: https://docs.honeycomb.io/api/query-annotations/delete-a-query-annotation /api/openapi-public.yaml delete /1/query_annotations/{datasetSlug}/{queryAnnotationId} Delete a Query Annotation by specifying its ID. # Get a Query Annotation Source: https://docs.honeycomb.io/api/query-annotations/get-a-query-annotation /api/openapi-public.yaml get /1/query_annotations/{datasetSlug}/{queryAnnotationId} Get a Query Annotation by its ID. # List Query Annotations Source: https://docs.honeycomb.io/api/query-annotations/list-query-annotations /api/openapi-public.yaml get /1/query_annotations/{datasetSlug} List all Query Annotations in the specified dataset. # Update a Query Annotation Source: https://docs.honeycomb.io/api/query-annotations/update-a-query-annotation /api/openapi-public.yaml put /1/query_annotations/{datasetSlug}/{queryAnnotationId} Update a Query Annotation by specifying its ID. The Query ID associated with the Query Annotation cannot be updated. Partial updates are not supported. # Create a Query Result Source: https://docs.honeycomb.io/api/query-data/create-a-query-result /api/openapi-public.yaml post /1/query_results/{datasetSlug} Kick off processing of a Query to then get back the Query Results. Once the Query Result has been created, the query will be run asynchronously, allowing the result data to be fetched from the GET query result endpoint. A maximum duration of 7 days of data can be queried. Any queries with a `start_time`, `end_time`, or `time_range` resulting in a duration longer than 7 days will result in a `400` error response. # Get Query Result Source: https://docs.honeycomb.io/api/query-data/get-query-result /api/openapi-public.yaml get /1/query_results/{datasetSlug}/{queryResultId} Get the Query Result details for a specific Query Result ID. This endpoint is used to fetch the results of a query that had previously been created. It is recommended to follow the Location header included in the Create Query Result output, but the URL can also be constructed manually with the <query-result-id>. Note: a query that fails to run still returns HTTP 200. Check the response body: a failed query has "complete": true with an "error" field in place of "data". # Rate Limits Source: https://docs.honeycomb.io/api/rate-limit Find out how Honeycomb API rate limits work, which response headers tell you your current usage, and how to handle 429 rate-limited errors. The Honeycomb API enforces rate limits to keep the platform stable and responsive for all users. Most API responses include headers that tell you where you stand in your current window, so you can monitor usage proactively and handle limits gracefully. ## Rate Limit Headers Most API responses include these headers: | Header | Description | | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `RateLimit` | Current window status: `limit=X, remaining=Y, reset=Z`. `X` is the maximum requests allowed in the window, `Y` is the requests remaining, and `Z` is the number of seconds until the limit resets. | | `RateLimit-Policy` | Window policy: `X;w=Y`. `X` is the maximum requests per window, and `Y` is the window size in seconds. | Example: Rate Limit Header ``` RateLimit: limit=100, remaining=80, reset=54 RateLimit-Policy: 100;w=60 ``` In this example, your rate limit policy allows 100 requests per 60-second window. In the current window, you have used 20 requests and have 80 remaining, with the window resetting in 54 seconds. Not all endpoints return `RateLimit` and `RateLimit-Policy` headers. Each endpoint's reference page indicates which headers are included in its responses. ## Handling Rate Limit Errors When you exceed the rate limit, the API returns a `429 Too Many Requests` response. Honeycomb uses two response body formats depending on the API version. V1 endpoints return an RFC7807 Problem Detail format: ```json theme={} { "status": 429, "type": "https://api.honeycomb.io/problems/rate-limited", "title": "You have exceeded your rate limit.", "error": "You have exceeded your rate limit.", "detail": "Please try again after 2025-02-01T15:23:12Z." } ``` V2 endpoints return a JSON:API format: ```json theme={} { "errors": [ { "id": "06dcdd6508ca822f0e7e2bb4121c1f52", "code": "rate-limited/may-retry", "title": "request rate limit exceeded", "detail": "Please try again after 2025-02-01T15:23:12Z." } ] } ``` Most `429` responses also include a `Retry-After` header with a timestamp indicating when you can retry: ``` Retry-After: Fri, 22 Mar 2024 18:37:53 GMT ``` The Events, Batch Events, and Query Data APIs do not include a `Retry-After` header in their `429` responses. ## Endpoint-Specific Rate Limits Some endpoints have stricter limits in addition to the general API rate limit: * **Create Query Result**: Limited to 10 requests per minute. * **Create Query Result with Relational Fields**: Limited to 1 request per minute. ## Best Practices * Check `RateLimit: remaining` in your response headers before making additional requests, especially in automated workflows or scripts. * When you receive a `429`, implement exponential backoff rather than retrying immediately. Exponential backoff reduces pressure on the API and increases the likelihood that your retry succeeds. * Use the `Retry-After` timestamp to determine when to retry, rather than guessing or using a fixed delay. # Create a Recipient Source: https://docs.honeycomb.io/api/recipients/create-a-recipient /api/openapi-public.yaml post /1/recipients Unlike many resources, Recipients are not linked to a specific Environment or Dataset. The Recipient will be created for the Team associated with your API key. The `details` fields will vary depending on the `type` of Recipient. Use the drop-down to view the specific fields for each `type` value. Before Slack Recipients can be created, the Slack OAuth flow in the Integration Center must be completed. # Delete a Recipient Source: https://docs.honeycomb.io/api/recipients/delete-a-recipient /api/openapi-public.yaml delete /1/recipients/{recipientId} Delete a recipient by specifying the recipient ID. A Recipient can only be deleted if it is NOT in use by any Triggers or Burn Alerts associated to the team. # Get a single Recipient Source: https://docs.honeycomb.io/api/recipients/get-a-single-recipient /api/openapi-public.yaml get /1/recipients/{recipientId} Retrieve a Recipient by recipient ID. # List all Recipients Source: https://docs.honeycomb.io/api/recipients/list-all-recipients /api/openapi-public.yaml get /1/recipients Retrieve all recipients for a team. # Update a Recipient Source: https://docs.honeycomb.io/api/recipients/update-a-recipient /api/openapi-public.yaml put /1/recipients/{recipientId} Update a Recipient by specifying the recipient ID and full recipient details. (Partial PUT is not supported.) Updates to the Recipient Type is not supported. For example, changing an existing Recipient from PagerDuty to Email is not allowed. **Important**: Modifying an existing recipient will change the destination of all triggers/burn alerts that use that recipient. # Get SLO History Source: https://docs.honeycomb.io/api/reporting/get-slo-history /api/openapi-public.yaml post /1/reporting/slos/historical Get a weekly breakdown of historical data for a list of SLOs for a given time range. # Create a Map Dependency Request Source: https://docs.honeycomb.io/api/service-maps/create-a-map-dependency-request /api/openapi-public.yaml post /1/maps/dependencies/requests Create a Map Dependency Request. # Get Map Dependencies Source: https://docs.honeycomb.io/api/service-maps/get-map-dependencies /api/openapi-public.yaml get /1/maps/dependencies/requests/{requestId} Get the dependencies for a previously created Map Dependencies Request. Note: This endpoint returns a single page of results and uses pagination. Even if you specified a large limit in the initial POST request, you will receive up to the page size limit per request and must use the pagination links to retrieve additional results. # Create an SLO Source: https://docs.honeycomb.io/api/slos/create-an-slo /api/openapi-public.yaml post /1/slos/{datasetSlug} Create an SLO on the provided dataset. # Delete an SLO Source: https://docs.honeycomb.io/api/slos/delete-an-slo /api/openapi-public.yaml delete /1/slos/{datasetSlug}/{sloId} Delete an SLO by specifying its ID. # Get all SLOs Source: https://docs.honeycomb.io/api/slos/get-all-slos /api/openapi-public.yaml get /1/slos/{datasetSlug} Get all SLOs for a dataset or environment (using `__all__`). This action returns any SLOs, including those applied with multiple datasets. # Get an SLO Source: https://docs.honeycomb.io/api/slos/get-an-slo /api/openapi-public.yaml get /1/slos/{datasetSlug}/{sloId} Get an SLO by ID. # Get SLO Hourly Counts History Source: https://docs.honeycomb.io/api/slos/get-slo-hourly-counts-history /api/openapi-public.yaml get /1/slos/{datasetSlug}/{sloId}/counts/history Get hourly-bucketed total and error event counts for an SLO from the persistent historical store. Use this endpoint to retrieve completed historical hours; pair with the [Get SLO Realtime Counts endpoint](https://api-docs.honeycomb.io/api/slos/getslorealtimecounts/) for the current in-progress hour. **Requirements:** - Available on the [Enterprise plan](https://www.honeycomb.io/pricing/) only. - This feature must be enabled for your team. Contact your account team to request access. **Partial buckets:** The most recent bucket may be marked `is_partial: true` if it covers the current in-progress hour. Counts for that bucket will increase until the hour completes. # Get SLO Realtime Counts Source: https://docs.honeycomb.io/api/slos/get-slo-realtime-counts /api/openapi-public.yaml get /1/slos/{datasetSlug}/{sloId}/counts Get per-minute success and failure event counts for an SLO, updated approximately once per minute from a rolling 24-hour window. This endpoint is intended for near-real-time integrations such as external SLO dashboards and alerting tools (e.g. nobl9). For weekly compliance history, use the [Get SLO History endpoint](https://api-docs.honeycomb.io/api/reporting/getSloHistory/). **Requirements:** - Available on the [Enterprise plan](https://www.honeycomb.io/pricing/) only. - This feature must be enabled for your team. Contact your account team to request access. **Gaps:** Some minutes may have no entry in the `windows` array. The first window after a gap may contain a larger-than-usual delta. Treat missing timestamps as unavailable data, not zero-event periods. **Epoch:** The response includes an `epoch` field — a hash of the SLO's SLI expression and dataset configuration. If this value changes between responses, the underlying SLO definition has changed and any client-side cache should be invalidated. **Partial windows:** Windows marked `is_partial: true` may still receive additional events. This occurs for the most recent 10 minutes (late-arriving data settlement) or when no prior snapshot exists to compute a delta from. # Update an SLO Source: https://docs.honeycomb.io/api/slos/update-an-slo /api/openapi-public.yaml put /1/slos/{datasetSlug}/{sloId} Update an SLO by specifying its ID and full SLO details. # Create a Trigger Source: https://docs.honeycomb.io/api/triggers/create-a-trigger /api/openapi-public.yaml post /1/triggers/{datasetSlug} Create a trigger on the provided dataset or environment. # Delete a Trigger Source: https://docs.honeycomb.io/api/triggers/delete-a-trigger /api/openapi-public.yaml delete /1/triggers/{datasetSlug}/{triggerId} Delete a trigger by specifying the trigger ID. The body of the DELETE request should be empty. # Get a Trigger Source: https://docs.honeycomb.io/api/triggers/get-a-trigger /api/openapi-public.yaml get /1/triggers/{datasetSlug}/{triggerId} Fetch details for a single Trigger by Trigger ID. # Get Triggers Associated with a Recipient Source: https://docs.honeycomb.io/api/triggers/get-triggers-associated-with-a-recipient /api/openapi-public.yaml get /1/recipients/{recipientId}/triggers List all triggers that will alert a given Recipient. **Important:** This request will return all Triggers associated with the specific Recipient across your entire Honeycomb team rather than being scoped to a dataset or environment. # List All Triggers Source: https://docs.honeycomb.io/api/triggers/list-all-triggers /api/openapi-public.yaml get /1/triggers/{datasetSlug} List all triggers on the provided dataset or environment. # Update a Trigger Source: https://docs.honeycomb.io/api/triggers/update-a-trigger /api/openapi-public.yaml put /1/triggers/{datasetSlug}/{triggerId} Update a trigger by specifying the trigger ID and the same fields used when creating a new trigger. # Configure Honeycomb Source: https://docs.honeycomb.io/configure Set up and manage your Honeycomb Teams, Environments, and Datasets. Manage your Honeycomb team, environments, and datasets through the UI or Terraform. Configure access controls, API keys, calculated fields, and markers to organize your data and control how your team works in Honeycomb. ## Environments Manage your Honeycomb Environments, which partition your data and organize your Honeycomb resources. Learn how to create and delete Environments, and how to change the Environment description and label color. Manage your Honeycomb API Keys. Use specialized Ingest Keys to send telemetry data to Honeycomb and use Configuration Keys to manage resources in your Honeycomb Environment. Learn how to create and delete API keys, and identify which permissions you may grant to your API Keys. Define and manage unique calculated fields for use in all Datasets contained within your Environment. Otherwise known as Derived Columns, calculated fields are computed properties that are calculated by a formula. Learn how to create, change, and delete environment-wide calculated fields. Each Environment allows you to define global markers that you can use across the Datasets contained within it. Use markers to emphasize specific data points in time, such as deployments, incidents, activated or resolved triggers, and enabled or disabled feature flags. Learn how to create, delete, and change the appearance of markers. ## Datasets Manage your Honeycomb Datasets, which group your data into collections of related events. Learn how to create and delete Datasets, and how to change the Dataset description and set defaults. Manage your Dataset structure to ensure that your data is displayed in ways that support your needs. Manage your Dataset field definitions. Tell Honeycomb how specific fields in your dataset should be interpreted. Define and manage unique calculated fields for use in your Dataset. Otherwise known as Derived Columns, calculated fields are computed properties that are calculated by a formula. Learn how to create, change, and delete dataset-specific calculated fields. Each Dataset allows you to define local markers that you can use within it only. Use markers to emphasize specific data points in time, such as deployments, incidents, activated or resolved triggers, and enabled or disabled feature flags. Learn how to create, delete, and change the appearance of markers. ## Teams Manage Honeycomb Teams, which organize groups of users, grant them access to data, and create a shared work history. Learn how to manage teams, including creating teams. Configure methods of accessing Honeycomb for your team. Learn how to allow team members to log in to the Honeycomb UI using Single Sign-on (SSO). Manage the behavior of Honeycomb Teams. Learn how to set a default environment, enable or disable the Query Assistant, and manage which URLs are displayed as external links for your team. Manage notifications for Honeycomb Teams. Learn how to control which team owners receive usage notifications and how to enable integrations and webhooks for notification purposes. Manage members for Honeycomb Teams. Learn how to invite users, remove users, change users' roles, copy invitation URLS, and restrict who can join your team by email address. Manage permissions for Honeycomb Teams. Learn how to apply roles and permissions to team members. Monitor usage for Honeycomb Teams. Learn how to access trends about your Team's event volume and throughput, and learn about enhanced reporting features. Investigate activity for Honeycomb Teams. Learn how to identify changes in resource configurations and understand how your team members are using Honeycomb by observing and investigating with all of Honeycomb's features, including querying, visualizations, Boards, Triggers, and more. This Honeycomb feature is in beta. ## Manage Honeycomb with Terraform Use the Honeycomb Terraform provider to programmatically create and manage datasets, triggers, SLOs, boards, and other Honeycomb resources as code. # Manage Dataset Calculated Fields Source: https://docs.honeycomb.io/configure/datasets/calculated-fields Create, update, and delete calculated fields scoped to a specific dataset to simplify queries and apply consistent logic to your telemetry data. For clearer insights and consistency, you can use calculated fields to create new fields by applying functions and logic to existing data. ## What is a Dataset Calculated Field? In Honeycomb, saved calculated fields can apply to either a specific dataset or an entire environment. Dataset-specific calculated fields allow you to define custom computations that apply only within a single dataset. By managing these fields at the dataset level, you transform raw data into more meaningful insights without affecting other datasets in your environment. For a more general introduction to calculated fields, their scopes, and how you can use them in Honeycomb, visit [Use Calculated Fields](/investigate/query/build/calculated-fields/). ## Creating Calculated Fields Define a calculated field to transform or derive new insights from your data. To create a dataset-specific calculated field: 1. Log in to the Honeycomb UI. 2. In the navigation menu, select the **Environment** label, then choose the environment that includes the dataset to which you want to add a calculated field. 3. In the navigation menu, select **Manage Data**, then choose **Datasets**. 4. Locate the dataset to which you want to add a calculated field, and select its name to open its settings. 5. Go to the **Schema** view. 6. Expand the **Calculated Fields** section. 7. Select **Add New Calculated Field**. 8. In the modal, enter details: | Field | Description | | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Display Name** | Name that appears in the Query Builder. Enter a name that is unique across the dataset and its containing environment. Although Honeycomb tries to prevent duplicate field names, they can still occur. For help resolving naming conflicts, visit [Common Issues with Queries: Calculated Fields](/troubleshoot/common-issues/queries/#a-link-points-to-the-wrong-location). | | **Prompt** (beta) | Use natural language to generate a Calculated Field. For example, `return "slow" if $duration_ms > 1000`. Be sure to explicitly reference any schema fields using the $ syntax (for example, `$field\_name\`). For help resolving errors, visit [Common Issues with Queries: Calculated Fields](/troubleshoot/common-issues/queries/#calculated-fields). | | Editor | Formula that defines your field. For syntax, available functions, and example formulas, visit [Calculated Field Formula Reference](/reference/calculated-field-expression/). | Hover over syntax errors (red underlines or red triangles) for suggestions on how to fix them. 9. Select **Save**. The screen refreshes, and your new field appears in the list. ## Editing Calculated Fields Update a calculated field to refine its formula or adjust its name. Before changing a calculated field, check for dependencies that may be affected, such as Boards, Triggers, and SLOs. To edit a dataset-specific calculated field: 1. Log in to the Honeycomb UI. 2. In the navigation menu, select the **Environment** label, then choose the environment that includes the dataset with the calculated field you want to change. 3. In the navigation menu, select **Manage Data**, then choose **Datasets**. 4. Find the dataset that contains the calculated field you want to change, and select its name to open its settings. 5. Go to the **Schema** view. 6. Expand the **Calculated Fields** section. 7. Locate the calculated field in the list, and select **Edit**. Edit calculated field 1. If dependencies exist, Honeycomb will prompt you to either [clone the field](#cloning-calculated-fields) or continue editing. If you are unsure, contact the field's most recent editor before proceeding. Edit a calculated field modal with a dependency 8. In the modal, modify the pre-populated name and formula as needed. For syntax, available functions, and example formulas, visit [Calculated Field Formula Reference](/reference/calculated-field-expression/). 9. Select **Save**. The screen refreshes, and the edited field updates in the list. ## Cloning Calculated Fields If you need a new calculated field similar to an existing one, you can clone the existing calculated field and modify it as needed. To clone a dataset-specific calculated field: 1. In the navigation menu, select the **Environment** label, then choose the environment that includes the dataset with the calculated field you want to clone. 2. In the navigation menu, select **Manage Data**, then choose **Datasets**. 3. Find the dataset that contains the calculated field you want to clone, and select its name to open its settings. 4. Go to the **Schema** view. 5. Expand the **Calculated Fields** section. 6. Locate the calculated field in the list, and select **Clone**. Clone a calculated field from the table 7. In the modal, modify the pre-populated name and formula as needed. For syntax, available functions, and example formulas, visit [Calculated Field Formula Reference](/reference/calculated-field-expression/). 8. Select **Save**. The screen refreshes, and your new field appears in the list. ## Deleting Calculated Fields To manage your data effectively, you may need to delete calculated fields that you no longer need. Before removing a calculated field, check for dependencies that may be affected, such as Boards, Triggers, and SLOs. To delete a calculated field, you must be its creator or a [Team Owner](/configure/teams/manage-permissions/). To delete a dataset-specific calculated field: 1. In the navigation menu, select the **Environment** label, then choose the environment that includes the dataset with the calculated field you want to delete. 2. In the navigation menu, select **Manage Data**, then choose **Datasets**. 3. Find the dataset that contains the calculated field you want to delete, and select its name to open its settings. 4. Go to the **Schema** view. 5. Expand the **Calculated Fields** section. 6. Locate the calculated field in the list, and select **Delete**. Delete calculated field 1. If dependencies exist, a list will appear. 2. To continue, remove all dependencies. If you are unsure, contact the most recent editor of each dependency before proceeding. 3. Select **Refresh Dependencies**. Delete a calculated field modal with dependent objects shown 7. In the confirmation modal, select **Delete**. Delete a calculated field confirmation modal The screen refreshes, and the field no longer appears in the list. Existing queries using the calculated field will still work, but the field name will no longer be available when building new queries. # Define Dataset Fields Source: https://docs.honeycomb.io/configure/datasets/definitions Designate which fields in your dataset have special meaning in Honeycomb, including trace IDs, durations, and error fields used in the trace waterfall. The **Definitions** tab in your [Dataset Settings](/reference/honeycomb-ui/manage-data/datasets/dataset-settings/) allows you to define how specific fields in your Honeycomb dataset should be interpreted. Dataset Definitions set the visualization fields in the [trace waterfall](/reference/honeycomb-ui/query/trace-waterfall/) and in [Home](/observe/honeycomb-home/). Some Dataset Definitions automatically populate when using OpenTelemetry or Beelines instrumentation, but additional definition of these fields is possible. ## Access Dataset Definitions Choose your method of accessing Dataset Definitions through **Dataset Settings**: * In [Home](/observe/honeycomb-home/), select **Dataset Settings** for the selected Dataset. In Settings, select the **Definitions** tab. * After selecting **Datasets** from **Manage Data** in the left menu, select a dataset to view its Dataset Settings. In Settings, select the **Definitions** tab. Dataset Definitions appear in the Definitions tab. Use the dropdown window in the top left of the Settings Page to navigate between specific Datasets and their definitions settings. Screenshot of Settings page with selected Definitions tab for frontend dataset ## View Dataset Definitions At the top of Dataset Definitions, two configuration completion indicators appear: [Tracing](/reference/honeycomb-ui/query/trace-waterfall/) () and [Home](/observe/honeycomb-home/) (). Example of Tracing and Home configuration completion indicators with Tracing complete and Home partially complete. Each indicator displays the level of field configuration completion in progress bar and in numerical format. If all fields are configured, then text will confirm completion. Otherwise, it warns about missing displays. Below the indicators, Dataset Definitions appear in rows. Two rows of dataset definitions with their fields mapped Each row consists of one or more **icons**, the **Dataset field**, and the **Field name**. The icons indicate if the Dataset Definition applies to the display configuration of Tracing and/or Home. Some Dataset fields overlap between the two configuration sets. The Dataset field is the fixed field that Honeycomb references in its configuration. The Field name options populate from fields in your dataset. If a Field name is blank, a Dataset Definition is not configured. To configure, use the dropdown list in Field name to choose from the available dataset fields. Selecting a dataset field maps it to Honeycomb's Dataset field. Multiple Dataset Definitions cannot use the same dataset field. If attempted, an "all fields must be unique" error message appears in the display. Honeycomb uses these definitions to provide more visualizations of your data in various Honeycomb interfaces, such as in [Home](/observe/honeycomb-home/), and in the [trace waterfall](/reference/honeycomb-ui/query/trace-waterfall/). ## Configure Dataset Definitions If a Field name in a row is blank, a Dataset Definition is not configured. To configure Dataset Definitions, use the dropdown list in Field name to choose from the available dataset fields. The Field name options populate from fields in your dataset that meet the Dataset field's data type requirements. Selecting a Field name option maps it to Honeycomb's Dataset field. Selecting the **X** removes the dataset definition assignment on this Dataset field. ## Available Definitions ### Tracing Some fields are required for the construction of a trace waterfall, while others are optional and allow us to visualize your data in a different way. Configure all 10 Tracing fields to ensure a full trace waterfall display. Some of these tracing fields overlap with the [Home fields](#home). There is a table showing the [meanings of each tracing field](/send-data/opentelemetry/#instrumented-fields); and a second with the meanings of [span annotation fields](/send-data/standardize/add-context/#annotating-spans) for span events and link events. **Span ID** : \[REQUIRED] The unique ID for each span. **Trace ID** : \[REQUIRED] The ID of the trace this span belongs to. **Parent Span ID** : \[REQUIRED] The ID of this span's parent span, the call location the current span was called from. **Name** : \[REQUIRED] The name of the function or method where the span was created. **Service Name** : \[REQUIRED] The name of the instrumented service. **Span Duration** : \[REQUIRED] How much time the span took, in milliseconds. **Metadata: Kind** : \[OPTIONAL] An attribute specifying the kind of span, for example `root` or `child`. This field previously specified span annotation types. **Metadata: Annotation Type** : An attribute specifying the type of Span Annotation. Accepted values are: `span_event` or `link`. Only required if you are using one or both of the Span Event or Trace Link annotation features. For most cases, this field is not required. This field lets Honeycomb move Span Annotations from the trace waterfall to the trace sidebar, where they are easier to find and access. Do not use this field for purposes other than specifying the type of Span Annotation. Learn more about [Span Annotations](/send-data/standardize/add-context/#annotating-spans). **Metadata: Link Span ID** : The [Link Span ID](/send-data/standardize/add-context/#establish-relationships-between-spans-in-different-trace-hierarchies) allows linking to a different span (when used with Link Trace ID). **Metadata: Link Trace ID** : The [Link Trace ID](/send-data/standardize/add-context/#establish-relationships-between-spans-in-different-trace-hierarchies) allows linking to a different trace or a different span in the same trace (when used with Link Span ID). ### Home Honeycomb visualizes some data on [Home](/observe/honeycomb-home/) without any of these definitions being set. Setting the dataset definitions for Home fields enables tabs within the Home display to be selectable. Some of these Home fields overlap with the [tracing fields](#tracing). Configure all 8 Home fields to ensure all tabs in Home are selectable. **Error** : A boolean or string indicating an error. This field can be a calculated field. If you use a string, any value except for `""`, `" "`, and `"false"` will be considered an error. **HTTP Status Code** : Indicates the success, failure, or other status of a request. This field can be a string, integer, float or calculated field. Read more about [http status codes here](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status). **Route** : The HTTP URL or equivalent route processed by the request. This field can be a calculated field. **Span Duration** : How much time the span took, in milliseconds. **User** : The ID, name, email address (or another unique identifier) of the user making the request in the system. This field can be a string, integer, float, or calculated field. **Name** : The Name field represents the name of the function or method where the span was created. **Log Message** : Value containing the log event message. May be a human-readable string message (including multiline) describing the event in free form. **Log Severity** : Severity level of the event (also known as log level). Supported values include: `trace`, `debug`, `info`, `warn`, `error`, `fatal`, and `unspecified`. # Manage Datasets Source: https://docs.honeycomb.io/configure/datasets/manage Create, delete, and update Honeycomb Datasets, which group related events into queryable collections organized within your Environments. Datasets are created programmatically when you send data to Honeycomb. Honeycomb uses Datasets to group your data into collections of related events. Once you create a dataset, you can manage it using the Honeycomb UI. ## Create Dataset To send data to Honeycomb, you must instrument your service and then make requests to it. Making requests to your service will generate telemetry data and send it to Honeycomb where it will appear in the Honeycomb UI within seconds. When you send data to Honeycomb, Honeycomb creates a Dataset in which to store your data, using the service name in your instrumentation as the Dataset's name. Once created, Dataset names are permanent. Honeycomb determines which Environment to should house your Dataset based on the [API Key](/configure/environments/manage-api-keys/) with which you send the data. You cannot create a Dataset through the Honeycomb UI. ## Add Description To add your Dataset's description: 1. Log in to the Honeycomb UI. 2. Select the **Environments** label on the top-left, then select the Environment that contains the Dataset for which you want to add a description. 3. In the left navigation menu, select **Manage Data**. 4. In the list, locate and select **Datasets**. 5. In the list, locate the Dataset for which you want to add a description, and select its name to view the available settings. 6. Locate the **Description** section, and select **Add a description for this dataset**. 7. Enter a description, and select **Save Changes**. ## Change Description To change your Dataset's description: 1. Log in to the Honeycomb UI. 2. Select the **Environments** label on the top-left, then select the Environment that contains the Dataset for which you want to change the description. 3. In the left navigation menu, select **Manage Data**. 4. In the list, locate and select **Datasets**. 5. In the list, locate the Dataset for which you want to change the description, and select its name to view the available settings. 6. Locate the **Description** section, and select **Edit**. 7. Enter a new description, and select **Save Changes**. ## Set Default Granularity For periodic data captured at regular, known intervals, such as metric data, you can set a minimum default granularity, or interval, to ensure that queries within the Dataset do not drop below it (unless you choose to override it manually when building an individual query). Default Granularity affects the display of visualizations seen: * after running a query * on [Honeycomb Home](/observe/honeycomb-home/) * as suggested queries on a blank query page To set your Dataset's default granularity: 1. Log in to the Honeycomb UI. 2. Select the **Environments** label on the top-left, then select the Environment that contains the Dataset for which you want to set the default granularity. 3. In the left navigation menu, select **Manage Data**. 4. In the list, locate and select **Datasets**. 5. In the list, locate the Dataset for which you want to set the default granularity, and select its name to view the available settings. 6. Locate the **Default Granularity** section, and select the desired interval from the dropdown. To prevent a spiky appearance in your graphs, we recommend that you set the default granularity with the interval at which data enters Honeycomb. For example, if your data enters the dataset at regular 30-second intervals, we recommend setting a default granularity of 30 seconds. We save your changes automatically. ## Set Suggested Queries For each Dataset, you can select a Board to provide suggested queries, which will appear any time you land on a blank query page. To set your Dataset's suggested queries: 1. Log in to the Honeycomb UI. 2. Select the **Environments** label on the top-left, then select the Environment that contains the Dataset for which you want to set suggested queries. 3. In the left navigation menu, select **Manage Data**. 4. In the list, locate and select **Datasets**. 5. In the list, locate the Dataset for which you want to set suggested queries, and select its name to view the available settings. 6. Locate the **Suggested Queries** section, and select the desired Board from the dropdown. You must select a public Board that contains named queries. Multiple datasets can use the same board. We save your changes automatically. ## Set Default Correlations Board For each Dataset, you can select a [Board](/observe/boards/) to appear in the **Correlations** view of your query results. The order of the charts in the Correlations view matches the order of the charts on the Board. To set your Dataset's default Correlations Board: 1. Log in to the Honeycomb UI. 2. Select the **Environments** label on the top-left, then select the Environment that contains the Dataset for which you want to set a default Correlations Board. 3. In the left navigation menu, select **Manage Data**. 4. In the list, locate and select **Datasets**. 5. In the list, locate the Dataset for which you want to set a default Correlations Board, and select its name to view the available settings. 6. Select the **Correlations** view. 7. Locate the **Default Correlations Board** section, and select the desired Board from the dropdown. You must select a public Board. Multiple datasets can use the same board. We save your changes automatically. ## Delete Dataset Dataset deletion is permanent, so make sure you really want to delete your Dataset before doing so. To delete a Dataset, you must be a [Team Owner](/configure/teams/manage-permissions/), and Deletion Protection must be disabled. To delete your Dataset: 1. Log in to the Honeycomb UI. 2. Select the **Environments** label on the top-left, then select the Environment that contains the Dataset you want to delete. 3. In the left navigation menu, select **Manage Data**. 4. In the list, locate and select **Datasets**. 5. In the list, locate the Dataset that you want to delete, and select its name to view the available settings. 6. Select the **Delete** view. 7. If **Deletion Protection** is enabled for the Dataset, toggle it 'off' to enable the **Delete Dataset** button. 8. Select **Delete Dataset**. 9. In the **Delete Dataset?** modal, enter the unique identifier of the Dataset (listed in parentheses). 10. Select **I understand the consequences. Delete this dataset**. Your Dataset will be deleted, but it may take several minutes for the process to complete. # Manage Dataset Markers Source: https://docs.honeycomb.io/configure/datasets/manage-markers Create, delete, and style markers scoped to a specific dataset to flag deployments, incidents, and feature flag changes within that dataset's views. Each Dataset allows you to define markers for use within it. You can create markers at both the Dataset and the Environment level. When you create a marker at the Dataset level, you can use it only within its associated Dataset. When you create a marker at the Environment level, you can use it across all Datasets in your Environment. You can manage markers using both the Honeycomb UI and [Honeycomb API](/api/marker-settings/). ## What are Markers? Markers are custom labels that you can add to your data to emphasize specific data points in time, such as when you change a condition, deploy code, or have an outage. Markers display as vertical lines on graphs in Honeycomb to signal interesting occurrences within the context of your queries. ## Uses Use markers to identify points in time, such as: * deployments * incidents * activated or resolved Triggers * enabled or disabled feature flags You should create a Dataset-level marker when the range of time is relevant only to the specific Dataset or Service. ## Change Marker Color You must be a [Team Owner](/configure/teams/manage-permissions/) to change a marker's color. To change your marker color: 1. Log in to the Honeycomb UI. 2. Select the **Environments** label on the top-left, then select the appropriate environment. 3. In the left navigation menu, select **Manage Data**. 4. In the list, locate and select **Datasets**. 5. In the list, locate the dataset that contains the marker you want to edit, and select its name to view the available settings. 6. Select the **Markers** view. 7. In the list, locate the **Marker Type** you want to change, and select the desired color from the dropdown in the **Color** column. We will save your changes automatically. ## Add Markers From the UI To create a marker from the Honeycomb UI: 1. In your query results, move your cursor over the graph to your desired time point. 2. Select your desired time point, which causes the graph menu options to appear. 3. Select **Add marker**. The **Add a Marker** modal appears. Screenshot illustrating the 'Add a Marker' dialog box 4. Enter the following information: 1. A Message for your marker, such as "Deploy #299" or "Abnormal Spike in Products Page Traffic". 2. A Type for the marker, such as "deploy" or "trigger". After creation, the type appears as a preface to the marker's message when viewing the marker details. 3. The URL field is optional, but provides a great way for more context about the marker. 4. Select the "Environment-wide" checkbox to apply this marker to **all** datasets in your environment. 5. When finished, select **Create** to add your marker to the graph. To add markers via a command line tool or further manage existing markers, use either `curl` or `honeymarker`, a lightweight marker management tool that provides a CRUD command line interface. Refer to our Markers documentation for more information. ## View Markers in the UI Once created, markers appear on any queries that run within the same time period as the marker(s). Each marker type can appear in its own color. To change dataset marker color, configure dataset markers in [Dataset Settings](/configure/datasets/manage-markers/#change-marker-color). Hover over the Marker icon () to view a marker's details. A solid vertical line appears and a window displays the marker's name, description, and if applicable, a selectable URL. To persist the marker's vertical line and information window, select the downward caret icon. To close the persisted display, use the icon () that appears in the window after selection. Screenshot illustrating a selected marker and marker details ## Filter Markers in the UI By default, Honeycomb shows environment markers in environment-wide queries and dataset markers in dataset queries. Use **Filter Markers** to modify what markers appear in the query results. To access **Filter Markers**, either: 1. Press `l` on your keyboard 2. Select the Marker options icon () below the time picker in your query results, and select **Filter Markers**. The Filter Markers modal appears. Use to modify what markers appear based on: 1. on their value 2. whether or not markers of the opposite type (environment/dataset) are allowed 3. their marker type Screenshot illustrating the 'Filter Markers' dialog box for a dataset query # Manage Dataset Structure Source: https://docs.honeycomb.io/configure/datasets/structure Adjust schema settings and field display options to control how incoming data is organized and presented within a Honeycomb Dataset. When you send data to Honeycomb, a dataset is created with a schema based on the incoming data. Adjust the dataset’s structure and settings to control how your data is organized. ## Introduction In Honeycomb, managing your dataset's structure ensures that your data is displayed in ways that support your analysis needs. ## Managing Unique Fields Your dataset is created when you first send data to Honeycomb, and its unique fields are automatically generated based on the incoming data. If you name your incoming data fields in a specific way, Honeycomb can automatically map them. To learn more about field mapping, visit [Map Your Data](/send-data/standardize/map-data/). By managing these unique fields, you can control how your data is structured and displayed, ensuring it meets your goals. ### Modifying Field Data Types In Honeycomb, you can modify the data type of a field to ensure it accurately reflects the data it holds. Adjusting field data types can help improve data consistency and support more accurate analysis. To modify a field's data type: 1. Log in to the Honeycomb UI. 2. In the navigation menu, select the **Environment** label, then choose the environment that includes the dataset with the unique field you want to change. 3. In the navigation menu, select **Manage Data**, then choose **Datasets**. 4. Locate the dataset that contains the unique field you want to change, and select its name to open its settings. 5. Go to the **Schema** view. 6. Expand the **Unique Fields** section. 7. Locate the field you want to change, and use the dropdown in the **Type** column to select a new data type. In the future, if you send an event that does not match the selected data type, Honeycomb will try to coerce the value. If coercion is not possible, the value will be set to `0` instead of being dropped. We save and apply your changes automatically. ### Managing Field Visibility You can control the visibility of unique fields in your dataset to streamline your data and focus on the most relevant information. Hiding fields that aren't needed helps keep your dataset clean and easy to navigate without losing data. When you hide a field, the field will no longer display in: * the [Query Builder](/reference/honeycomb-ui/query/#query-builder) for editing. * the Schema sidebar for searching. * the [Dataset Definition](/configure/datasets/definitions/#access-dataset-definitions). Hidden fields will still display in: * Triggers * Calculated Fields (with a warning) To hide or show a unique field: 1. Log in to the Honeycomb UI. 2. In the navigation menu, select the **Environment** label, then choose the environment that includes the dataset with the unique field for which you want to change visibility. 3. In the navigation menu, select **Manage Data**, then choose **Datasets**. 4. Locate the dataset that contains the unique field for which you want to change visibility, and select its name to open its settings. 5. Go to the **Schema** view. 6. Expand the **Unique Fields** section. 7. Locate the field for which you want to change visibility, and locate its **Hide** column, then: * Select the checkbox to hide the field. * Deselect the checkbox to show the field. We save and apply your changes automatically. ### Editing Unique Fields You can customize the properties of your unique fields to refine your dataset's structure. To edit a unique field: 1. Log in to the Honeycomb UI. 2. In the navigation menu, select the **Environment** label, then choose the environment that includes the dataset with the unique field you want to change. 3. In the navigation menu, select **Manage Data**, then choose **Datasets**. 4. Locate the dataset that contains the unique field you want to change, and select its name to open its settings. 5. Go to the **Schema** view. 6. Expand the **Unique Fields** section. 7. Locate the field you want to change, and edit its properties: | Property | Description | | ------------------ | -------------------------------------------------------------------------------------- | | **Type** | Data type of the field. | | **Hide** | Controls whether the field is visible in queries. Select to hide, or deselect to show. | | **Description** | Description of the field. Maximum of 255 characters. | | **Max Key Length** | Maximum length allowed for key names in the field. | We save and apply your changes automatically. # Manage Environment Calculated Fields Source: https://docs.honeycomb.io/configure/environments/calculated-fields Create, update, and delete calculated fields that apply across all datasets in an Environment, so you can standardize metrics and reuse logic team-wide. For clearer insights and consistency, you can use calculated fields to create new fields by applying functions and logic to existing data. Environments exist only in Honeycomb's current release. If you use Honeycomb Classic, we recommend [migrating to Honeycomb Environments](/troubleshoot/product-lifecycle/recommended-migrations/#migrate-from-honeycomb-classic-to-honeycomb-environments), so you can take advantage of its expanded data model and future product updates. ## What is an Environment Calculated Field? In Honeycomb, saved calculated fields can apply to either a specific dataset or an entire environment. Environment-wide calculated fields let you define reusable computations that apply across multiple datasets and services. By managing these fields at the environment level, you ensure consistency in data transformation and reduce the need for redundant field definitions. For a more general introduction to calculated fields, their scopes, and how you can use them in Honeycomb, visit [Use Calculated Fields](/investigate/query/build/calculated-fields/). ## Creating Calculated Fields Define a calculated field to transform or derive new insights from your data. To create an environment-wide calculated field: 1. Log in to the Honeycomb UI. 2. In the navigation menu, select the **Environment** label, then choose **Manage Environments**. 3. Locate the environment to which you want to add a calculated field, and select its name to open its settings. 4. Go to the **Schema** view. 5. Select **Add New Calculated Field**. 6. In the modal, enter details: | Field | Description | | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **Display Name** | Name that appears in the Query Builder. Enter a name that is unique across all datasets and the containing environment. Although Honeycomb tries to prevent duplicate field names, they can still occur. For help resolving naming conflicts, visit [Common Issues with Queries: Calculated Fields](/troubleshoot/common-issues/queries/#a-link-points-to-the-wrong-location). | | **Prompt** (beta) | Use natural language to generate a Calculated Field. For example, `return "slow" if $duration_ms > 1000`. Be sure to explicitly reference any schema fields using the $ syntax (for example, `$field\_name\`). For help resolving errors, visit [Common Issues with Queries: Calculated Fields](/troubleshoot/common-issues/queries/#calculated-fields). | | Editor | Formula that defines your field. For syntax, available functions, and example formulas, visit [Calculated Field Formula Reference](/reference/calculated-field-expression/). | Hover over syntax errors (red underlines or red triangles) for suggestions on how to fix them. 7. Select **Save**. The screen refreshes, and your new field appears in the list. ## Editing Calculated Fields Update a calculated field to refine its formula or adjust its name. Before changing a calculated field, check for dependencies that may be affected, such as Boards, Triggers, and SLOs. To edit an environment-wide calculated field: 1. Log in to the Honeycomb UI. 2. In the navigation menu, select the **Environment** label, then select **Manage Environments**. 3. Find the environment containing the calculated field you want to change, and select its name to open its settings. 4. Go to the **Schema** view. 5. Locate the calculated field in the list, and select **Edit**. Edit calculated field 1. If dependencies exist, Honeycomb will prompt you to either [clone the field](#cloning-calculated-fields) or continue editing. If you are unsure, contact the field's most recent editor before proceeding. Edit a calculated field modal with a dependency 6. In the modal, modify the pre-populated name and formula as needed. For syntax, available functions, and example formulas, visit [Calculated Field Formula Reference](/reference/calculated-field-expression/). 7. Select **Save**. The screen refreshes, and the edited field updates in the list. ## Cloning Calculated Fields If you need a new calculated field similar to an existing one, you can clone the existing calculated field and modify it as needed. To clone an environment-wide calculated field: 1. Log in to the Honeycomb UI. 2. In the navigation menu, select the **Environment** label, then select **Manage Environments**. 3. Find the environment containing the calculated field you want to clone, and select its name to open its settings. 4. Go to the **Schema** view. 5. Locate the calculated field in the list, and select **Clone**. Clone a calculated field from the table 6. In the modal, modify the pre-populated name and formula as needed. For syntax, available functions, and example formulas, visit [Calculated Field Formula Reference](/reference/calculated-field-expression/). 7. Select **Save**. The screen refreshes, and your new field appears in the list. ## Deleting Calculated Fields To manage your data effectively, you may need to delete calculated fields that you no longer need. Before removing a calculated field, check for dependencies that may be affected, such as Boards, Triggers, and SLOs. To delete a calculated field, you must be its creator or a [Team Owner](/configure/teams/manage-permissions/). To delete an environment-wide calculated field: 1. Log in to the Honeycomb UI. 2. In the navigation menu, select the **Environment** label, then choose **Manage Environments**. 3. Find the environment containing the calculated field you want to delete, and select its name to open its settings. 4. Go to the **Schema** view. 5. Locate the calculated field in the list, and select **Delete**. Delete calculated field 1. If dependencies exist, a list will appear. 2. To continue, remove all dependencies. If you are unsure, contact the most recent editor of each dependency before proceeding. 3. Select **Refresh Dependencies**. Delete a calculated field modal with dependent objects shown 6. In the confirmation modal, select **Delete**. Delete a calculated field confirmation modal The screen refreshes, and the field no longer appears in the list. Existing queries using the calculated field will still work, but the field name will no longer be available when building new queries. # Manage Environments Source: https://docs.honeycomb.io/configure/environments/manage Create, delete, and update Honeycomb Environments, which partition your data and organize your resources across datasets and API keys. When you first add Honeycomb to your application, you will need to specify an Environment. Honeycomb uses Environments to partition your data and organize your Honeycomb resources. You can manage your Honeycomb Environments using the Honeycomb UI. Environments exist only in Honeycomb's current release. If you use Honeycomb Classic, we recommend [migrating to Honeycomb Environments](/troubleshoot/product-lifecycle/recommended-migrations/#migrate-from-honeycomb-classic-to-honeycomb-environments), so you can take advantage of its expanded data model and future product updates. ## Create Environment To create your Environment: 1. Log in to the Honeycomb UI. 2. Select the **Environments** label on the top-left, then select **Manage Environments**. 3. Select **Create Environment**. 4. In the **Create Environment** modal, enter a name for the environment. Optionally, enter a description and choose a color for its label. Once you create your environment, you cannot rename it. You can delete it. 5. Select **Create Environment**. You should now see the new Environment in the list of environments. We have also automatically generated an API Key for your Environment; to see it, select **View API Keys**. Make sure you copy your API Key for later use in your instrumentation. To learn more about API Keys, visit [Manage API Keys](/configure/environments/manage-api-keys/). ## Add Description To add your Environment's description: 1. Log in to the Honeycomb UI. 2. Select the **Environments** label on the top-left, then select **Manage Environments**. 3. In the list, locate the environment for which you want to add a description, and select its name to view the available settings. 4. Locate the **Description** section, and select **Add a description for this environment**. 5. Enter a description, and select **Save Changes**. ## Change Description To change your Environment's description: 1. Log in to the Honeycomb UI. 2. Select the **Environments** label on the top-left, then select **Manage Environments**. 3. In the list, locate the environment for which you want to change the description, and select its name to view the available settings. 4. Locate the **Description** section, and select **Edit**. 5. Enter a new description, and select **Save Changes**. ## Change Label Color To change your Environment's label color: 1. Log in to the Honeycomb UI. 2. Select the **Environments** label on the top-left, then select **Manage Environments**. 3. In the list, locate the environment for which you want to change the label color, and select its name to view the available settings. 4. Locate the **Color** section, and select the desired color from the dropdown. 5. Select **Save Changes**. ## Delete Environment Environment deletion is permanent, so make sure you really want to delete your Environment before doing so. Deletion Protection prevents an Environment from being accidentally deleted. To delete an Environment, you must be a [Team Owner](/configure/teams/manage-permissions/), Deletion Protection must be disabled, and the Environment must not be the last Environment in your Team. To delete your Environment: 1. Log in to the Honeycomb UI. 2. Select the **Environments** label on the top-left, then select **Manage Environments**. 3. In the list, locate the Environment that you want to delete, and select its name to view the available settings. 4. Select the **Delete** view. 5. If **Deletion Protection** is enabled for the Environment, toggle it 'off' to enable the **Delete Environment** button. 6. Select **Delete Environment**. 7. In the **Delete Environment?** modal, enter the unique identifier of the Environment (listed in parentheses). 8. Select **I understand the consequences. Delete this environment**. Your Environment will be deleted, but it may take several minutes for the process to complete. ## Troubleshoot To see common issues when managing Environments and their solutions, visit [Common Issues with Configuring Honeycomb: Environments](/troubleshoot/common-issues/configuring-honeycomb/#environments). # Manage Environment API Keys Source: https://docs.honeycomb.io/configure/environments/manage-api-keys Create and manage Ingest and Configuration API keys at the Environment level, and control which permissions each key type can grant. Each Environment allows you to define API Keys for use within it. You can create API Keys at the Environment level only. API Keys are shared and available for you to use across all Datasets in your Environment. You can create and manage Environment-level API Keys through the Honeycomb UI. To create and manage Team-level resources, visit [Team API Keys](/configure/teams/manage-api-keys/). ## What are Environment-level API Keys? In Honeycomb, some API keys are associated with Honeycomb Environments, which organize all of your Honeycomb resources and consist of a set of datasets, a set of API keys, a set of calculated fields, and a set of markers. When you create an API key, you assign it a set of permissions, which determines which actions your Team can use it to perform in the associated Environment. Any programmatic request sent to Honeycomb must use an API Key. ## Uses Honeycomb uses two types of Environment-level API keys, each for different purposes: * **Ingest Keys**: You can use these API Keys to send telemetry data to Honeycomb. * **Configuration Keys**: You can use these API Keys to manage resources in your Honeycomb Environment. To learn more about using API Keys, visit [Best Practices for API Keys](/get-started/best-practices/api-keys/). ## Find API Keys When you join Honeycomb, we help you create your first Team and Environment. As part of this process, we create your first Environment-level API Key--a Configuration Key--for you. For security reasons, you can access the value of your API key only while creating it. You may be able to use the information you retrieve in this section to identify a key or its settings, so you can retrieve it from the safe location in which you previously stored it. To find your API Keys: 1. Log in to the Honeycomb UI. 2. Select the **Environments** selector in the navigation menu, then select **Manage Environments**. 3. In the list, locate the Environment for which you would like to find API Keys, and select its name to view the available settings. 4. Select the **API Keys** view. 5. Select the view that corresponds to the type of API Keys that you would like to view, either **Ingest** or **Configuration**. ## Create API Key To create an API Key, you must be a [Team Owner](/configure/teams/manage-permissions/). Whenever you create an Environment, we automatically create your first Configuration Key for you. To create your API Key: 1. Log in to the Honeycomb UI. 2. Select the **Environments** selector in the navigation menu, then select **Manage Environments**. 3. In the list, locate the Environment where you want to add an API Key, and select its name to view the available settings. 4. Select the **API Keys** view. 5. Select the view that corresponds to the type of API Key that you would like to create, either **Ingest** or **Configuration**. 6. Select **Create API Key**. 7. In the **Create API Key** modal, enter the details for your API Key: | Field | Description | | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | | Name | Label for the API Key. Used to identify this key in the Honeycomb UI. | | Visible to Team Members | *Configuration Keys only*. Controls whether this key is visible to all Team members or Team owners only. | | Permissions | Actions this key is allowed to perform. For a full list of available permissions, visit [API Key Permissions](#api-key-permissions). | For Ingest Keys, choose permissions carefully; they are permanent. To change permissions, you must delete the API Key and create a new one. 8. Select **Save**. 9. For Ingest Keys, copy your Key and save it to a secure location, then select **Ok, I've copied the key**. Honeycomb returns it only upon creation. Configuration Keys can be retrieved from the Honeycomb UI at any time. Store your API keys securely and never check them into version control systems, such as Git. Your new API Key appears in the list of keys. The Key ID is a label that identifies this key in the Honeycomb UI. To learn how to use your new key, visit [API Documentation: Authentication](/api/authentication). To learn more about what you can do with your new key, visit [Honeycomb API Documentation](/api). Or [send data to Honeycomb](/send-data/) with an Ingest Key. ## Change API Key To modify an API Key, you must be a [Team Owner](/configure/teams/manage-permissions/). To change your API Key: 1. Log in to the Honeycomb UI. 2. Select the **Environments** label on the top-left, then select **Manage Environments**. 3. In the list, locate the Environment that contains the API Key that you want to edit, and select its name to view the available settings. 4. Select the **API Keys** view. 5. Select the view that corresponds to the type of API Key that you would like to change, either **Ingest** or **Configuration**. 6. In the list, locate the API Key that you want to change, and select **Details** to view its settings. 7. Change the API Key's details as desired. To learn more about the actions that you can assign to API Keys, visit the [API Key permissions](#api-key-permissions) section. For Ingest API keys, you cannot change the selected actions, but you can delete the API Key. 8. Select **Save**. Your API Key will be changed, but it may take several minutes for the changes to go into effect. ## Delete Ingest Keys Deleting an Ingest Key is permanent, so make sure you really want to delete your Ingest Key before doing so. To delete an Ingest Key, you must be a [Team Owner](/configure/teams/manage-permissions/). To delete your Ingest Key: 1. Log in to the Honeycomb UI. 2. Select the **Environments** label on the top-left, then select **Manage Environments**. 3. In the list, locate the Environment that contains the API Key that you want to delete, and select its name to view the available settings. 4. Select the **API Keys** view. 5. Select the **Ingest Keys** view. 6. In the list, locate the Ingest Key that you want to delete, and select **Details** to view its settings. 7. Select **Delete**. 8. In the **Delete Ingest API Key?** modal, enter the unique identifier of the Ingest Key (located above the field). 9. Select **Delete**. Your Ingest Key will no longer show in the list, but it may take several minutes for the process to complete. ## Disable Configuration Keys To disable a Configuration Key, you must be a [Team Owner](/configure/teams/manage-permissions/), and you must have at least one remaining Configuration Key in your Environment. To disable your Configuration Key: 1. Log in to the Honeycomb UI. 2. Select the **Environments** label on the top-left, then select **Manage Environments**. 3. In the list, locate the Environment that contains the API Key that you want to disable, and select its name to view the available settings. 4. Select the **API Keys** view. 5. Select the **Configuration Keys** view. 6. In the list, locate the Configuration Key that you want to disable, and select **Details** to view its settings. 7. Locate the **Enable** checkbox, and deselect it. 8. Select **Save**. Your Configuration Key will no longer show in the list, but it may take several minutes for the process to complete. ## Enable Configuration Keys To enable a Configuration Key, you must be a [Team Owner](/configure/teams/manage-permissions/). To enable your Configuration Key: 1. Log in to the Honeycomb UI. 2. Select the **Environments** label on the top-left, then select **Manage Environments**. 3. In the list, locate the Environment that contains the API Key that you want to enable, and select its name to view the available settings. 4. Select the **API Keys** view. 5. Select the **Configuration Keys** view. 6. Select **Show disabled keys**. 7. In the list, locate the Configuration Key that you want to enable, and select **Details** to view its settings. 8. Locate the **Enable** checkbox, and select it. 9. Select **Save**. Your Configuration Key will show in the list of Configuration Keys, but it may take several minutes for the process to complete. ## API Key Permissions Honeycomb uses two types of Environment-level API keys, each for different purposes: * **Ingest Keys**: Generally used to send telemetry data to Honeycomb. * **Configuration Keys**: Generally used to manage resources in your Honeycomb Environment. However, you can manage the actions that API Keys may perform in your Environment at a more granular level. ### Ingest Keys Ingest Keys are Environment-level API Keys that you can use to send telemetry data to Honeycomb. Ingest Keys have a single permission available: whether they can implicitly create datasets. If an event is sent to Honeycomb specifying a non-existent dataset, Honeycomb will create a new dataset if the associated Ingest Key can implicitly create datasets. You cannot change permissions assigned to an Ingest Key after you have created the key. You can delete the Ingest Key. You can programmatically manage Ingest Keys by using our [Key Management APIs](/api/key-management). ### Classic Ingest Keys Ingest Keys are supported for [Honeycomb Classic](/troubleshoot/product-lifecycle/recommended-migrations/#migrate-from-honeycomb-classic-to-honeycomb-environments) environments, provided the minimum required version of the software sending data in is in use. Please reference the table below to find the minimum supported version for your libraries, and upgrade, if necessary, prior to using Ingest Keys. | Library | Minimum Version | | ----------------------------------------------------------------------------------------------- | --------------- | | [beeline-go](https://github.com/honeycombio/beeline-go) | 1.15.0 | | [beeline-java](https://github.com/honeycombio/beeline-java) | 2.2.0 | | [beeline-nodejs](https://github.com/honeycombio/beeline-nodejs) | 4.1.0 | | [beeline-python](https://github.com/honeycombio/beeline-python) | 3.6.0 | | [beeline-ruby](https://github.com/honeycombio/beeline-ruby) | 3.1.0 | | [buildevents](https://github.com/honeycombio/buildevents) | 0.16.0 | | [honeycomb-opentelemetry-dotnet](https://github.com/honeycombio/honeycomb-opentelemetry-dotnet) | 1.5.0 | | [honeycomb-opentelemetry-go](https://github.com/honeycombio/honeycomb-opentelemetry-go) | 0.10.0 | | [honeycomb-opentelemetry-java](https://github.com/honeycombio/honeycomb-opentelemetry-java) | 1.6.0 | | [honeycomb-opentelemetry-node](https://github.com/honeycombio/honeycomb-opentelemetry-node) | 0.7.0 | | [honeycomb-opentelemetry-python](https://github.com/honeycombio/honeycomb-opentelemetry-python) | 0.4.0b0 | | [honeycomb-opentelemetry-web](https://github.com/honeycombio/honeycomb-opentelemetry-web) | 0.0.4 | | [libhoney-dotnet](https://github.com/honeycombio/libhoney-dotnet) | 1.4.0 | | [libhoney-go](https://github.com/honeycombio/libhoney-go) | 1.22.0 | | [libhoney-java](https://github.com/honeycombio/libhoney-java) | 1.6.0 | | [libhoney-js](https://github.com/honeycombio/libhoney-js) | 4.2.0 | | [libhoney-py](https://github.com/honeycombio/libhoney-py) | 2.4.0 | | [libhoney-rb](https://github.com/honeycombio/libhoney-js) | 2.3.0 | | [husky](https://github.com/honeycombio/husky) | 0.26.0 | | [refinery](https://github.com/honeycombio/refinery) | 2.5.0 | ### Configuration Keys Configuration Keys are API Keys that you can use to manage resources in your Honeycomb Environments. Configuration Keys may have any number of these permissions: Although you may use Configuration Keys to send telemetry data to Honeycomb, we recommend that you use Ingest Keys instead; they are built specifically for this purpose. | API Key Permission | [Auth API value](https:///api/auth/) | Description | | -------------------------- | ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Send Events | `send events` | Send events to Honeycomb. Used as the API Key for [sending data](/send-data/) and for the [Events API](/api/events/). | | Create Datasets | `create datasets` | [Create and manage datasets via API](/api/datasets/). Datasets may also be created implicitly; if an event is sent to Honeycomb specifying a non-existent dataset, an event using an API key with this permission will create a new dataset. | | Manage Queries and Columns | `queries and columns` | Create and manage [queries](/api/queries/), [columns](/api/columns/), [calculated fields](/api/calculated-fields/), and [query annotations](/api/query-annotations/). | | Run Queries | `run queries` | Execute existing queries using the [Query Data API](/api/query-data/). This feature is available as part of the [Honeycomb Enterprise plan](https://www.honeycomb.io/pricing/). | | Manage Public Boards | `boards` | Create and manage [Boards](/api/boards/). | | Manage SLOs | `SLOs` | Create and manage [SLOs](/api/slos/) and their [Burn Alerts](/api/burn-alerts/). SLO Management is available as part of the [Honeycomb Pro and Enterprise plans](https://www.honeycomb.io/pricing/). SLO Reporting is only available on the [Honeycomb Enterprise plan](https://www.honeycomb.io/pricing/). | | Manage Triggers | `triggers` | Create and manage [Triggers](/api/triggers/). | | Manage Recipients | `recipients` | Create and manage [Recipients](/api/recipients/). | | Manage Markers | `markers` | Create and manage [Markers](/api/markers/). | | Read Service Maps | `service maps` | Read [service maps](/api/service-maps/) dependencies. This feature is available as part of the [Honeycomb Enterprise plan](https://www.honeycomb.io/pricing/). | ## Troubleshoot To see common issues when managing API Keys and their solutions, visit [Common Issues with Configuring Honeycomb: API Keys](/troubleshoot/common-issues/configuring-honeycomb/#api-keys). # Manage Environment Markers Source: https://docs.honeycomb.io/configure/environments/manage-markers Create, delete, and style markers at the Environment level to flag deployments, incidents, and feature flag changes across all datasets in that environment. Each Environment allows you to define markers for use within it. You can create markers at both the Dataset and the Environment level. When you create a marker at the Dataset level, you can use it only within its associated Dataset. When you create a marker at the Environment level, you can use it across all Datasets in your Environment. You can manage markers and marker settings using the Honeycomb UI or the Honeycomb API. To learn how to manage markers via the API, visit [Honeycomb API: Markers](/api/markers/). To learn how to manage marker settings via the API, visit [Honeycomb API: Marker Settings](/api/marker-settings/). ## What are Markers? Markers are custom labels that you can add to your data to emphasize specific data points in time, such as when you change a condition, deploy code, or have an outage. Markers display as vertical lines on graphs in Honeycomb to signal interesting occurrences within the context of your queries. ## Uses Use markers to identify points in time, such as: * deployments * incidents * activated or resolved Triggers * enabled or disabled feature flags You should create an Environment-level marker when the range of time is relevant across multiple datasets and services, such as a during a deployment. ## Change Marker Color You must be a [Team Owner](/configure/teams/manage-permissions/) to change a marker's color. To change your marker color: 1. Log in to the Honeycomb UI. 2. Select the **Environments** label on the top-left, then select **Manage Environments**. 3. In the list, locate the environment that contains the marker you want to edit, and select its name to view the available settings. 4. Select the **Markers** view. 5. In the list, locate the **Marker Type** you want to change, and select the desired color from the dropdown in the **Color** column. We save your changes automatically. ## Add Markers From the UI To create a marker from the Honeycomb UI: 1. In your query results, move your cursor over the graph to your desired time point. 2. Select your desired time point, which causes the graph menu options to appear. 3. Select **Add marker**. The **Add a Marker** modal appears. Screenshot illustrating the 'Add a Marker' dialog box 4. Enter the following information: 1. A Message for your marker, such as "Deploy #299" or "Abnormal Spike in Products Page Traffic". 2. A Type for the marker, such as "deploy" or "trigger". After creation, the type appears as a preface to the marker's message when viewing the marker details. 3. The URL field is optional, but provides a great way for more context about the marker. 4. Select the "Environment-wide" checkbox to apply this marker to **all** datasets in your environment. 5. When finished, select **Create** to add your marker to the graph. To add markers via a command line tool or further manage existing markers, use either `curl` or `honeymarker`, a lightweight marker management tool that provides a CRUD command line interface. Refer to our Markers documentation for more information. ## View Markers in the UI Once created, markers appear on any queries that run within the same time period as the marker(s). Each marker type can appear in its own color. Hover over the Marker () to view a marker's details. A solid vertical line appears and a window displays the marker's name, description, and if applicable, a selectable URL. To persist the marker's vertical line and information window, select the downward caret icon. To close the persisted display, use the icon () that appears in the window after selection. Screenshot illustrating a selected marker and marker details ## Filter Markers in the UI By default, Honeycomb shows environment markers in environment-wide queries and dataset markers in dataset queries. Use **Filter Markers** to modify what markers appear in the query results. To access **Filter Markers**, either: 1. Press `l` on your keyboard 2. Select the Marker options icon () below the time picker in your query results, and select **Filter Markers**. The Filter Markers modal appears. Use to modify what markers appear based on: 1. on their value 2. whether or not markers of the opposite type (environment/dataset) are allowed 3. their marker type Screenshot illustrating the 'Filter Markers' dialog box for a dataset query # Configure Team Access Source: https://docs.honeycomb.io/configure/teams/configure-access Let team members authenticate with SSO using Google, Okta SAML, or Microsoft Entra ID. Configure access to allow members of your Team to authenticate using various methods of Single Sign-on (SSO). This feature is available as part of the [Honeycomb Pro and Enterprise plans](https://www.honeycomb.io/pricing/). Configure access to let team members authenticate using Google Single Sign-on (SSO). Configure access to let team members authenticate using Okta SAML Single Sign-on (SSO). Configure access to let team members authenticate using Microsoft Entra ID Single Sign-on (SSO). Learn how to update your SAML Service Provider certificate when Honeycomb releases new certificates. # Rotate Your SAML Certificate Source: https://docs.honeycomb.io/configure/teams/configure-access/saml-certificate-rotation Update your Honeycomb SAML Service Provider certificate when Honeycomb releases a new one to keep SSO authentication working without interruption. EntPro This feature is available as part of the [Honeycomb Pro and Enterprise plans](https://www.honeycomb.io/pricing/). Honeycomb periodically updates the Service Provider certificates used for SAML Single Sign-On (SSO) authentication. When a new certificate is available, Team Owners will see a notification in their team's SAML settings and should update their Identity Provider configuration to use the new certificate. Team SAML settings showing a warning banner saying that the certificate has expired but will still be honored Honeycomb continues to honor older certificates even after newer ones are available. However, we recommend updating to the latest certificate for improved security and to ensure continued support. ## Before you begin To successfully complete this guide, you should have: * Team Owner permissions in Honeycomb * Administrative access to your SAML Identity Provider (IdP) (such as Okta or Microsoft Entra ID) * A SAML Identity Provider that is configured to encrypt assertions * An active SAML SSO configuration for your Team ## Copy the new certificate 1. In Honeycomb, navigate to **Account** > **Team Settings**. 2. Select the **Team Details** view. 3. Locate the **Single Sign-On** section. 4. Select **Change** next to your SAML configuration. 5. In the SAML configuration form, locate the **Service Provider Certificate** field. This field displays the latest certificate that your IdP needs to use. 6. Select the copy button next to the Service Provider Certificate. 7. Save the copied Certificate to a local file. Most Identity Providers require it in `.pem` format. ## Update your Identity Provider Now update your Identity Provider configuration with the new Service Provider Certificate. The specific steps vary depending on your Identity Provider. ### Okta To update the certificate in Okta: 1. Open a new browser tab and navigate to your Okta admin console. 2. Go to **Applications** > **Applications**. 3. Select your Honeycomb application from the list. 4. Select the **General** tab. 5. In the **SAML Settings** section, select **Edit**. 6. Select **Next** to advance past the General Settings. 7. Select **Show Advanced Settings**. 8. Ensure that the "Assertion Encryption" field is set to "Encrypted". If it is set to "Unencrypted", you do not need to do anything. 9. In the **Encryption Certificate** field, upload the certificate file you saved from Honeycomb. 10. Select **Next**, then **Finish**. SAML advanced settings configuration page in Okta showing dropdown menus for security parameters like signature algorithms, encryption settings, and certificate upload options. ### Other SAML providers If you use a different SAML Identity Provider, locate the equivalent certificate or encryption certificate settings in your provider's administration interface. Upload or paste the new Service Provider Certificate that you copied from Honeycomb. ## Complete the certificate update After updating your Identity Provider with the new certificate, complete the update process in Honeycomb: 1. Return to the browser tab with your Honeycomb SAML configuration form. 2. Select **Update SAML Configuration**. 3. Complete the authentication flow with your Identity Provider. If successful, you return to your team's Home page in Honeycomb. The warning notification in your team's SAML settings should no longer appear. For more information about SAML configuration, see: * [Configure Access with Okta/SAML SSO](/configure/teams/configure-access/sso-okta-saml/) * [Configure Access with Microsoft Entra ID/SAML SSO](/configure/teams/configure-access/sso-microsoft-entra-id-saml/) * [Log in with SAML SSO]("/get-started/honeycomb/log-in-with-saml-sso") # Configure Access with Google SSO Source: https://docs.honeycomb.io/configure/teams/configure-access/sso-google Require your Honeycomb Team to authenticate with Google SSO, or allow individual members to opt in to Google login without a team-wide requirement. In Honeycomb, Team Owners can [require that team members authenticate using Google Single Sign-On (SSO)](#requiring-a-team-to-use-google-sso) if the team has a Google Workspace hosted domain. Even when Google SSO is not required, individual users can choose to use their Google accounts to log in to Honeycomb: * New users can [sign up for Honeycomb](#signing-up-for-honeycomb-using-your-google-account) using their Google account * Existing users can enable Google SSO for their individual Honeycomb accounts by [linking an individual Google account](#enabling-google-sso-for-an-existing-honeycomb-account) Honeycomb only supports a single Google SSO hosted domain for a Honeycomb Team. If your Google Workspace has multiple hosted domains, only one can be used for Google SSO with Honeycomb. ## Requiring a team to use Google SSO If you're a Team Owner, you can require that your Team's members authenticate using Google SSO. ### Before you begin To successfully require Google SSO for your Team, you should have a Google Workspace hosted domain. Each Google Workspace hosted domain corresponds to only one Honeycomb Team, and new accounts are automatically added to this Team. For example, all users signing in from `myexample.com` will be added to the Team that corresponds to `myexample.com`. Once SSO is enabled for your Honeycomb Team, all users on your team will need to authenticate through that SSO provider to access the team. Any users that do not exist within your team's chosen SSO provider will not be able to log in. A Honeycomb account can be linked to more than one SAML IdP, so linking this account won't affect any existing IdP connections. ### Enable Google SSO for an existing Honeycomb Team owner account Before you can require that your Honeycomb Team authenticate using Google SSO, you should enable Google SSO for your Team Owner account: 1. Log in to Honeycomb using your Team Owner account. 2. Navigate to [**Account** > **My account**](https://ui.honeycomb.io/account). 3. Locate your name and email address, and select **Google SSO Link Account**. 4. When prompted, complete the additional steps to authenticate with Google. To ensure better security, enable two-factor authentication, if possible. Notice that your account page now shows **(Google SSO)** next to your email address. The next time you access the Honeycomb UI, you can [log in using your Google account](#logging-in-to-honeycomb-using-your-google-account). ### Convert your Honeycomb Team to Google SSO Next, require Google SSO for your Honeycomb Team: 1. In Honeycomb, navigate to **Account** > **Team Settings**, and select the **Team Details** view. 2. Locate the **Single Sign-On** section, which displays any previous SSO configuration. 3. Select **Enable SSO**. Enable SSO 4. In the SSO provider configuration modal, select **Google**, then select **Next**. 5. You can also choose a **Default Role** to assign to new users joining your team through SSO. If you don't choose a default role, **Read-Only** will be the default role. 6. When prompted, complete the additional steps to authenticate with Google. Notice that your Team Settings page now shows **Single Sign-On: Enabled**. Your team members will now need to use Google SSO to log in to Honeycomb. ## Signing up for Honeycomb using your Google account If you are a new user and you want to sign up for Honeycomb using your Google account: 1. Navigate to the [Honeycomb sign-up page](https://ui.honeycomb.io/signup), and select **Sign up with Google**. Sign up with Google 2. When prompted, choose your Google account, then complete the additional sign-up steps. ## Enabling Google SSO for an existing Honeycomb account If you created your Honeycomb account with email address/password as credentials, you can link your Google account to your Honeycomb account and use Google to log in to Honeycomb thereafter: 1. Navigate to [**Account** > **My account**](https://ui.honeycomb.io/account). 2. Locate your name and email address, and select **Google SSO Link Account**. 3. When prompted, complete the additional steps to authenticate with Google. To ensure better security, enable two-factor authentication, if possible. Notice that your account page now shows **(Google SSO)** next to your email address. The next time you access the Honeycomb UI, you can [log in using your Google account](#logging-in-to-honeycomb-using-your-google-account). ## Logging in to Honeycomb using your Google account If you originally [signed up for Honeycomb using your Google account](#signing-up-for-honeycomb-using-your-google-account) or have [enabled Google SSO for an Existing Honeycomb account](#enabling-google-sso-for-an-existing-honeycomb-account), you can log in to Honeycomb using your Google account: 1. Navigate to the [Honeycomb UI](https://ui.honeycomb.io), and select **Login with Google**. Log in with Google 2. When prompted, choose your Google account. If you encounter an error while signing in, [check out our troubleshooting section](#troubleshooting). ## Troubleshooting To explore common issues when configuring access, visit [Common Issues with Configuring Honeycomb: Google SSO](/troubleshoot/common-issues/configuring-honeycomb/#google-sso). ### Honeycomb does not support multiple hosted domains Honeycomb currently only supports a single Google SSO hosted domain for a Honeycomb Team. Although your Google Workspace may have multiple hosted domains attached to it, only one can be used for Google SSO with Honeycomb. # Configure Access with Microsoft Entra ID/SAML SSO Source: https://docs.honeycomb.io/configure/teams/configure-access/sso-microsoft-entra-id-saml Require your Honeycomb Team to authenticate via Microsoft Entra ID, formerly Azure Active Directory. EntPro This feature is available as part of the [Honeycomb Pro and Enterprise plans](https://www.honeycomb.io/pricing/). Enable single sign-on (SSO) to authenticate to Honeycomb with your Microsoft Entra account. Microsoft Entra ID is formerly known as Microsoft Azure Active Directory (Azure AD). In Honeycomb, Team Owners can require that their team members authenticate using Single Sign-On (SSO) via an external SAML 2.0 Identity Provider, such as Okta or Microsoft Entra ID. When you configure SSO via an external SAML Identity Provider, you must get information generated during the configuration process from both Honeycomb and your Identity Provider. Because you will also need to enter information into both Honeycomb and your Identity Provider's user interface, you will need to use more than one browser tab. In this guide, we demonstrate a SAML Identity Provider configuration using Microsoft Entra ID. If you are using a different SAML Identity Provider, field names and locations may vary, so you will need to locate the corresponding fields in your Identity Provider's user interface. ## Before You Begin To successfully complete this guide, you should have an active [Microsoft Entra](https://entra.microsoft.com/) account. Once SSO is enabled for your Honeycomb Team, all users on your team will need to authenticate through that SSO provider to access the team. Any users that do not exist within your team's chosen SSO provider will not be able to log in. A Honeycomb account can be linked to more than one SAML IdP, so linking this account won't affect any existing IdP connections. ## Enable SSO in Honeycomb To begin, enable SSO in Honeycomb, which will allow you to get Honeycomb's Service Provider settings: 1. In Honeycomb, navigate to **Account** > **Team Settings**, and select the **Team Details** view. 2. Locate the **Single Sign-On** section, which displays any previous SSO configuration. 3. If your team is already configured to use Google SSO, turn off Google SSO. Turn off SSO 4. Select **Enable SSO**. Enable SSO 5. In the SSO provider configuration modal, select **SAML/Okta**, then select **Next**. 6. Locate the settings required by your Identity Provider. Information you will need includes: * Service Provider Issuer * Service Provider ACS URL * Service Provider Certificate (optional, used when your Identity Provider requires encrypted SAML assertions or signed authentication requests) Leave this browser tab open, so you will have the information you need to configure your Identity Provider. SAML Honeycomb settings screen Honeycomb generates a unique identifier based on your team name. You will see the identifier appended to the values in the **Service Provider Issuer** and **Service Provider ACS URL** fields. For this example, the team name is `Crewbacca`, so the team's generated identifier is `crewbacca`. ## Configure Your Identity Provider Next, configure your Identity Provider to work with Honeycomb. To do this, you must set up SSO for an application integration in your Identity Provider, and then specify which users should be able to use SSO to log in to your team in Honeycomb. When you configure your Identity Provider, you must [provide exact configuration values for your SAML attributes](#exact-configuration-values). In this section, we demonstrate a typical SAML Identity Provider configuration using Microsoft Entra ID. If you are using a different SAML Identity Provider, field names and locations may vary, so you will need to locate the corresponding fields in your Identity Provider's user interface. ### Set Up SSO Set up SSO in your Identity Provider using the Service Provider settings you retrieved from Honeycomb: 1. Open a new browser tab, and go to your Microsoft Entra admin center. 2. In Microsoft Entra, go to **Dashboard** > **Enterprise Applications** > **Overview**. 3. Select **+ New application** and a Browse Microsoft Entra Gallery display appears. 4. Select **Create your own application**. 5. When prompted, name your app in the format "Honeycomb \[Your Team Name]" and select the **Integrate any other applications you don't find in the gallery (Non-gallery)** radio option. Microsoft Entra Create your own application modal Because you can have multiple Honeycomb teams connected to SSO and separate SSO configurations for each Honeycomb team, ensure your chosen application name clearly defines which team uses this SSO integration. The application name will appear in your application directory after installation. For this example, our team name is `Crewbacca`, so we name our application `Honeycomb [Crewbacca]`. 6. Assign yourself access to the new Honeycomb enterprise application. Your user account must be assigned to the Honeycomb application in order to finish configuration. You may assign other users to the application now, or you can wait and add more users later. 7. Select **SAML** as the single sign-on method. 8. For **Set up Single Sign-On with SAML**, locate the **Basic SAML Configuration** section, and enter your retrieved Honeycomb setting values according to the following mapping: | Microsoft Entra ID Field | Honeycomb Setting Name | | ---------------------------------------------- | --------------------------------------------------------------------------------------------------------- | | **Identifier (Entity ID)** | **Service Provider Issuer/Entity ID** | | **Reply URL (Assertion Consumer Service URL)** | **Service Provider ACS URL** | | **Sign on URL** | The `honeycomb.io` base domain from the URLs above plus the path `/login/sso/{team_slug}`. See tip below. | To find the **Sign on URL** value for Microsoft Entra ID, navigate in Honeycomb to **Account** > **Team Settings** > **Team Details**, scroll to the **Single Sign-On** section, and copy the URL that appears in the paragraph for "manually visit `https://ui.honeycomb.io/login/sso/`. 9. Locate the **Attribute & Claims** section, and add the following values: Honeycomb reads the claim names (`Email`, `FirstName`, `LastName`) from your SAML assertion, so they must match exactly with any Identity Provider. `Unique User Identifier` becomes the assertion's NameID, which Honeycomb also requires. The **Value** column is Entra specific: it tells Microsoft Entra ID which user profile field to send. For example, enter `user.mail`, not the user's actual email address. | Attribute Name | Value | | ------------------------ | ------------------------ | | `Email` | `user.mail` | | `FirstName` | `user.givenname` | | `LastName` | `user.surname` | | `Unique User Identifier` | `user.userprincipalname` | All attributes should have no namespace. Leave advanced SAML claims options as their defaults: | Advanced SAML Claims Option | Value | | ------------------------------- | ---------- | | `Include attribute name format` | `Disabled` | | `Issuer with application ID` | `Disabled` | | `Audience override` | `none` | When you have finished, your complete Microsoft Entra SAML configuration for Honeycomb should look similar to our example: Complete Microsoft Entra SAML configuration for Honeycomb ## Configure Honeycomb Finally, configure SSO in Honeycomb using the Identity Provider settings you retrieved from your Identity Provider. Microsoft Entra provides a metadata URL, which allows Honeycomb to fetch the settings it needs and update them automatically. To automatically configure SSO in Honeycomb: 1. Switch to the browser tab that contains your Honeycomb Service Provider settings. 2. In Microsoft Entra, locate **App Federation Metadata Url** under the **SAML Certificates** section and copy it. 3. In Honeycomb, paste the **App Federation Metadata Url** you copied from your Identity Provider into **Identity Provider Metadata URL**. 4. You can also choose a **Default Role** to assign to new users joining your team through SSO. If you don't choose a default role, **Read-Only** will be the default role. 5. Select **Convert to SAML SSO Team**. You should see the SAML authentication flow begin. If successful, your team should now be able to use SAML SSO to authenticate. ## Log in to Honeycomb using your Microsoft Entra ID/ SAML SSO account To learn how to log in when Microsoft Entra ID / SAML SSO is configured for your Team, visit [Log in with SAML SSO](/get-started/honeycomb/log-in-with-saml-sso/). ## Certificate rotation When Honeycomb releases updated Service Provider certificates, you will see a warning notification in your team's SAML settings. To update to the new certificate, see [SAML Certificate Rotation](/configure/teams/configure-access/saml-certificate-rotation/). ## Troubleshooting To explore common issues when configuring access, visit [Common Issues with Configuring Honeycomb: Microsoft Entra ID SSO](/troubleshoot/common-issues/configuring-honeycomb/#microsoft-entra-id-sso). # Configure Access with Okta/SAML SSO Source: https://docs.honeycomb.io/configure/teams/configure-access/sso-okta-saml Require your Honeycomb Team to authenticate via Okta or another SAML 2.0 identity provider. EntPro This feature is available as part of the [Honeycomb Pro and Enterprise plans](https://www.honeycomb.io/pricing/). In Honeycomb, Team Owners can require that their team members authenticate using Single Sign-On (SSO) via an external SAML 2.0 Identity Provider, such as Okta. When you configure SSO via an external SAML Identity Provider, you must get information generated during the configuration process from both Honeycomb and your Identity Provider. Because you will also need to enter information into both Honeycomb and your Identity Provider's user interface, you will need to use more than one browser tab. In this guide, we demonstrate a typical SAML Identity Provider configuration using Okta. If you are using a different SAML Identity Provider, field names and locations may vary, so you will need to locate the corresponding fields in your Identity Provider's user interface. ## Before You Begin To successfully complete this guide, you should have an active [Okta](https://www.okta.com/) account. Once SSO is enabled for your Honeycomb Team, all users on your team will need to authenticate through that SSO provider to access the team. Any users that do not exist within your team's chosen SSO provider will not be able to log in. A Honeycomb account can be linked to more than one SAML IdP, so linking this account won't affect any existing IdP connections. ## Enable SSO in Honeycomb To begin, enable SSO in Honeycomb, which will allow you to get Honeycomb's Service Provider settings: 1. In Honeycomb, navigate to **Account** > **Team Settings**, and select the **Team Details** view. 2. Locate the **Single Sign-On** section, which displays any previous SSO configuration. 3. If your team is already configured to use Google SSO, turn off Google SSO. Turn off SSO 4. Select **Enable SSO**. Enable SSO 5. In the SSO provider configuration modal, select **SAML/Okta**, then select **Next**. 6. Locate the settings required by your Identity Provider. You will need: * Service Provider Issuer * Service Provider ACS URL * Service Provider Certificate (optional, used when your Identity Provider requires encrypted SAML assertions or signed authentication requests) Leave this browser tab open, so you will have the information you need to configure your Identity Provider later. SAML Honeycomb settings screen Honeycomb generates a unique identifier based on your team name. You will see the identifier appended to the values in the **Service Provider Issuer** and **Service Provider ACS URL** fields. For this example, the team name is "Crewbacca", so the team's generated identifier is `crewbacca`. ## Configure Your Identity Provider Next, configure your Identity Provider to work with Honeycomb. To do this, you must set up SSO for an application integration in your Identity Provider, and then specify which users should be able to use SSO to log in to your team in Honeycomb. In this section, we demonstrate a typical SAML Identity Provider configuration using Okta. If you are using a different SAML Identity Provider, field names and locations may vary, so you will need to locate the corresponding fields in your Identity Provider's user interface. ### Set Up SSO Set up SSO in your Identity Provider using the Service Provider settings you retrieved from Honeycomb: 1. Open a new browser tab, and go to your Okta admin console. 2. In Okta, go to **Applications** > **Applications**, and select **Create App Integration**. Create an application 3. In the sign-in method modal, select **SAML 2.0**, then select **Next**. 4. For **General Settings**, locate **App Name** and enter a name for your application, such as in the format `Honeycomb [Your Team Name]`, then select **Next**. Because you can have multiple Honeycomb teams connected to SSO and separate SSO configurations for each Honeycomb team, be sure the application name you choose clearly defines which team uses this SSO integration. The application name will appear in your application directory after installation. For this example, our team name is "Crewbacca", so we name our application `Honeycomb Crewbacca`. 5. For **Configure SAML**, locate the **SAML Settings** section, and enter your retrieved Honeycomb setting values according to the following mapping: | Okta Field | Honeycomb Setting Name | | ------------------------------- | ------------------------------------- | | **Single sign-on URL** | **Service Provider ACS URL** | | **Audience URI (SP Entity ID)** | **Service Provider Issuer/Entity ID** | Fill in SAML settings 6. Locate the **Attribute Statements** section, and add the following exact values, then select **Next**: Honeycomb reads the attribute names (`FirstName`, `LastName`, `Email`) from your SAML assertion, so they must match exactly with any Identity Provider. The **Value** column is Okta specific: it tells Okta which user profile field to send. For example, enter `user.email`, not the user's actual email address. | Name | Name format | Value | | ----------- | ------------- | ---------------- | | `FirstName` | `Unspecified` | `user.firstName` | | `LastName` | `Unspecified` | `user.lastName` | | `Email` | `Unspecified` | `user.email` | Fill in attribute statements 7. For **Feedback**, select the following values, then select **Finish**: | Field | Value | | ------------------------------------ | ---------------------------------------------------- | | **Are you a customer or a partner?** | `I'm an Okta customer adding an internal app` | | **Contact app vendor** | `It's required to contact the vendor to enable SAML` | 8. From the application's SSO settings, locate and copy the **Metadata URL**. You will need this information to configure Honeycomb. Sign on tab Although most modern SAML Identity Providers, like Okta, provide a Metadata URL, not all do. If your Identity Provider does not provide a Metadata URL, you must locate the required information to configure Honeycomb. Information you need includes: * Identity Provider Issuer * Identity Provider SSO URL * Identity Provider Certificate (optional, used when your Identity Provider requires signed authentication requests) ### Assign Users Assign users to the Honeycomb application in your Identity Provider: To finish your Honeycomb configuration, you must assign your own user account to the Honeycomb application in your Identity Provider. If you want, you can wait and add more users later. 1. Go to your new application, and select the **Assignments** view. 2. Select **Assign** > **Assign to People** or **Assign to Groups**, depending on whether you want to allow individual users or specific groups to log in to your team in Honeycomb. Select Assignments tab in your Honeycomb Application settings 3. In the group assignment modal, search for and select **Assign** next to the individual users or specific groups you want to allow to log in to your team in Honeycomb using SSO, then select **Done**. Remember to assign your own account to the application. 4. Confirm that the **Assignments** view reflects your selections. ## Configure Honeycomb Finally, configure SSO in Honeycomb using the Identity Provider settings you retrieved from your Identity Provider. Some Identity Providers, like Okta, provide a metadata URL, which allows Honeycomb to fetch the settings it needs and update them automatically. Other SAML Identity Providers may not provide metadata URLs. If your Identity Provider does not provide a metadata URL, you must configure Honeycomb manually and maintain its configuration settings. If your Identity Provider provided a metadata URL, like Okta does, automatically configure SSO in Honeycomb: 1. Switch to the browser tab that contains your Honeycomb Service Provider settings, locate the **Identity Provider Metadata URL**, and paste the metadata URL you copied from your Identity Provider. 2. You can also choose a **Default Role** to assign to new users joining your team through SSO. If you don't choose a default role, **Read-Only** will be the default role. 3. Select **Convert to SAML SSO Team**. SAML Honeycomb settings screen If your Identity Provider does not provide a metadata URL, you must configure Honeycomb manually with the information that you located from your Identity Provider: 1. Switch to the browser tab that contains your Honeycomb Service Provider settings, and select **Enter settings manually**. Notice that the **Identity Provider Metadata URL** field has been replaced by separate fields corresponding to the settings that Honeycomb requires. 2. (Optional) Choose a **Default Role** to assign to new users joining your team through SSO. If you don't choose a default role, **Read-Only** will be the default role. 3. Enter the retrieved Identity Provider setting values: * Identity Provider Issuer * Identity Provider SSO URL * Identity Provider Certificate (optional, used when your Identity Provider requires signed authentication requests) 4. Select **Convert to SAML SSO Team**. If a "SAML Assertion" error appears, verify that your SSO Identity Provider **Audience** and **Recipient** fields match your Honeycomb team settings SSO **Service Provider Issuer/Entity ID** and **Service Provider ACS URL** fields. The **Audience** field should contain: `https://ui.honeycomb.io/saml/`, while the **Recipient** field should contain: `https://ui.honeycomb.io/auth/callback/saml/`. SAML Honeycomb settings screen You should see the SAML authentication flow begin. If you configured Okta as your Identity Provider, you see an Okta animation. If successful, your team should now be able to use SAML SSO to authenticate. ## Log in to Honeycomb using your Okta / SAML SSO account To learn how to log in when Okta / SAML SSO is configured for your Team, visit [Log in with SAML SSO](/get-started/honeycomb/log-in-with-saml-sso/). ## Certificate rotation When Honeycomb releases updated Service Provider certificates, you will see a warning notification in your team's SAML settings. To update to the new certificate, see [SAML Certificate Rotation](/configure/teams/configure-access/saml-certificate-rotation/). ## Troubleshooting To explore common issues when configuring access, visit [Common Issues with Configuring Honeycomb: SAML SSO](/troubleshoot/common-issues/configuring-honeycomb/#saml-sso). # Customize Telemetry Schema Source: https://docs.honeycomb.io/configure/teams/customize-telemetry-schema Define a custom telemetry schema so that MCP tools understand your team's telemetry data and give AI agents accurate, team-specific context. [Honeycomb MCP tools](/integrations/mcp/concepts/) use attribute descriptions to understand your telemetry data. By default, these descriptions come from standard [OpenTelemetry semantic conventions](https://opentelemetry.io/docs/specs/semconv/) and Honeycomb's built-in attribute registry. If your team uses custom attributes, you can define descriptions for them so that AI agents understand what those attributes mean in the context of your system, giving them team-specific context when they search attributes, explore fields, or describe your data. ## How it works Honeycomb's attribute registry is a merged stack of three layers. Your team can customize the top layer to teach AI agents about your team's specific attributes. ### Custom attribute descriptions You define custom attribute descriptions for your team using a custom telemetry schema, a YAML-based configuration that overlays the standard OpenTelemetry and Honeycomb attribute definitions with your own. For a full list of supported fields, refer to the [Supported Fields](#supported-fields) section. ### Attribute resolution Honeycomb resolves attribute descriptions by merging three layers in order: 1. **OpenTelemetry base**: Standard [OpenTelemetry semantic conventions](https://opentelemetry.io/docs/specs/semconv/) (for example, `http.request.method`, `service.name`). 2. **Honeycomb overlay**: Honeycomb-specific field names produced during OTLP translation (for example, `duration_ms`, `samplerate`). 3. **Team overlay**: Your custom attribute descriptions, defined as a custom telemetry schema. When the same attribute appears in more than one layer, the later layer takes precedence. Your team overlay replaces any default description for attributes you define in it; all other attributes continue to use their standard definitions. ### Tools that use the registry The following MCP tools use the merged registry when they reason about your data: * `search_semconv` * `get_semconv_attribute` * `list_semconv_namespaces` * `get_dataset_columns` * `find_columns` * `get_workspace_context` ## Managing your registry Use the **Telemetry Schema** page in **Team Settings** to define, update, or remove your team's custom attribute descriptions. ### Viewing your registry To complete this task, you must be a [Team Owner](/configure/teams/manage-permissions/). Check your current registry to confirm what descriptions are active for your team before making changes. 1. Select **Account** from the navigation menu, then **Team Settings**. 2. Select the **Telemetry Schema** tab. If your team has already defined a registry, it appears in the editor. If not, the editor is empty and ready for input. ### Creating or updating your registry To complete this task, you must be a [Team Owner](/configure/teams/manage-permissions/). Add or update your registry to give AI agents richer context about your team's custom attributes the next time they explore your telemetry data. 1. Select **Account** from the navigation menu, then **Team Settings**. 2. Select the **Telemetry Schema** tab. 3. Enter or paste your registry YAML into the editor. The YAML must follow the [OpenTelemetry Weaver format](https://github.com/open-telemetry/weaver). For a full list of supported fields, refer to the [Supported Fields](#supported-fields) section. 4. Select **Save Schema** to save a new registry, or **Update Schema** to replace an existing one. Honeycomb validates the YAML against the OpenTelemetry Weaver schema before saving. If the YAML is invalid, an error message describes what went wrong. ### Deleting your registry To complete this task, you must be a [Team Owner](/configure/teams/manage-permissions/). Delete your registry to remove all custom attribute descriptions for your team. 1. Select **Account** from the navigation menu, then **Team Settings**. 2. Select the **Telemetry Schema** tab. 3. Select **Delete Schema**. 4. Confirm the deletion in the dialog. MCP tools fall back to the standard OpenTelemetry and Honeycomb attribute descriptions. ## Registry format The custom telemetry schema uses the [OpenTelemetry Weaver YAML format](https://github.com/open-telemetry/weaver), the same format used by the OpenTelemetry project to define semantic conventions. Each registry file contains one or more attribute groups. Each group has a unique ID, a type, a brief description, and a list of attributes. ### Example The following example defines three custom attributes for a commerce platform: ```yaml theme={} groups: - id: acme.commerce type: attribute_group brief: ACME commerce platform attributes attributes: - id: acme.order.priority type: string brief: Order fulfillment priority tier (standard, express, overnight) - id: acme.warehouse.region type: string brief: Regional warehouse code that processed the order - id: acme.cart.item_count type: int brief: Number of distinct items in the shopping cart at checkout ``` This example uses `id` to identify each attribute, which matches the Weaver-native registry format. You can paste a registry generated by the [Weaver CLI](https://github.com/open-telemetry/weaver) as-is, without renaming fields. For a full list of supported fields, refer to the [Supported Fields](#supported-fields) section. ### Supported fields The registry YAML supports the following fields for attributes and groups. #### Attribute fields Each attribute supports: | Field | Required | Description | | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `id` | Yes | The attribute identifier, which must exactly match the field name in your Honeycomb telemetry data. This is the Weaver-native field. Honeycomb also accepts `name` as an alias, which matches the field used in a resolved Weaver schema. | | `type` | Yes | The attribute type: `string`, `int`, `double`, `boolean`, `string[]`, `int[]`, `double[]`, or `boolean[]`. | | `brief` | Yes | A short description of the attribute. This is what MCP tools surface to AI agents. | #### Group fields Each group supports: | Field | Required | Description | | ------------ | -------- | ----------------------------------------------------------------------------- | | `id` | Yes | A unique identifier for the group, typically using dot-separated namespacing. | | `type` | Yes | Must be `attribute_group`. | | `brief` | Yes | A short description of the group. | | `note` | No | Additional context or usage notes for the group. | | `attributes` | Yes | The list of attributes in the group. | ## Best practices Follow these guidelines to get the most out of your custom telemetry schema. * **Name attributes to exactly match your field names**: The `id` value must match the field name in your Honeycomb telemetry data exactly for MCP tools to apply the description. * **Write briefs for someone unfamiliar with your system**: The `brief` field is what AI agents see. Describe what the attribute represents and what its values mean, not just what the name suggests. * **Group related attributes**: Use attribute groups to organize attributes by service, domain, or team. The group `brief` gives AI agents additional context about how those attributes relate to each other. * **Define only what you need to customize**: You only need to define attributes where you want to override or supplement the standard OpenTelemetry or Honeycomb attributes. # Investigate Team Activity Source: https://docs.honeycomb.io/configure/teams/investigate-activity Monitor how your team uses Honeycomb. Track team activity such as configuration changes, user logins & sessions, and statistics about the telemetry you send. Ent This feature is available as part of the [Honeycomb Enterprise plan](https://www.honeycomb.io/pricing/). The Activity Log is an environment for telemetry generated from your team's Honeycomb usage. In this environment, you can observe and investigate your team's activity using all of Honeycomb's features. The Activity Log Environment contains a dataset for the following resources: * [API Keys](#api-keys): create, update, delete, enable, and disable * [Boards](#boards): create, update, and delete * [Burn Alerts](#burn-alerts): create, update, delete, and state changes to/from `Triggered` * [Calculated Fields](#calculated-fields), otherwise known as Derived Columns: create, update, and delete * [OAuth Sessions](#oauth-sessions): create, update, and revoke * [Query Results](#query-results): completed query runs * [SLOs](#slos): create, update, delete, budget resets, and Service Level Indicator (SLI) expression updates * [Telemetry Stats](#telemetry-stats): aggregated statistics about the telemetry you send to Honeycomb, including rejections * [Triggers](#triggers): create, update, delete, and state changes to/from `Triggered` * [Users](#users): logins ## Report on All Team Activity You can interact with activity logs through reports. ### Access Activity Log Reports To access Activity Log reports, you must be a [Team Owner](/configure/teams/manage-permissions/). To access Activity Log reports: 1. Log in to the Honeycomb UI. 2. From the navigation bar, select **Account**, then select **Team settings**. 3. Select the **Activity Log** view. ### Export Activity Log Reports You can download all available team activity as a CSV file with a standard retention window of the last 60 days. Each entry in the CSV file includes: * Who performed the action * What time the action was performed * What kind of action was performed * Whether or not the action succeeded or failed To download your Activity Log reports: 1. Log in to the Honeycomb UI. 2. From the navigation bar, select **Account**, then select **Team settings**. 3. Select the **Activity Log** view. 4. Select **Download CSV**. #### File Schema The downloaded Activity Log CSV file uses the following schema and definitions. Not all attributes are relevant; only some may apply to each entry. * **timestamp**: Timestamp when the action was recorded by the system. * **resource.type**: Type of resource the log relates to. * **resource.action**: Create, Update, or Delete. In the case of certain resources, can be a system event. * **resource.id**: Unique identifier associated with the resource being modified, if applicable. * **environment.slug**: Slug (unique name) of the specific Honeycomb Environment associated with the entry, if applicable. * **dataset.slug**: Slug (unique name) of the specific Honeycomb Dataset associated with the entry, if applicable. * **changed\_fields**: For Create, Update, or Delete logs, attributes of the resource that changed. * **user.id**: User's ID if the log is the result of a user action. `System` if the log is the result of an automated action. * **user.email**: User's email address if a log is the result of a user action. * **user.ip\_address**: IP address that generated the log (only available on User Login entries). * **metadata**: Other information about the event or change, if available. ### Export Activity Log Data for a Specific Resource Each Dataset within your Activity Log Environment contains a stream of activity related to one resource. To investigate activity for a specific resource, you can export Activity Log data for the dataset that corresponds to the target resource. To download your Activity Logs for a particular dataset: 1. Log in to the Honeycomb UI. 2. In the left navigation menu, select **Manage Data**. 3. In the list, locate and select **Datasets**. 4. Select the **Activity Log** view. 5. Select **Download CSV**. To learn more about the information you can report on and the file schema, visit [File Schema](#file-schema). ## Investigate Team Activity Using Activity Log Datasets The Activity Log Environment contains various datasets housing streams of activity related to each supported resource. Within this Environment, team members can observe and investigate team activity with all of Honeycomb's features, including querying, visualizations, Boards, Triggers, and more. The standard retention period for this Environment is one year. ### Explore your Activity Log Environment Using Honeycomb to monitor your team activity opens up a wide range of possibilities to explore. All users on your team can access the Activity Log Environment and query its datasets in the Honeycomb UI, regardless of role. Only the downloadable reports in **Team settings** (described above) are limited to [Team Owners](/configure/teams/manage-permissions/). Through the [Honeycomb MCP server](/integrations/mcp/), the Activity Log Environment is available only to Team Owners. To access your Activity Log Environment: 1. Log in to the Honeycomb UI. 2. Select the **Environments** label on the top-left, then select **Activity Log**. 3. Begin querying the environment and its datasets. Available datasets include **api\_keys**, **boards**, **burn\_alerts**, **derived\_columns**, **oauth\_sessions**, **query\_results**, **slos**, **telemetry\_stats**, **triggers**, and **users**. List of datasets for the Activity Log environment shown through the Dataset scope dropdown window in Query Builder. We want to know the ways in which your team discovers and uses Activity Log data, but to help you get started exploring, check out the following ideas. #### Find Environment-wide Data To find the types of data available in your Activity Log Environment, run a query for **All datasets in activity log** with: | VISUALIZE | GROUP BY | | --------- | --------------- | | COUNT | `resource.type` | Display of described query in Query Builder. When querying, try using a `24 hour` (or `Last 1 day`) time range. Use the time picker to modify your time range. #### Explore Available Fields on Specific Datasets To learn about the fields available within a dataset: 1. Run an empty query on the target Dataset. 2. In Query Builder, use the **Events** view to view the contents of each event. In this display, each event is a row and each field is a column. 3. Use this information to construct and try different queries. ## Activity Log Datasets Each dataset in the Activity Log Environment contains a stream of activity for one resource type. Except for `telemetry_stats`, all datasets share a set of common fields: * `resource.type`, `resource.action`, and `resource.id`: the affected resource and what happened to it * `user.id` and `user.email`: who performed the action. `user.id` is `system` if the event is the result of an automated action, such as a Trigger firing. * `environment.slug` and `dataset.slug`: the Environment and Dataset the resource belongs to, if applicable * `resource.changed_fields` and `before.`: on updates, which fields changed and each field's prior value The following sections describe each dataset, along with example queries. ### API Keys The `api_keys` dataset records API key lifecycle events: `created`, `updated`, `deleted`, `enabled`, and `disabled`. Every event includes the key's `name`, its `key_type` (`legacy`, `ingest`, or `management`), and whether the key is currently `enabled`. Additional fields depend on the key type: * Ingest keys include `access.events` and `access.create_datasets`. * Management keys include their API `scopes`. * Legacy keys include the full set of `access.*` permission fields, and `visible_to_members`, which indicates whether non-admin team members can see the key. ### Boards The `boards` dataset records Board creation, updates, and deletion. Events include the Board's `name`, `description`, and `style`, its default filters and time range (`default.filters_json`, `default.start_time`, `default.end_time`, `default.granularity`), and `source`: the surface that created the Board, such as the UI, the API, or Slack. For private Boards, the name and description are redacted as `[private board]`, and default filters are omitted. ### Burn Alerts The `burn_alerts` dataset records Burn Alert configuration changes (`created`, `updated`, `deleted`) and state changes (`triggered`, `resolved`), which are attributed to `system`. Events include: * `alert_type`: `exhaustion_time` or `budget_rate` * `exhaustion_minutes`: the minutes-to-exhaustion threshold, on exhaustion-time alerts * `budget_rate_window_minutes` and `budget_rate_decrease_threshold_per_million`: the sliding window and threshold, on budget-rate alerts * `slo.id`, `slo.name`, and `sli.alias`: the parent SLO and its SLI ### Calculated Fields The `derived_columns` dataset records Calculated Field (Derived Column) creation, updates, and deletion. Events include the field's `alias`, `description`, and `expression`. When a changed expression belongs to a Calculated Field used as an SLI, a corresponding update event also appears in the [slos](#slos) dataset. #### Example: Find Calculated Field Experts Using Calculated Fields indicates advanced Honeycomb knowledge. Find your advanced Honeycomb users. Query the `derived_columns` dataset for `created` and `updated` actions to find out who develops Calculated Fields and uses them to explore data. To see who creates and updates Calculated Fields, run a query with: | VISUALIZE | WHERE | GROUP BY | | --------- | ------------------------------------- | ------------ | | COUNT | `resource.action` in created, updated | `user.email` | ### OAuth Sessions The `oauth_sessions` dataset records sessions for integrations that authenticate with Honeycomb through OAuth: session creation, updates, and revocation. Events include the `client_id` of the OAuth client, the requested and granted scopes (`scopes` and `oauth_session.granted_scopes`), and session timing fields such as `expires_at` and `invalidated_at`. Unlike most Activity Log datasets, OAuth session events are not scoped to an Environment or Dataset. ### Query Results The `query_results` dataset records one event for each completed query run from a user-facing surface, such as the UI, the public API, MCP, Slack, or a template link. Internal system queries are not recorded. The `resource.action` is always `created`. Each event describes the query itself, including `query.visualize`, `query.where`, `query.group_by`, `query.order_by`, `query.having`, `query.limit`, and `query.time_range.sec`, along with the `source` surface and the `user.email` of the person who ran it. #### Example: Find All Queries Run During Incidents The `query_results` dataset shows how many queries users run and their query patterns. To learn which datasets users interact with most, run a query with: | VISUALIZE | GROUP BY | | --------- | ---------------------------------------- | | COUNT | `environment.slug`
`dataset.slug` | To see what types of queries, or questions, that users ask during an incident, use the above query and select the time duration that maps to an incident window. #### Example: Find All Queries Run Using Specific Fields Ready to retire some data? Or are you curious about which parts of the datasets are used most? Query the `query_results` dataset to see which fields are most queried or if specific fields are queried. To see patterns of fields being used in queries, run a query with: | VISUALIZE | GROUP BY | | --------- | ------------- | | COUNT | `query.where` | Alternatively, use a different field for **GROUP BY** with this query, such as **GROUP BY** `query.group_by` or **GROUP BY** `query.havings`. ### SLOs The `slos` dataset records SLO creation, updates, and deletion, plus error budget resets (`resource.action` of `budget_reset`) and changes to the SLI expression. Events include the SLO's `name` and `description`, `sli.alias` (the Calculated Field that defines the SLI), `time_period_days`, and `target_per_million`. SLI expression changes include the new expression as `sli.expression` and the prior expression as `before.sli.expression`. ### Telemetry Stats The `telemetry_stats` dataset contains aggregated statistics about the events your team sends to Honeycomb, including rejections. Unlike the other Activity Log datasets, it records ingest telemetry rather than resource changes, so it does not include the common `resource.*` and `user.*` fields. Each record aggregates up to 10 minutes of ingest activity for one combination of destination dataset, outcome, API key, and event type. A record's sample rate is set to the number of events it represents, so a sample-rate-weighted COUNT reflects your true event volume. Interesting fields include: * `outcome`: `accepted`, `rejected`, or `error` * `event.type`: the kind of telemetry, such as `traces`, `logs`, or `metrics` * `error`: a normalized rejection or error message; when present on accepted events, indicates a data quality problem. Note the special `overflow` error indicates too many distinct field combinations to record, so only per-`outcome` totals are preserved. * `http.status`: the HTTP status Honeycomb returned * `api_key.name`: the name of the ingest key used * `dataset.slug` and `environment.slug`: where the events were sent * `event.field_count.avg`: the mean number of fields per event * `event.latency_seconds.avg` and `event.latency_seconds.max`: difference between the event's timestamp and time of receipt by Honeycomb; negative values indicate future-dated events * `dataset.field_count`: the number of columns in the destination dataset, a signal of schema size #### Example: Find Out Why Events Are Rejected To find out why events are being rejected, run a query with: | VISUALIZE | WHERE | GROUP BY | | --------- | -------------------- | -------- | | COUNT | `outcome` = rejected | `error` | ### Triggers The `triggers` dataset records Trigger creation, updates, and deletion, as well as `triggered` and `resolved` state changes, which are attributed to `system`. Display of resource.action attributes in results chart, which include triggered, resolved, updated, and created Every Trigger event includes: * `name` and `description` * `query.id`: the query the Trigger evaluates * `frequency`: how often the Trigger runs, in seconds * `threshold.value` and `threshold.operator`: the alert condition * `disabled` and `triggered`: the Trigger's current state #### Example: Find Sensitive Triggers Find sensitive triggers, or triggers that seem to fire more than expected or tend to auto-resolve. Once you find these triggers, consider improving their configuration to give more actionable alerts. Use the `triggers` dataset to identify how many times a trigger has fired in a given time period. To see which triggers fire often, run a query with: | VISUALIZE | WHERE | GROUP BY | | --------- | ----------------------------- | -------- | | COUNT | `resource.action` = triggered | `name` | ### Users The `users` dataset records user logins. Each successful authentication generates one event in the Activity Log of every team the user belongs to. The `resource.action` is always `authenticated`. Events include the `user.email` and `user.ip_address` of the person logging in, and the `authentication_method` used, such as password, SSO, or Google. # Manage Teams Source: https://docs.honeycomb.io/configure/teams/manage Create and manage Honeycomb Teams, which represent your organization, group users, grant data access, and build a shared query history. When you first join Honeycomb, you will be asked to create a Team, which will represent your organization in Honeycomb. Honeycomb uses Teams to organize groups of users, grant them access to data, and create a shared work history. You can manage your Honeycomb Teams using the Honeycomb UI. ## Create Team When you join Honeycomb, we help you create your first team during the signup process. To sign up, decide whether you would like Honeycomb to store your data in a US-based or EU-based location, then [create a Honeycomb account in the US](https://ui.honeycomb.io/signup) or [create a Honeycomb account in the EU](https://ui.eu1.honeycomb.io/signup). Signup is free! To create another Team: 1. Log in to the Honeycomb UI. 2. From the main navigation menu, select **Account** > **Switch Teams** > **Your teams**. 3. Locate the **Create Team** section. 4. Enter a name for your team. We recommend using your company or organization name as your Honeycomb team name. 5. Select **Create**. 6. When prompted, enter a name for the first Environment in your team. You should now be in your new Team. You are the first Team Owner, which gives you special permissions for your Team. To learn more about Team Owner permissions, visit [Manage Permissions](/configure/teams/manage-permissions/). # Manage Team API Keys Source: https://docs.honeycomb.io/configure/teams/manage-api-keys Create and manage Team-level Management API keys to control API keys across all Environments in your Team and set the scopes each key can access. Management API Keys allow you to manage API Keys at the Team level, which includes all API Keys for the Environments associated with your team. Create and manage these team-scoped Management API Keys through the Honeycomb UI. We require you to manually create a Management API Key. When you create a Management API Key, you assign it a set of scopes, which determine what actions the API Key can perform in the associated Team. Use Management API Keys to authorize the Key Management API. Refer to the [Key Management API documentation](/api/key-management/) for details. Any programmatic request sent to Honeycomb must use an API Key, but most Honeycomb APIs operate at the Environment level and require a [Configuration Key](/configure/environments/manage-api-keys/#find-api-keys) for resource management. To learn more about using API Keys, visit [Best Practices for API Keys](/get-started/best-practices/api-keys/). ## Find Management API Keys To find your existing Management API Keys: 1. Log in to the Honeycomb UI. 2. From the navigation bar, select **Account**, and then **Team Settings**. 3. Select the **API Keys** view. ## Create Management API Key To create a Management API Key, you must be a [Team Owner](/configure/teams/manage-permissions/). For security reasons, you can access the secret portion of your Management API Key only while creating it. You may be able to use the information you retrieve in this section to identify a key or its settings, so you can retrieve it from the safe location in which you previously stored it. To create your API Key: 1. Log in to the Honeycomb UI. 2. From the navigation bar, select **Account**, and then **Team Settings**. 3. Select the **API Keys** view. 4. Select **Create Management API Key**. 5. In the **Create Management API Key** modal, enter the details for your API Key: | Field | Description | | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | | Name | Label for the API Key. Used to identify this key in the Honeycomb UI. | | Scopes | Actions this key is allowed to perform on Honeycomb resources. For a full list of available scopes, visit [Management Key Scopes](#management-key-scopes). | Choose scopes carefully; they are permanent. To change scopes, you must delete the API Key and create a new one. 6. Select **Create**. 7. Copy your **Secret** and save it to a secure location. Honeycomb returns it only upon creation. Store your API keys securely and never check them into version control systems, such as Git. 8. Select **I've copied the secret**. 9. Optionally, copy your **Key ID**. You will need both your **Key ID** and **Secret** to authenticate requests to the API. Your **Key ID** is always available after creation, but your **Secret** is not. Your new API Key appears in the list of keys. To learn how to use your new key, visit [API Documentation: Authentication](/api/authentication). ## Disable Management Keys To disable a Management Key, you must be a [Team Owner](/configure/teams/manage-permissions/). To disable your Management Key: 1. Log in to the Honeycomb UI. 2. From the navigation bar, select **Account**, and then **Team Settings**. 3. Select the **API Keys** view. 4. In the list, locate the Management Key that you want to disable, and select **Details** to view its settings. 5. Locate the **Enable** checkbox, and deselect it. 6. Select **Save**. Your Management Key will appear grayed out in the list, but it may take several minutes for the process to complete. ## Delete Management Keys Management Key deletion is permanent, so make sure you really want to delete your Management Key before doing so. To delete a Management Key, you must be a [Team Owner](/configure/teams/manage-permissions/). To delete your Management Key: 1. Log in to the Honeycomb UI. 2. From the navigation bar, select **Account**, and then **Team Settings**. 3. Select the **API Keys** view. 4. In the list, locate the Management Key that you want to delete, and select **Details** to view its settings. 5. Select **Delete**. 6. In the **Delete Management API Key?** modal, enter the name of the Management Key (located above the field). 7. Select **Delete**. Your Management Key will no longer appear in the list, but it may take several minutes for the process to complete. ## Management Key Scopes You can control the actions that a Management API Key may perform in your Team at a more granular level. You cannot change scopes assigned to a Management Key after the key has been created. Management Keys can be deleted. ### API Keys | Scope | Description | | -------------------- | --------------------------------------------------------------------------------------- | | `api-keys:read` | Grants `list` and `view details` to the team's API Keys. | | `api-keys:write` | Grants `create`, `list`, `update`, `delete` and `view details` for the team's API Keys. | | `environments:read` | Grants `list` and `view details` to the team's Environments. | | `environments:write` | Grants `create`, `list`, `update`, and `view details` for the team's Environments. | # Manage Team Behavior Source: https://docs.honeycomb.io/configure/teams/manage-behavior Set your Team's default environment, enable or disable the Query Assistant, and manage which external URLs appear as links across your Honeycomb Team. Each Honeycomb Team, which represents your organization in Honeycomb, allows its Team Owners to manage its behavior. Team Owners can set their Team's default environment, enable or disable the Query Assistant, and manage which URLs are displayed as external links for your team. ## Set default environment Set the default environment that Team members should land in when they are new to the Team or when Honeycomb can't identify their last environment. Only Team Owners can set a default environment. To set your team's default environment: 1. Select **Account** from the main navigation menu, then select **Team settings**. 2. On the **Team Details** view, locate the **Environments and API Keys** section. 3. Select the default environment from the dropdown. Honeycomb saves your changes automatically. ## Manage Honeycomb Intelligence [Honeycomb Intelligence](/get-started/honeycomb/honeycomb-intelligence) is a suite of AI-powered features built into Honeycomb. Team Owners can enable or disable Honeycomb Intelligence at any time. When disabled, no Honeycomb Intelligence features are active, including features that surface insights passively. Only Team Owners can enable or disable Honeycomb Intelligence. ### Enable Honeycomb Intelligence Turn on Honeycomb Intelligence to make all Honeycomb Intelligence features available to your Team. 1. Select **Account** from the navigation menu, then **Team settings**. 2. On the **Team Details** view, locate the **Honeycomb Intelligence** section. 3. Select ** Turn on**. The button updates to ** Turn off**, confirming that Honeycomb Intelligence is now enabled for your Team. ### Disable Honeycomb Intelligence Turn off Honeycomb Intelligence to deactivate all Honeycomb Intelligence features for your Team, including features that surface insights passively. 1. Select **Account** from the navigation menu, then **Team settings**. 2. On the **Team Details** view, locate the **Honeycomb Intelligence** section. 3. Select ** Turn off**. The button updates to ** Turn on**, confirming that Honeycomb Intelligence is now disabled for your Team. ## Manage Allowed Web Domains Team Owners can control which URLs they want Honeycomb to display as external links by adding domains to the web domain allowlist. Honeycomb compares the web domain allowlist against URLs in your Honeycomb instance to determine whether we should display a URL as an external link rather than as static text in the Query Builder, the Explore Data tab, and the Trace View. Honeycomb notifies all Team Owners any time a change is made to the web domain allowlist. **Scenario:** You add `honeycomb.io` to your Team's web domain allowlist. **Outcome:** Honeycomb will display the following URLs as external links in the UI: * `https://ui.honeycomb.io` * `https://www.honeycomb.io` * `https://honeycomb.io` * `https://honeycomb.io/about` Honeycomb will display the following URLs as static text in the UI: * `https://malicioushoneycomb.io` (allowed domain is `honeycomb.io`, not `malicioushoneycomb.io`) * `https://ui.malicioushoneycomb.io` (allowed domain is `honeycomb.io`, not `malicioushoneycomb.io`) * `clickherehttps://honeycomb.io` (valid protocol is `https`, not `clickherehttps`) * `honeycomb.io` (no protocol provided) * `https://honeycomb.io clickhere` (string contains a valid URL but is not a valid URL itself) To learn about criteria for valid domains and URLs, visit [Team Settings: Valid Domains and URLs](/reference/honeycomb-ui/account/team-settings/#valid-domains-and-urls). Only Team Owners can manage allowed web domains. ### Add allowed web domains Add a domain to the allowlist to let Honeycomb display URLs from that domain as external links across your Team. 1. Select **Account** from the navigation menu, then **Team settings**. 2. On the **Team Details** view, locate the **Manage allowed domains** section. 3. Select the **Web domains** view. 4. Enter a domain, then select **Add domain**, and confirm that the web domain allowlist now contains your entry. To learn more about domain validation rules, visit [Team Settings: Valid Domains and URLs](/reference/honeycomb-ui/account/team-settings/#valid-domains-and-urls). The domain appears in the allowlist. ### Remove allowed web domains Remove a domain from the allowlist to stop Honeycomb from displaying URLs from that domain as external links across your Team. 1. Select **Account** from the main navigation menu, then select **Team settings**. 2. On the **Team Details** view, locate the **Manage allowed domains** section. 3. Select the **Web domains** view. 4. Locate the web domain you want to remove in the allowlist, and select **Remove**. The domain no longer appears in the allowlist. # Manage Team Members Source: https://docs.honeycomb.io/configure/teams/manage-members Invite, remove, and update roles for members of your Honeycomb Team, and restrict who can join. The Team Owners for a Honeycomb Team can manage their Team's members. Team Owners can invite users, remove users, change users' roles, copy invitation URLs, and restrict who can join their Team by email address. ## Invite Team Members If you are a Team Owner, you can invite users to your Team directly, or you can share an invitation URL to allow new Honeycomb users to request access to your Team. If you have configured allowed email domains for your Team, then only users with email addresses that match allowed domains can join your team. To learn how to configure allowed email domains, visit [Manage Allowed Email Domains](#manage-allowed-email-domains). ### Invite Team Members Directly #### Non-Enterprise Plans To invite a Team Member directly: 1. Log in to the Honeycomb UI. 2. From the main navigation menu, select **Account** > **Team settings**. 3. Select the **Users** tab 4. Select **Invite user**. 5. In the dialog, enter the email address of the user you want to invite to your Team, then select **Invite**. You can invite multiple users at once by entering multiple email addresses separated by commas (for example, `email1@example.com,email2@example.com`). New members will receive Member permissions when they accept the invite #### Enterprise Plans To invite a Team Member directly: 1. Log in to the Honeycomb UI. 2. From the main navigation menu, select **Account** > **Team settings**. 3. Select the **Users** tab. 4. Select **Invite user**. You'll be taken to a dedicated invite page. 5. Enter the user's email address. 6. Configure their access: * Check **"Grant Owner team-level access"** to invite them as an Owner, OR * Leave unchecked and configure: * **Team-Level Access:** Select Member or Read-Only for team-level resources (Settings, Usage, Pipelines, Canvas) 7. Select **Invite user** to send the invitation. ### Copy Invitation URL To copy the Team Invitation URL: 1. Log in to the Honeycomb UI. 2. From the main navigation menu, select **Account** > **Team settings**. 3. Select the **Users** tab. 4. Select **Team URL** button. 5. Select the Copy icon () to copy the Team Join URL. If a user requests access through an invitation URL, a Team Owner must approve the user's request before Honeycomb will add the user to the Team. ## Manage Pending Invitations The **Pending invitations** section displays invites that have been sent but not yet accepted. For each pending invitation, Team Owners can: * **Resend** - Send another invitation email (useful if the invite expired or wasn't received) * **Delete** - Cancel the invitation The status column shows when the invite was sent or if it has expired. ## Approve Join Requests The **Join team requests** section displays users who have requested to join your team via the Team Join URL. ### Non-Enterprise Plans For each join request, Team Owners can: * **Accept** - Immediately adds the user to your team with Member permissions * **Decline** - Rejects the join request ### Enterprise Plans For each join request, Team Owners can: * **Approve** - Opens a dedicated approval page where you configure the user's permissions before adding them * **Decline** - Rejects the join request **To approve a join request:** 1. From the **Join team requests** section, select **Approve** next to the join request. 2. On the approval page, configure the user's access: * Check **"Grant Owner team-level access"** to add them as an Owner, OR * Leave unchecked and configure: * **Team-Level Access:** Select Member or Read-Only 3. Select **Approve user** to complete the approval. ## Manage Allowed Email Domains If you are a Team Owner, you can control the domains from which Honeycomb will allow users to join your Team by adding domains to the email domain allowlist. Honeycomb compares the email domain allowlist against user email addresses to determine whether a user may join your team. Honeycomb notifies all Team Owners any time a change is made to the email domain allowlist. **Scenario:** You add `example.com` to your Team's email domain allowlist. **Outcome:** Honeycomb will allow anyone with an email address that ends in `example.com` to join your team. For example, a user with email address `user@example.com` can join. If no allowed email domains have been configured, users with any email address may join your Team. ### Add Allowed Email Domains To add an allowed email domain: 1. Log in to the Honeycomb UI. 2. From the main navigation menu, select **Account** > **Team settings**. 3. Locate the **Manage allowed domains** section. 4. Select the **Email domains** view. 5. Enter a domain, then select **Add domain**, and confirm that the email domain allowlist now contains your entry. To learn more about domain validation rules, visit [Team Settings: Valid Domains and URLs](/reference/honeycomb-ui/account/team-settings/#valid-domains-and-urls). ### Remove Allowed Email Domains To remove an allowed email domain: 1. Log in to the Honeycomb UI. 2. From the main navigation menu, select **Account** > **Team settings**. 3. Locate the **Manage allowed domains** section. 4. Select the **Email domains** view. 5. Locate the email domain you want to remove in the allowlist, and select **Remove**. ## Manage Team Member Roles If you are a Team Owner, you can assign roles to other users in your Team. Roles include Owner and Member (Enterprise plans also include Read-Only). To learn more about the permissions granted to each role, visit [Team Permissions](/configure/teams/manage-permissions/). To assign a role to a Team Member: 1. Log in to the Honeycomb UI. 2. From the main navigation menu, select **Account** > **Team settings**. 3. Select the **Users** tab. 4. In the users table, locate the user for whom you want to change the role, and select the desired role from the **Role** column. 5. If prompted, confirm changes. ## Remove Team Members If you are a Team Owner, you can remove Team Members from your Team. To remove a Team Member: 1. Log in to the Honeycomb UI. 2. From the main navigation menu, select **Account** > **Team settings**. 3. Select the **Users** tab. 4. In the users table, locate the user that you want to remove, and select the trash icon in the **Actions** column at the end of the row 5. Confirm by selecting **Yes, remove**. # Manage Team Notifications Source: https://docs.honeycomb.io/configure/teams/manage-notifications Control which Team Owners receive usage notifications and configure integrations and webhooks to route Honeycomb alerts to your preferred channels. ## Email Notifications **Email notifications** control which Team Owners will receive usage notifications. Owners can select **Change** to modify the list of notification recipients. Honeycomb sends usage notifications for the following events: * billing enforcement, such as burst protection, event count overages and throttling events * event ingest rate limiting * dataset created or deleted * datasets exceeding the maximum number of fields limit * environments exceeding the maximum number of datasets limit ## Integrations Within **Integrations**, view and configure third-party integrations and webhooks for notification purposes. The **Honeycomb + Slack** and **Honeycomb + GitHub** sections indicate their respective integration's implementation status. Use the Slack integration to share [Trigger](/notify/triggers/) and [SLO](/notify/slos/) notifications in your Slack workspace. Use the GitHub integration with [GitHub Deployment Protection Rules](/integrations/github-deployment-protection-rules/). In **Trigger Notifications**, add, remove, or edit team-level integration settings for [Triggers](/notify/triggers/). Use the search box to search for specific trigger recipients. Read the detailed instructions to set up your team-level [trigger recipients](/notify/), such as Slack, PagerDuty, Microsoft Teams, and Webhooks. # Manage Team Permissions Source: https://docs.honeycomb.io/configure/teams/manage-permissions Apply roles and permissions to Honeycomb Team members to control access to datasets, environments, and administrative functions across your organization. Honeycomb uses a tiered system of access control to provide granular access to its endpoints. Honeycomb's mission is to empower engineering **teams** to debug production systems. Many defaults are chosen to enable and support the ambient broadcasting and sharing of knowledge. Our permissions philosophy centers around minimizing behaviors that may be destructive or disruptive to fellow team members' query activity. ## Types of Roles in Honeycomb * **Team Owners** control billing and destructive actions for the team. Owners are also able to override member privacy settings. * **Team Members** are able to view all public resources, add metadata, and make non-destructive configuration changes at the dataset level. * **Read-Only** (the default role for everyone) can view all public resources and interactively query data in Honeycomb but cannot perform create, update, or delete actions anywhere in the team. ## Team Membership and Billing | | Owner | Member | Read-Only | | --------------------------------------- | ----- | ------ | --------- | | Promote other team owners | ✔ | | | | Make team SSO-only | ✔ | | | | Upgrade and adjust pricing | ✔ | | | | Invite new users / accept join requests | ✔ | | | | Create new teams | ✔ | ✔ | ✔ | | Create, edit, and disable API keys | ✔ | | | | Delete ingest API keys | ✔ | | | | Redact API keys | ✔ | ✔ | | | View redacted API keys | ✔ | | | | View non-redacted API keys | ✔ | ✔ | | ## Environments Environments can only be created by a team owner. | | Owner | Member | Read-Only | | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----- | ------ | --------- | | Create environment | ✔ | | | | Edit environment display
*For example, environment descriptions.* | ✔ | ✔ | | | View and query the [Activity Log](/configure/teams/investigate-activity/) Environment
*Available as part of the [Honeycomb Enterprise plan](https://www.honeycomb.io/pricing/).* | ✔ | ✔ | ✔ | | Download Activity Log reports from Team settings
*Available as part of the [Honeycomb Enterprise plan](https://www.honeycomb.io/pricing/).* | ✔ | | |
Honeycomb Classic uses a dataset-only data model and does not include Environments. Learn more about [Honeycomb versus Honeycomb Classic](/troubleshoot/product-lifecycle/recommended-migrations/#migrate-from-honeycomb-classic-to-honeycomb-environments). ## Datasets Datasets may be queried on by any member of the team and query history is visible to all members of the team. | | Owner | Member | Read-Only | | -------------------------------------------------------------------------------------------- | ----- | ------ | --------- | | Run queries | ✔ | ✔ | ✔ | | Annotate queries | ✔ | ✔ | | | Delete a dataset | ✔ | | | | Toggle deletion protection | ✔ | | | | Edit dataset ingest settings
*For example, nested JSON.* | ✔ | | | | Edit dataset schema settings
*For example, field types, field max lengths.* | ✔ | ✔ | | | Edit dataset display
*For example, field descriptions, dataset descriptions, aliases.* | ✔ | ✔ | |
## Boards Boards can be created by team members and team owners and default to being public. Any public boards will be viewable to everyone in your team and will be modifiable by team members and team owners. Boards marked as \***Restricted (Collaborators and owners only)** are visible only by the creator and any team owners. The board owner may take the board public at any time. Other members will not be able to add or edit queries to a limited access board unless explicitly added as a collaborator by the owner. | | Owner | Member | Read-Only | | ------------------------------------------- | ----- | ------ | --------- | | Create public boards | ✔ | ✔ | | | View public boards | ✔ | ✔ | ✔ | | Create limited access boards | ✔ | ✔ | | | Make limited access boards public | ✔ | ✔ | | | Add collaborators to a limited access board | ✔ | ✔ | | | Add queries and metadata to boards | ✔ | ✔ | | | Edit queries and metadata on boards | ✔ | ✔ | | | View anybody's limited access board | ✔ | | | | Delete public boards | ✔ | ✔ | | | Delete anybody's limited access board | ✔ | | | ## Triggers Triggers are viewable by all members in a team. Triggers are creatable and editable for team members but not for read-ony users. Clear attribution on triggers communicate which user created or last edited a particular trigger. [Read more about Triggers](/notify/triggers/) | | Owner | Member | Read-Only | | -------------------- | ----- | ------ | --------- | | Create triggers | ✔ | ✔ | | | View triggers | ✔ | ✔ | ✔ | | Edit/delete triggers | ✔ | ✔ | | ## Calculated Fields Calculated fields, otherwise known as Derived Columns, may be created on a Dataset or an Environment by team members and team owners. As with boards, calculated fields may only be deleted by the creator or a team owner. Everyone in the team can view calculated fields. [Read more about Calculated Fields](/configure/environments/calculated-fields/). | | Owner | Member | Read-Only | | -------------------------------- | ----- | ------ | --------- | | Create calculated fields | ✔ | ✔ | | | Edit calculated fields | ✔ | ✔ | | | Delete own calculated field | ✔ | ✔ | | | Delete any calculated field | ✔ | | | | View calculated fields in schema | ✔ | ✔ | ✔ | ## Canvas Canvas allows team members to create collaborative workspaces for investigations and analysis. All users can create and view private Canvases, while team members and owners can also create public Canvases and collaborate on shared work. | | Owner | Member | Read-Only | | --------------------------- | ----- | ------ | --------- | | Create private Canvases | ✔ | ✔ | ✔ | | View private Canvases (own) | ✔ | ✔ | ✔ | | Create public Canvases | ✔ | ✔ | | | View public Canvases | ✔ | ✔ | | | Edit own Canvases | ✔ | ✔ | ✔ | # Monitor Team Use Source: https://docs.honeycomb.io/configure/teams/monitor-use Track your Team's event volume and throughput trends, and access enhanced usage reporting to monitor costs and plan capacity. **[Usage](/reference/honeycomb-ui/account/team-settings/#usage)** shows details and trends about your team's event volume and throughput. Usage can also be accessed directly via the [Usage icon () in the left navigation](/reference/honeycomb-ui/usage/). ## Enhanced Reporting **Enhanced Reporting** is visible if you are a [Honeycomb Enterprise customer](https://www.honeycomb.io/pricing/). Enhanced Reporting shows a variety of information through graphs, charts, and statistics on your Honeycomb Events Ingest, Queries, and more. # Change Pricing Plan Source: https://docs.honeycomb.io/configure/teams/pricing-plan Upgrade, downgrade, or switch your Honeycomb pricing plan at any time to match your team's event volume and feature requirements. Choose the plan that fits your team's needs. Update your Honeycomb pricing plan at any time. Upgrade to access higher event volume and advanced features, switch between paid plans, or downgrade to a different plan level as your requirements change. ## Before you Begin Before you change your pricing plan, make sure you have: * **A Honeycomb account.** If you don't have an account yet, sign up for a Free plan: * [Create a US account](https://ui.honeycomb.io/signup) * [Create an EU account](https://ui.eu1.honeycomb.io/signup) Your account region determines where Honeycomb stores your data. Choose US-based or EU-based storage based on your data residency requirements. * **Team Owner role.** Only Team Owners can change billing settings and update plans. ## Compare Available Plans Honeycomb offers multiple plan levels to fit different team sizes and needs: * **Free:** Get started with core observability features at no cost. * **Pro:** Access flexible event volume tiers and advanced features. * **Enterprise:** Customize a solution for large-scale deployments. For detailed feature comparisons and pricing information, visit [Honeycomb Pricing Plans](https://www.honeycomb.io/pricing). ## Change Your Plan To complete this task, you must be a [Team Owner](/configure/teams/manage-permissions/). To change your Team's pricing plan: 1. Select **Account** (your avatar) from the navigation menu, then choose **Team Settings**. 2. On the **Team Settings** page, select the **Billing** view. The **Billing** view shows your current plan and billing information. Screenshot showing the Billing tab with current plan information and Update Plan button 3. Select **Update Plan**. 4. On the **Select Your Plan** page, review the available plans and select **Select Plan** next to your preferred option. Screenshot showing available plan tiers with Select Plan buttons Enterprise plans offer custom configurations and pricing. To explore Enterprise options, select **Contact Sales**. 5. Select **Add Payment** to continue to the payment details page. 6. Enter your payment information: * Credit card number, expiration date, and security code * Billing address associated with your credit card * Promo code (if you have one) Screenshot showing the Add Payment Method page with credit card and billing address fields 7. Choose your billing cycle: * **Monthly:** Pay each month. * **Yearly:** Pay annually (typically includes a discount). 8. Review the Terms of Service, then select **Add Payment**. 9. In the confirmation modal, review both your current plan and selected plan details, then select **Confirm**. Screenshot showing the confirmation modal with current and selected plan comparison After you confirm, Honeycomb returns you to the **Billing** view. Your new plan appears immediately, and your billing history updates with the purchase date and status. # Get Started: Overview Source: https://docs.honeycomb.io/get-started Instrument your app, send telemetry to Honeycomb, and start debugging with high-cardinality observability. Choose your path and get up and running fast. Welcome to Honeycomb! We're happy to see you. ## Start Building Get up and running with Honeycomb for your application. Learn how to easily add instrumentation and use Honeycomb to observe and understand your application. Start sending your mobile and web application telemetry from Embrace to Honeycomb. Learn how to easily add Honeycomb to your Kubernetes cluster. Explore our free, interactive demo. Choose your own path: analyze and debug an issue, explore a service map, or correlate app and Kubernetes errors. Use example applications to quickly learn about Honeycomb. ## Observability Fundamentals Find out what observability is and why it changes how you debug production software. Build a foundation in the concepts of modern observability. ## Honeycomb Basics Learn what Honeycomb is, what problem it solves, and how its core concepts fit together. Understand the telemetry signals Honeycomb supports, how each one works, and how they fit together. Learn how Honeycomb handles log data, how logs relate to traces and metrics, and how to get the most out of your log data. Learn how Honeycomb handles metrics data, how metrics relate to traces and logs, and when to use metrics in your observability practice. Learn about our AI-powered suite of features that surface insights from your telemetry so you can investigate faster and resolve incidents with confidence. Cycle through your telemetry dimensions, form hypotheses, and validate them with data. Learn how to debug any system from first principles. Understand the organizational structure of Honeycomb: teams, environments, datasets, and events. Get familiar with the Honeycomb interface. Learn how to log in, navigate the UI, and find your way around your team's environments, datasets, and query history. Run the full Honeycomb observability platform in your own infrastructure for enhanced data governance, regulatory compliance, and infrastructure control. Find out how Honeycomb secures its infrastructure, protects your data, maintains compliance certifications, and approaches AI features responsibly. ## Plan & Design Explore Honeycomb's recommendations for working with our product. Understand how Honeycomb measures usage, predicts and handles overage, and retains data. # Best Practices Source: https://docs.honeycomb.io/get-started/best-practices Get Honeycomb's recommendations for organizing data, managing API keys, writing effective alerts, working with SLOs, and getting the most out of your implementation We recommend that you follow certain best practices when using Honeycomb. Explore Honeycomb's recommendations for organizing your data into datasets and environments. Explore Honeycomb's recommendations for working with API keys. Explore Honeycomb's recommendations for using the Honeycomb OpenTelemetry Web SDK in applications with a Micro Frontend architecture. Explore Honeycomb's recommendations for querying using relational fields. Explore Honeycomb's recommendations for alerting on triggers and Service Level Objectives (SLOs). Explore Honeycomb's recommendations for using Service Level Objectives (SLOs). # Best Practices for Alerts Source: https://docs.honeycomb.io/get-started/best-practices/alerts Get Honeycomb's recommendations for writing effective alerts: how to name and describe triggers, set thresholds, and reduce alert fatigue with SLO-based alerting. We recommend that you follow certain best practices when creating alerts. ## Triggers * Use the Name and Description fields effectively. The Name field should tell you **what** the alert is; the Description field should tell you what to **do** about the alert. Links to internal wikis or runbooks are best. * Use filters to improve the quality of your signal. If you are interested in latency, but have a long poll endpoint, use a filter to remove that endpoint from the calculation rather than adjusting the values of the threshold. * To detect spikes in latency metrics, combine a filter with your cutoff (for example, `>100ms`) with a `COUNT`. Your result will be the number of events that exceed your threshold. * To ignore spikes in latency and trigger on overall performance, use the `P95` or `P99` calculations. These will be more representative of the majority of traffic than `AVG`, which can be polluted by large outliers. * When detecting errors, allow good values instead of looking for bad values. For example, instead of building a filter of HTTP status codes `== 500`, use several filters to look for events that do not have status codes `200`, `301`, `302`, or `404`. ## SLOs Some of these are general guidelines, and some are specific to alert type. ### General Guidelines Regardless of the alert type: * Iterate when creating [Burn Alerts](/notify/slos/monitor/#burn-alert-types). Start by sending alerts to an internal recipient (either a team member's email address or a private Slack channel) to monitor the frequency of alerts in your system. Use these Burn Alerts as a first step toward understanding how your service performs and what kinds of alerts are actionable and important to your team, and then iterate. * Start with the shape of the signal that you care about: * For slow SLO burn, you care about issues that occur over a prolonged time period. * For fast SLO burn, you care about significant spikes over a shorter time period. * Use alerts to refine any new SLOs that you create. For new SLOs, start with a Budget Rate alert, which will notify you when system conditions impact your budget, to learn: * If you are missing any criteria in your SLI. * If you can historically sustain your SLO. ### Exhaustion Time Burn Alerts When choosing the length of time for a given Budget Exhaustion burn alert, consider the context and goals of your organization. Ask questions to help frame the definition of some initial Exhaustion Time burn alerts. If you are X hours away from running out of budget: * Who would need to know * Via what method * What would they need to do For example, a 24-hour exhaustion time alert can be useful if service quality is slowly degrading and a Slack-based notification allows the team to remediate the issue before the budget reaches zero (`0`). Alternatively, a 4-hour exhaustion time alert may be more urgent and require a pager notification, such as from PagerDuty. We recommend creating at least one Exhaustion Time burn alert where the Exhaustion Time is `0`. This will notify you when your SLO budget is completely exhausted. ### Budget Rate Burn Alerts When starting with a Budget Rate burn alert, consider whether you seek an alert for a smooth, slow burn or a fast, abrupt drop. Start with a less-sensitive alert and adjust as needed. Depending on the length of your SLO's time period, try these values when creating Budget Rate burn alerts. #### 30 Day SLO Example Use the following example to create a series of Budget Rate burn alerts for your SLO. Each row represents an alert and its values. | Budget Decrease (%) | Time Window | Notification Type | | ------------------- | ----------- | ----------------- | | 2% | 1 hour | PagerDuty | | 5% | 6 hour | PagerDuty | | 10% | 3 days | Slack | #### 7 Day SLO Example Use the following example to create a series of Budget Rate burn alerts for your SLO. Each row represents an alert and its values. | Budget Decrease (%) | Time Window | Notification Type | | ------------------- | ----------- | ----------------- | | 8.5% | 1h | PagerDuty | | 21.5% | 6h | PagerDuty | | 43.20% | 3 days | Slack | | 50% | 3.5 days | Slack | #### Use the Time Window to Determine the Notification Method A long Time Window, such as 24 hours, is useful in detecting long, slow burns that use up your SLO budget faster than expected, but not fast enough to wake someone out of bed. A short Time Window, such as one hour, is useful in detecting very fast SLO budget burns that need to be addressed quickly. Use the time window to determine the alert method. For example: * For a long, slow SLO budget decrease, send a Slack message, so the issue can be addressed during business hours. * For a short, fast SLO budget decrease, send a critical PagerDuty notification, so it can be acted on immediately. Although it may be counterintuitive, a Budget Rate alert with a long time window will also activate on a short, fast burn. For example, if you have two Budget Rate burn alerts with the parameters: * Notify when the Budget Decrease exceeds 25% over a **24** hour period * Notify when the Budget Decrease exceeds 25% over a **1** hour period If your environment encountered a large spike of errors and burned 25% of your SLO budget in the last hour, both the 24-hour Budget Rate burn alert and the 1-hour Budget Rate burn alert will fire, because both include the last hour in their calculation. You might ask, since both Burn Alerts activated, why do you need both? You need both if you want to control where the Burn Alert notifies. #### Use Budget Decrease to Control Alert Frequency To control the frequency of your Burn Alert and calibrate its sensitivity: * Increase the Budget Decrease value if the alert is too noisy. * Decrease the Budget Decrease value if the alert is too quiet. ## Guidelines for when to use SLOs and Trigger Alerts In highly dynamic systems, attention is a scarce resource. There are more signals than you can process, and large systems often have ongoing issues. Even with a team, it is impossible to handle everything. You cannot grasp the entire system, and you should not be expected to. SLOs and trigger alerts can help, but to make them most efficient, you should implement them with some general rules in mind. ## General Guidelines To manage your scarce attention effectively: * **Design thoughtful alerts**: Create alerts that do not compete aggressively for your attention. They should only interrupt you for genuinely important matters, similar to how you would respond to a busy colleague. * **Prioritize interrupts**: Use monitoring and alerting systems to direct your attention when needed but avoid distracting you unnecessarily. Remember the principle: "Treat the patient, not the alarm." ### Prioritize users who will be directly impacted Prioritize anyone who has a vested interest and who will be directly impacted. This almost always includes customers, and for development and deployment flows, this also includes other engineers. Your on-call structure means that one or two people already respond for many services. Setting an SLO for a specific microservice will not prevent someone else from being paged--only the same people on the same rotation. ### Prioritize issues that may surface bigger conversations The second-order goal of an SLO is to serve as a guide when discussing how to allocate engineering effort. If you are starting to slip on your ability to properly serve your users, you need to discuss what type of work you prioritize. The best SLO candidates are issues that, if unresolved, may surface bigger conversations throughout your organization. ### Limit pager notifications Rather than notifying via pager for all alerts, consider perceived urgency and time of day. For a discussion of pager notification for specific alert types, see the [Pager Notifications](#pager-notifications) section. ## Example Errors and Alert Types Because SLOs and Triggers work similarly (repetitively check for a bad value threshold to be crossed, then warn), choosing when to use each can be difficult. The choice becomes more difficult because SLOs can encompass a wide range of "users", including customers, coworkers, and other services. In the following table, we discuss the most common types of errors and our recommendations. | Type | Description | Example | What should be used | Comment | | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Error Rates | Identify whether customer-visible interactions succeed. | Could the user access their data? | SLOs | Ignore failures outside of your control since you cannot fix them. Often combined with performance indicators. | | Performance | Identify whether customer-visible interactions happen within a delay you judge to be acceptable. | Did you retrieve account history within 10 seconds? Are you processing incoming transactions within N milliseconds? | SLOs | Try to find measures that adjust to expected cost (for example, "we expect some complex queries to take longer"). Often combined with error rates. | | Assertions and pre/post conditions | Identify whether some internal operations are taking place correctly based on checks you put in place. | Are dangling lockfiles present? Has the CronJob run? | Triggers | More checks make sense when shipping something new; they act like a production test. Over time, you may want to remove some and keep only checks that indicate "things are messed up if this no longer happens". | | Normalcy | Define some order of magnitude where you consider things to be "normal" and want to know when you stray. | Cost of lambda queries? High login activity? Too little inbound traffic? | Triggers | These are limited because they come from a pre-determined normative idea of what a customer should do, or from trying to figure out what that should be. As such, they tend to be brittle. If you can find a good weighing mechanism (for example, "customers in category X should never break spend Y"), then you can turn these into SLOs. | | Saturation Thresholds | Identify issues that require significant ramp-up time to address to keep things safe before getting back to a stable level and issues that have fixes that are difficult to automate. In these cases, if you wait for end-user failures to show up, it's usually too late to address the issue properly. | Data retention duration and recovery procedures? Connection limits to a database? Expired certificates? | Triggers | Turning these into SLOs requires significant effort and tends to be closely associated with automation of contracts. For example, you could decide, "we guarantee 30% headroom on connection counts to all database users" and turn it into an SLO, but it's much more straightforward to run a trigger that checks connection counts at regular intervals. | ## Pager Notifications When setting up SLOs and triggers, you will want to consider whether to notify your team via pager. Your decision should vary based on perceived urgency and the time of the day. ### Error Rates From time to time, an error rate on a successful action may fail. If fixing the issue requires an hour of investigation, three to four hours of fixing, plus some time to deploy the fix, then you may want to be interrupted multiple hours ahead of time. Otherwise, there is no need to cancel a meeting or be awakened for something that can wait and be reasonably fixed the next day. ### Pre/Post Conditions Pre/post conditions should identify issues that you would arguably want to investigate during gaps in your schedule or tasks that you could manually re-run the next day. For example, a pre/post condition could monitor connection limits to a database, which can point to sudden cascading failures. In such cases, these should warn you early enough to not require immediate attention. You should need to address them only when they start feeling significantly broken. Additionally, if you avoid addressing these issues immediately, you can track the rate of breakage. Though this not a critical metric, tracking it can be valuable to assess whether things are becoming more brittle over time. ### Saturation Thresholds A saturation threshold represents a signal of future potential issues (for example, "in three months, an issue could arise"). The goal of a saturation threshold is to be visible enough, especially during slow times, for you to schedule corrective work. As such, a saturation threshold may not need to ever page you. ### Normalcy When normalcy alerts involve small deviations from expectations (for example, "maybe we have a user going beyond normal limits to try something out right now"), they may resemble saturation thresholds. However, when there are huge deviations from expectations (for example, "that's more than 10 times the very generous spend we expect; is someone actively abusing the platform?"), normalcy alerts may become full-blown incidents. For both cases, consider creating staggered alerts--one alert that warns you via email or instant messaging, and one that pages you. If you plan to page for suspected abuse, you should also plan appropriate actions. For example, you may want to suspend the user or escalate to a team or department responsible for this type of issue. ### Burn rate For SLOs, your main tool to mediate and escalate alerting is the burn rate. If the budget is about to be empty in 24 hours, you should notify via email or instant messaging. If the budget is about to be empty in approximately 4 hours (a safe default), then you should page. # Best Practices for API Keys Source: https://docs.honeycomb.io/get-started/best-practices/api-keys Get Honeycomb's recommendations for API key management: when to use Ingest, Management, and Configuration keys, and how to keep them secure across your organization. We recommend that you follow certain best practices when using API Keys. ## Use API Key types appropriately We recommend using Ingest Keys to send data to Honeycomb, and Management and Configuration keys to manage your Honeycomb resources. ### Ingest Keys We recommend using Ingest API Keys to send data to Honeycomb. They are specialized, environment-scoped keys, which are designed to securely transmit telemetry data, including the optional creation of new datasets. Ingest Keys have the following properties: * Limited permissions: Can only be used to write telemetry data, and optionally create new datasets. * Immutable: Once created, their permissions cannot be altered, which makes them the safest option for client-side instrumentation. * Can be deleted: These keys can be temporarily disabled or permanently deleted, which help users manage clutter and adhere to certain compliance standards. Check out: * our guides on [sending data to Honeycomb](/send-data/) * our API Documentation on [creating events](/api/events/createevents/) to learn more * our documentation on finding your [Ingest Key](/configure/environments/manage-api-keys/#find-api-keys) ### Management Keys Management API Keys allow you to manage API Keys and Environments at the Team level. Each key has a set of scopes, which can not be altered once the key has been created. Check out: * our [API Documentation](/api/) to learn more about what you can do with a Management Key * our documentation on finding your [Management Key](/configure/teams/manage-api-keys/#find-management-api-keys) ### Configuration Keys Configuration API Keys allow you to manage resources in your Environment, such as Boards, Columns, Markers, Triggers, and SLOs. Their permissions can be modified after their creation, and while they can be granted the permission to send events it is recommended that Ingest API Keys be used for that purpose. Check out: * our [API Documentation](/api/) to learn more about what you can do with a Configuration Key * our documentation on finding your [Configuration Key](/configure/environments/manage-api-keys/#find-api-keys) ## Use different API keys for different purposes For example, the API key used to send data in from your production cluster should be different from the API key used for testing; the key used by your build process to create markers should be different from either of those. Separating these purposes among different API keys allows you to revoke permissions on one key without affecting the abilities of others. It also minimizes the negative effects if a key leaks or is lost. # Observability and Working with Micro Frontends Source: https://docs.honeycomb.io/get-started/best-practices/micro-frontends Get Honeycomb's recommendations for adding observability to micro frontend applications with Honeycomb. Find out the tradeoffs and how to get OpenTelemetry or the Honeycomb Web SDK working in your setup. Micro frontend applications present a challenge for frontend observability libraries. No single solution exists to make OpenTelemetry or the Honeycomb Web SDK work easily with micro frontend. You will need to consider tradeoffs and limitations, so you'll need a clear understanding of your micro frontend architecture and your observability needs. To start, ask yourself: * What does my micro frontend architecture look like? * How is it unique? * How is it similar to other micro frontend systems? (For example, it uses module federation.) * What sort of information am I observing? * At what granularity am I observing this information? Read on for some ideas about how to manage the challenges of adding observability to your micro frontend. ## Initializing Libraries To initialize libraries, micro frontend systems usually use either module federation or a central bootstrap. Some systems even use both approaches. Systems using module federation are much more likely to encounter issues while initializing observability libraries, whereas issues are less of a problem with micro frontends that use a central bootstrap approach. Most micro frontends will encounter problems related to the observability SDK being a singleton. OpenTelemetry libraries and the Honeycomb Web SDK must be initialized only once per page load, which can be a problem in micro frontend architectures where every module is attempting to initialize its own OpenTelemetry library or Honeycomb Web SDK. If your system allows, initialize the library in a central bootstrap or shared module, and expose it to the other modules. Some module federation systems allow you to specify "singleton dependencies" for libraries like OpenTelemetry or React.js, which require that they be singletons on the page. This example shows [webpack](https://webpack.js.org/) with the [ModuleFederation plugin](https://webpack.js.org/plugins/module-federation-plugin/): ```javascript theme={} module.exports = { plugins: [ new ModuleFederationPlugin({ shared: { // Adds HoneycombWebSDK and OpenTelemetry as shared modules "@honeycombio/opentelemetry-web": { singleton: true, }, "@opentelemetry/api": { singleton: true, } }, }), ], }; // Initializes HoneycombWebSDK (only do this in one module) const sdk = new HoneycombWebSDK({ apiKey: "your-honeycomb-api-key", serviceName: "hfo-microfrontends", instrumentations: [getWebAutoInstrumentations()], localVisualizations: true, }); ``` The Honeycomb Web SDK will be initialized in the main module, and you can use the OpenTelemetry API for custom instrumentation. In other modules, you can create traces and spans as you normally would. ## Understanding Your Observability Needs The sort of challenges you face will depend on what information you need visibility into and how granular you want to be with attributing things to modules: * What metrics are done on a per-page basis? * Which metrics should be granular enough to go down to the module, or even the component, level? Some metrics might be fine at a per-page level. But for many metrics, such as error reporting, you'll likely want to identify the modules from which the errors came. ## Custom Instrumentation One way to avoid issues is to write your own code to handle instrumentation instead of using automatic instrumentation. If most of your telemetry uses custom instrumentation, you may be able to more easily add attributes for identifying specific modules. ## Auto-instrumentation When it comes to automatic instrumentation, most observability libraries will treat the entire application as a monolith. If you are only concerned with page-level granularity--for example, when tracking Web Core Vitals per page--this might be fine. Getting more granular data, especially at the module level, can be more challenging. You could use events like user clicks to identify the module the event came from. Check out the section on [custom span processing](/send-data/javascript-browser/#adding-custom-span-processing) with the Honeycomb Web SDK for more custom span processor examples. ```javascript theme={} class MFOSpanProcessor implements SpanProcessor { constructor(){ super(); } onStart(span: Span) { let moduleName = 'unknown-module'; if(isModuleA()) { moduleName = 'module-a'; } else if(isModuleB()) { moduleName = 'module-b'; } else if(isMainModule()) { moduleName = 'module-main'; } span.setAttributes({'module': moduleName}); } } //... const sdk = new HoneycombWebSDK({ apiKey: "your-honeycomb-api-key", serviceName: "hfo-micorfrontends", instrumentations: [getWebAutoInstrumentations()], spanProcessors: [new MFOSpanProcessor()] localVisualizations: true, }); ``` The method by which you figure out which module the span comes from will depend on your implementation. Sometimes you can use pre-existing attributes, such as the target element to determine origin. # Best Practices for Organizing Data Source: https://docs.honeycomb.io/get-started/best-practices/organizing-data Get Honeycomb's recommendations for organizing your data into datasets and environments, including naming conventions and structural patterns for the current data model. We recommend that you follow certain best practices when organizing data. Honeycomb divides your data into Environments and, within them, Datasets. An **Environment** represents the context for your events. A **Dataset** represents a collection of related events that come from the same source, or are related to the same source. ## Use Environments to group Datasets based on a theme Group events in the same Environment when you expect to analyze them as part of the same query or see them in the same trace. For example, if you create a separate Environment for each of your staging environments ("Production", "Development", and "Testing"), you can maintain focused datasets accompanied by relevant fields and values for each staging scenario. Separate events into different Environments when you cannot establish a relationship between them and want to reinforce that the data is differentiated. For example, you likely would not want to issue a single query against both "Production" and "Development". We do not recommend mixing data in the same Environment. Events from different Environments appear similar to one another and can be easily confused. Relying on the consistent application of a filter is tedious, error-prone, and likely to create misleading query results when forgotten. ### Consolidate Traces in an Environment For tracing, all the events in a trace must be within the same environment in order to render correctly in the UI. To ensure distributed tracing works across a number of services, send events from all of these services to a single environment. ### Examples of Environments The general guideline when creating environments is to what degree you will need to query data in the same place. There ara a few common patterns for choosing when to create distinct environments. #### Environments for Release Workflow You can use an Environment to represent different instances of an application as it moves through the release workflow, separating events that will be used in `production` from those in `staging`. You might also use a separate Environment for CI concerns, such as tracking [build events](/get-started/basics/observability/concepts/instrumentation/#batch-jobs-and-serverless) or test suite automation. #### Individual Development Environments Many Honeycomb users find it helpful send data from their local development environment. In this case, it can make sense for each team member to have an environment with their name, for example: `dev-alice`. A development environment can help both check that instrumentation is working correctly, and can also help understand how a new service is working. In some cases, you might prefer to have all developers use one shared `dev` environment. In those situations, every developer would send their events to the same dataset. Consider tagging each event with a field that specifies the developer whose local environment sent that event. That would allow a developer to query only their events by adding the filter `developer.name = name` to their queries. #### Environments for Regulatory Purposes Some Honeycomb users are subject to regulatory regimes, such as GDPR, and choose to create different environments to represent data that is affected by different regulations. Even though the events represent similar underlying activity, they may choose to send less-identifiable data to one environment than another. #### Data That Does Not Seem to Fit an Environment You might have general data that does not specifically fit into one environment. For example, you might keep infrastructure metrics that support both test and production data. We suggest you choose one well-known environment to put these into. One way to do this is create a separate `infra` environment. Alternately, you can put those events into `production`. ## Datasets Group Data Together Each Environment consists of a number of different Datasets. You can query within a single dataset, or across the entire Environment. Datasets are separated into two types: Service Datasets and General Datasets. ### Service Datasets The events in a Service Dataset represent distributed tracing spans. Each service is distinguished by its `service.name` field or `serviceName` configuration. A single trace can cross a number of different Service Datasets. When you look at a Trace, the query engine will find all spans — across all the Services in the Environment — that share the same trace id field. This will allow you to see the entire trace from any entry point. ### General Datasets General datasets consist of any data that does not participate in traces. They may include data from deployments, data from log sources, or metrics. We recommend that you send events into the Environment that best corresponds to those events. For example, a load balancer dataset might go into the `prod` Environment. While you can query across multiple datasets in Honeycomb, you may benefit from partitioning portions of your non-trace data into multiple general datasets. We recommend this approach to setting up your non-trace data: * Think of some of the **questions** that you want to ask of your data * Think about **what data** you need to collect in order to answer that question * Think about the **query** that you need to run across your data in order to answer the question - and in particular, how to make sure that you can **filter** it to only contain the data that you want. ### Manage the Number of Services Honeycomb sees Service Datasets as a way to group data: any data that is closely related to each other should go in the same Dataset. Information about a particular **instance** of a service should be sent as fields on the event, rather than the name of the service itself. For example, rather than sending data to two separate services, `authservice-host-01` and `authservice-host-02`, consider instead sending the data to one service, named `authservice`; use an additional field, `host`, to contain `01` and `02`. If you are able to combine this data into a single service, you will be able to more easily query across them. This will also let you use tools like [BubbleUp](/investigate/analyze/identify-outliers/) to compare and contrast fields on those events. ### Querying Across Trace and Non-trace data In order to easily query across trace and non-trace data - for example, correlating load metrics with trace information on API calls - it is important that you maintain consistency between your trace data and non-trace data. For example, if you are using OpenTelemetry to ingest your data, use the suggested OpenTelemetry schema for your service name, hostname, and other fields that you may decide to use. ## Managing your Data There are some general best-practices not linked to Environments and Datasets in particular. ### Namespace Custom Fields To help keep fields in order, it can be helpful to organize fields in the incoming events. We recommend using namespaces with dots to help bring them together. The automatic instrumentation in OpenTelemetry and Beelines follow this convention. For example: * tracing data is identified with `trace.trace_id`, `trace.parent_id`, and so on. * HTTP requests use fields like `request.url` and `request.user-agent` * database spans include fields such as `db.query`, `db.query_args`, and `db.rows_affected` Refer to the [OpenTelemetry Semantic Conventions](https://github.com/open-telemetry/semantic-conventions/) to learn more about conventional names for fields. Consider putting manual instrumentation under `app.`. Use as many layers of hierarchy as makes sense: `app.shopping_cart.subtotal` and `app.shopping_cart.items`; `app.user.email` and `app.user.id`. In general, it is a best practice not to dynamically set a field's name from your instrumentation code, or to generate field names on the fly. This can lead to runaway schemas, which can make the dataset difficult to navigate, and to Honeycomb throttling the creation of new columns. It is a common error to accidentally send a timestamp as a key, rather than as a value. It is particularly dangerous to send unsanitized user input as a field name. ### Ensure Schema Consistency In a dataset that encompasses multiple services, it can be distressingly easy to create inconsistent field names. ```json theme={} { "service.name": "web", "app.customer_login": "tallen", "http.url": "/home", ... } ``` ```json theme={} { "service.name": "s3", "app.user_id": "tallen", "s3.bucket": 5484, "s3.size": 518324, ... } ``` When you look at a full trace that contains both columns, the inconsistent user name fields might be annoying. Even though this will not be a significant problem when querying within one dataset, the inconsistency can lead to potential problems. One way to help ensure consistency is to use a shared library of constants, or shared functions that add instrumentation. ### Ensure Appropriate Field Data Types Check that your data is a good match for the type Honeycomb thinks it is. For example, a field that looks like an integer might actually be a user ID. It would not make sense to round a user ID, which could happen with a large integer value. You should explicitly send these as string data. Alternately, you can set the field type in from the Dataset Settings Schema page. ## Limits ### Limits for Environments Team owners can create any number of Environments in Honeycomb. You can send up to 100 datasets to a single Environment. If you are on a [Honeycomb Enterprise plan](https://www.honeycomb.io/pricing/), you can send up to 300 datasets to a single Environment. When you are approaching 90% of your limit, Honeycomb will warn the team via email. When you have hit your limit, Honeycomb will stop accepting new datasets for the environment but will continue to accept events for existing datasets. View the current number of datasets for your Environment from the Manage Environments page. If your team needs more datasets, please contact our Support team via [support.honeycomb.io](https://support.honeycomb.io/), or email at [support@honeycomb.io](mailto:support@honeycomb.io) to raise these limits. ### Limits for Events Each event allows a maximum of 2,000 distinct fields. Each entire event must contain less than 1 MB of uncompressed JSON data. For string fields, each string field has a maximum length of 64KB. For number fields, integers and floats are both 64-bit. If you exceed the maximum limit for any of these values, then the event is rejected and and an error is returned. Javascript's Number type can only represent up to 53 bit integers, so large 64-bit integer values may be rounded when displayed in the Honeycomb UI. ## Query Assistant In addition to your schema, Query Assistant uses the following as context: * The current query, if it exists * Suggested Queries for your dataset * [Dataset Definitions](/configure/datasets/definitions/) When modifying the current query, Query Assistant translates your prompts into additional query clauses. For example, when given a query that displays overall latency and the prompt "only show errors", Query Assistant usually adds a WHERE clause to return spans with an error field present and set to `true`. When a dataset has Suggested Queries configured, Query Assistant analyzes its fields and generates better results. We recommend configuring your own Suggested Queries for datasets that do not conform to common standards defined by OpenTelemetry instrumentation. Query Assistant uses the fields defined in [Dataset Definitions](/configure/datasets/definitions/). For example, OpenTelemetry (and Honeycomb, by default) recognizes any error as a boolean value in the `error` field. When a Dataset Definition overrides this default with a string value in the `app.error` field, Query Assistant uses the `app.error` field instead of the `error` field when it evaluates prompts. # Best Practices for Querying using Relational Fields Source: https://docs.honeycomb.io/get-started/best-practices/relational-fields Get Honeycomb's recommendations for querying with relational fields, including how to handle warnings and get accurate results from trace-based queries. ## Query Warnings ### Understanding the "Ignoring long traces" warning When you run a query with relational fields, Honeycomb uses a finite join buffer to bring together each trace's relevant spans. If a trace's spans are too far apart in your data stream (meaning, they were ingested by honeycomb at very different times), we may retire that trace before reading all of its constituent spans, resulting in this warning. There are three common reasons you might see this: * For high-volume environments, the buffer is typically around 3-10 minutes, so traces longer than this are at risk. You may be able to mitigate this by including more filters (especially on service name) in the query. * Problems with your ingestion pipeline which delay sending parts of a trace can cause this problem. You can identify this issue by looking for divergence between the timestamps of your spans and their recorded ingestion time. See the [Calculated Field Expression Reference](/reference/calculated-field-expression/time/#ingest_timestamp) for how to access this field. * Some customers use a single trace id for a very long-running or background operation, resulting in a very large "giga-trace". (We have observed single traces hundreds of millions of spans across multiple days). These are impossible to join successfully, but may not be relevant to your query. You can identify this issue by looking for traces with extremely large numbers of spans (COUNT GROUP BY trace.trace\_id), although in high-volume environments you'll want to scope that to as narrow a time range as possible. ## Query Performance To make your queries run faster, we recommend that you follow certain best practices when querying using relational fields. ### Use more filters Using more filters will give the greatest performance increase. Wherever possible, use filters! To get the greatest performance increase: * add filters that use field names both with and without relational field prefixes, even if some of those filters are duplicated. * if you add a filter with a relational field prefix to the **GROUP BY** clause, add a filter that uses the same relational field prefix to the **WHERE** clause. For example, if you are grouping by `parent.name`, also add a filter with a `parent.` relational field prefix into the **WHERE** clause. * make sure any of the additional filters you use exclude a meaningful number of events. If all else fails, identify a field that applies to all spans (for example, `service.name`) and include it in the **WHERE** clause. Following these recommendations will be particularly helpful for more expensive prefixes like `anyX.` (`any.`, `any2.`, `any3.`) and `parent.`. ### Root > anyX > parent Queries involving the `root.` prefix generally run faster than queries involving the `anyX.` (`any.`, `any2.`, `any3.`) prefix, which generally run faster than queries involving the `parent.` prefix. When you use the `root.` prefix, you get a free, implied `is_root` filter in the **WHERE** clause, which will usually filter out a substantial number of spans. When you use `anyX.` (`any.`, `any2.`, `any3.`), Honeycomb chooses the first span that matches your criteria, which also filters out a substantial number of spans. When you use `parent.`, Honeycomb must find the parent span for every event that matches the criteria defined by your non-prefixed fields, which can take some time. To improve performance, you could add a `parent.name` to the **WHERE** clause. ### Use shorter time ranges Use shorter time ranges for queries, including queries using relational fields. While Honeycomb can do an impressive amount of parallel processing of infrequently accessed data, we can do only so much within a given time frame. Be prepared for queries with long time ranges to take a while. ### Use traces with fewer spans Smaller traces means fewer events to hold in memory at once and less work for Honeycomb. ### Use similar services in a single trace Honeycomb uses the ingest time to determine what fits into a “window” of events that we keep in memory at a time. If you have a significant ingest delay for a specific service, relational fields queries that rely on joining that service's data with other services might suffer. For example, if you use a mix of AWS Lambda and non-Lambda services in a single trace, your ingest delay will likely vary significantly. AWS freezes the execution environment before spans can be flushed, which increases the ingest delay from AWS as opposed to other services. This only matters if the amount of ingest delay varies by service/span. If all of your services have roughly the same amount of ingest delay (for example, all consistently two to three minutes late), then your queries should not be affected. # Best Practices for Service Level Objectives (SLOs) Source: https://docs.honeycomb.io/get-started/best-practices/slos Get Honeycomb's recommendations for SLOs: when to use them across datasets, how to set meaningful targets, and how to avoid common pitfalls. EntPro This feature is available as part of the [Honeycomb Enterprise and Pro plans](https://www.honeycomb.io/pricing/). We recommend that you follow certain best practices when using [Service Level Objectives (SLOs)](/notify/slos/). ## Use SLOs across multiple datasets only when necessary Even though Honeycomb allows you to create an SLO that shares a budget across multiple datasets/services, most SLOs can be made with one service/dataset. In most cases, you can define the correct SLO for an experience by putting the SLO on the service that is closest to your end users, which is also known as the edge service. Define an SLO across multiple services only when multiple edge services exist. ## Attach only one SLO to any SLI Honeycomb limits you to attaching only one SLO to any SLI Calculated Field. For example, you may not have both a 30-day and a 60-day SLO attached to the same SLI calculated field, although you may have as many Burn Alerts attached to an SLO as you wish. If you find yourself needing more than one SLO attached to any SLI Calculated Field, please [contact Honeycomb for support](/troubleshoot/customer-support/); we would like to understand that scenario better! ## Use SLOs with a reasonably high volume of data SLOs are most effective when you have a reasonably high volume of data: a small number of failures in an hour should not make a major dent in your reliability. ## Apply fairly few SLOs to any dataset SLOs should describe interfaces to a system rather than, for example, customers. In this example, generally, customers should behave roughly similar to one another; if groups of customers have properties that set them apart from others, try to write SLOs against those properties instead. ## Keep your retention period in mind Honeycomb will track SLO values past your retention period, but will display these for only the Budget Burndown and Historical Compliance graphs. You cannot use BubbleUp or the heatmap to look at times beyond your retention period. # Sign Up for Honeycomb Source: https://docs.honeycomb.io/get-started/create-account Learn how to create a new Honeycomb account, create a new team, and invite your teammates to Honeycomb. ## Create your Honeycomb account 1. Go to [https://ui.honeycomb.io/signup](https://ui.honeycomb.io/signup). 2. Select **Switch to European Union** or **Switch to North America** to choose your account's region. 3. Sign up with your email or Google account. 4. Activate your account using the activation link sent to your email. Honeycomb stores your data in either a US-based or EU-based location depending on your account region. Sign up form for creating a Honeycomb account. ## Create your team When you log in to your new Honeycomb account, you'll be taken to the **Create new team** page. Give your team a name, choose your occupation/role, and let us know how you heard about Honeycomb. When you are ready, select **Create Team**. Example form for creating a new team in Honeycomb. ## Invite people to your team 1. Navigate to **Account** > **Team Settings** > **Users** 2. Select **Team URL** and **copy** your team's URL. 3. Share this URL with your teammates. If available, you can also select **Invite Users** and add members to your team by providing a list of comma-separated emails. # 2026 Pro Plan Changes Source: https://docs.honeycomb.io/get-started/honeycomb/2026-pro-plan-changes Learn what is changing in Honeycomb's 2026 Pro plan pricing, including new tiers, a grace period, and what it means for your current plan. Honeycomb is introducing a new generation of self-serve Pro pricing. This page answers common questions about what is changing and what it means for your existing plan. ## What is changing? Starting July 1, 2026, Honeycomb is updating Pro plan pricing to include access to [Time Series Metrics](/get-started/honeycomb/metrics-in-honeycomb) and AI-powered features included in [Honeycomb Intelligence](/get-started/honeycomb/honeycomb-intelligence), like [Canvas](/investigate/canvas) and the [Honeycomb MCP](/integrations/mcp). The new per-event rate is \$3.00 per million events, compared to \$1.30 per million events on legacy plans. The tier structure is also changing, from three tiers to four, topping out at 750M events per month. To explore the new tiers, visit [Honeycomb Pricing](https://honeycomb.io/pricing). Other entitlements, like [Triggers](/notify/triggers), [Service Level Objectives (SLOs)](/notify/slos), and support tier, stay the same regardless of which plan you are on. Similarly, usage is still [measured in events per month and datapoints per month](/get-started/manage-costs/how-honeycomb-calculates-usage) and data retention periods remain the same. ## Why is pricing changing on Pro plans? In the last year, Honeycomb has introduced several powerful features, such as [Time Series Metrics](/get-started/honeycomb/metrics-in-honeycomb), [Canvas](/investigate/canvas), and the [Honeycomb MCP](/integrations/mcp). Our Enterprise clients are already leveraging these tools to achieve greater value through accelerated onboarding, improved incident response times, and enhanced visibility into production AI agents. To ensure even more users can take advantage of these capabilities, we are extending them to our Pro customers. You can learn more about the new features we have released on the [Honeycomb Blog](https://www.honeycomb.io/blog?page=1\&topic=Product+Updates). Pricing is being adjusted to reflect the inclusion of these features and the rollout of new tiers designed to better align with customer events and usage requirements. ## What about Honeycomb for Builders? How will this change the Pro1500 discounts and usage? The [Honeycomb for Builders](https://www.honeycomb.io/honeycomb-for-builders) program discounts will not change for those already enrolled. For new members of the program, the Pro discounts will cover Pro750 to align to the new pricing tiers. ## Do I need to do anything right now? Not right away. You can stay on your current Pro plan during the grace period, which ends on December 31, 2026, and nothing changes until then. Your billing page shows a `(Legacy)` label, so you know which generation of plan you are on. If you want to lock in savings now, though, you can commit to an annual term on your current legacy tier during the grace period and you will get a full year at your legacy rate plus a 20% increase, which costs less than switching to a new tier outright. To learn more, refer to [Can I keep legacy pricing for longer?](#can-i-keep-legacy-pricing-for-longer). The grace period is a good opportunity to re-evaluate your telemetry needs. If you are currently sending metrics as events, moving that telemetry to time series metrics frees up meaningful event headroom, since metrics data points bill separately from events. This shift can affect which 2026 tier actually fits your usage. ## What happens if I don't take any action? If you haven't chosen a new plan by the time the grace period ends, Honeycomb moves your team to the 2026 Pro tier that most closely matches your current legacy tier. This happens automatically at your next billing boundary. The 2026 Pro tier plan chosen is based on the plan you are on, not your real consumption. If you have seen overage notices or throttling, it is worth choosing your tier proactively rather than waiting for the automatic move. If your usage runs higher than the top 2026 Pro tier, Honeycomb will reach out to you before the grace period ends to help you find the right plan. ## Can I keep legacy pricing for longer? If you commit to an annual term on your current legacy tier during the grace period, you can keep legacy pricing for that full annual term, up to one year, at a 20% increase over your legacy rate. When the legacy renewal term ends, you move to current 2026 pricing and tiers, either monthly or annually. However, the grace period is a good opportunity to re-evaluate your telemetry needs. If you are currently sending metrics as events, moving that telemetry to time series metrics frees up meaningful event headroom, since metrics data points bill separately from events. That shift can change which 2026 tier actually fits your usage, so it is worth choosing your plan rather than relying on automatic migration. To learn how to update your plan, visit [Change Pricing Plan](/configure/teams/pricing-plan). ## What if my Team is on an annual plan with time left on it? You keep your current plan until your plan renews, at which point Honeycomb automatically moves your team to the 2026 Pro tier that corresponds to your current legacy tier. ## Where can I get help? If you have questions about your Pro plan and these changes, reach out to [Honeycomb Support](/troubleshoot/customer-support). # Core Analysis Loop Source: https://docs.honeycomb.io/get-started/honeycomb/core-analysis-loop Cycle through your telemetry dimensions, form hypotheses, and validate them with data. Learn how to debug any system from first principles. The core analysis loop is the basis of debugging from first principles. No matter how little you know about a system, you can use this loop as a brute-force method to cycle through all available dimensions in your telemetry data and identify which ones explain or correlate with outlier graphs. For more structured learning, check out the [The Core Analysis Loop](https://academy.honeycomb.io/app/courses/879919e3-5eb8-4d78-b0b6-f15863127c9d) course from Honeycomb Academy. ## Debugging From First Principles Once you have gathered telemetry data as events, achieving observability requires that you are capable of analyzing that data in powerful and objective ways. You should have to know very little before debugging an issue. You should be able to systematically and scientifically take one step after another, and methodically follow clues to find an answer, even when you are unfamiliar with the system. In short, you should be able to debug your applications from first principles. A first principle is a basic assumption about a system that was not deduced from another assumption. While intuitively jumping straight to the answer is wonderful, it becomes increasingly impractical as complexity rises and the number of possible answers skyrockets. Proper science requires you to avoid assuming anything. You must start by questioning what has been proven and what you are absolutely sure is true. Then, you must form a hypothesis and validate or invalidate it based on observations about the system. Debugging from first principles is a methodology you can follow to understand a system scientifically and is a core capability of observability. ## Using the Core Analysis Loop The core analysis loop is the process of using your telemetry to form hypotheses and to validate or invalidate them with data, thereby systematically arriving at the answer to a complex problem. It puts debugging from first principles into practice through the use of a methodical, repeatable, verifiable process. Debugging from first principles begins when you are made aware that something is wrong. You could have received an alert or a customer complaint: you know that something is slow, but you do not know what is wrong. At this point, you can begin the stages of the core analysis loop: Diagram of Core Analysis Loop 1. **Define: What are you trying to understand?** Start with what prompted your investigation: what did the customer or alert tell you? 2. **Visualize: Visualize telemetry data to find relevant performance anomalies.** Verify that what you know so far is true: do you see a notable change in performance happening somewhere in the system? Data visualizations can help you identify changes of behavior--you'll see a change in a curve somewhere on the graph. 3. **Investigate: Search for common dimensions within the anomalous area by grouping or filtering for different attributes in your wide events.** Search for dimensions that might drive the change in performance. To do this, you might: 1. Examine sample rows from the area that shows the change: are there any outliers in the columns that might give you a clue? 2. Slice those rows across various dimensions looking for patterns: do any of those views highlight distinct behavior across one or more dimensions? Try an experimental **GROUP BY** on commonly useful fields, like `status_code`. 3. Filter for particular dimensions or values within those rows to better expose potential outliers. You can use Honeycomb's BubbleUp feature to simplify this step. To see an example, read ["Example: Investigate an Outlier Using BubbleUp"](#example-investigate-an-outlier-using-bubbleup). 4. **Evaluate: Have you isolated likely dimensions that identify potential sources of the anomaly?** Do you now know enough about what might be occurring? If so, you're done! If not, filter your view to isolate this area of performance as your next starting point, then return to step 3. The core analysis loop works best with rich, high-cardinality structured events: the more context each event carries, the more dimensions you have to investigate. Logs and metrics can participate in the loop too, especially when logs are sent as structured events via OpenTelemetry and correlated with traces. The more structure your telemetry has, the more effectively you can apply this methodology. ## Automating the Core Analysis Loop When uncovering interesting dimensions, you can perform the core analysis loop manually, but a good observability tool should automate as much of the investigation for you as possible. Rather than manually searching across rows and columns to coax out patterns, an automated approach would be to retrieve the values of all dimensions, both inside the isolated area (the anomaly) and outside the area (the system baseline), diff them, and then sort by the difference. Very quickly, this lets you see a list of things that are different in your investigation's areas of concern as compared to everything else. For example, you might isolate a spike in request latency and, when automating the core analysis loop, get back a sorted list of dimensions and how often they appear within this area. You might see the following: * `request.endpoint` with value `batch` is in 100% of requests in the isolated area, but in only 20% of the baseline area. * `handler_route` with value `/1/markers/` is in 100% of requests in the isolated area, but only 10% of the baseline area. * `request.header.user_agent` is populated in 97% of requests in the isolated area, but 100% of the baseline area. At a glance, this tells you that the events in this specific area of performance you care about are different from the rest of the system in all of these ways, whether that be one deviation or dozens. ### Example: Investigate an Outlier Using BubbleUp Honeycomb automates the core analysis loop with the [BubbleUp](/investigate/analyze/identify-outliers/) feature. With Honeycomb, you start by visualizing a heatmap to isolate a particular area of performance you care about. Select a spike in a line chart or drag to select an unusual area on your heatmap, and choose **BubbleUp Outliers**. BubbleUp computes the values of all dimensions both inside the box (the anomaly you care about and want to explain) and outside the box (the baseline), and then compares the two and sorts the resulting view by percent of differences. Let's take a look at a heatmap that shows an anomaly and use BubbleUp to investigate it. In this real-world example, we're looking at an application with high-dimensionality instrumentation that BubbleUp can compute and compare. We have already visualized a heatmap of event performance, seen an anomalous shape on our heatmap, and dragged to draw a box around the anomalous shape and open up BubbleUp. Screenshot of a Honeycomb heatmap of event performance during a real incident In this example, BubbleUp surfaces results for 63 interesting dimensions and ranks the results by the largest percentage difference. The results of the computation are shown in histograms using two primary colors: blue for baseline dimensions and orange for dimensions in the selected anomaly area. In the top results, we see two histograms showing notable differences between baseline dimensions and anomalous dimensions: a field named `global.availability_zone` with a value of `us-east-1a` and a field named `global.instance` with a value of `m6g.4xlarge`. Other surfaced dimensions have differences that tend to be less stark, indicating that they are likely not as relevant to this investigation. When we hover over the histograms, we get further details. For example, we can see that `global.availability_zone` appears as `us-east-1a` in 98% of anomalous events in the selected area and only in 17% of baseline events. Screenshot of BubbleUp histograms of most interesting dimensions Overall, the noteworthy histograms show that: * slow-performing events are mostly originating from one particular availability zone (AZ) from our cloud infrastructure provider * one particular virtual machine instance type appears to be more affected than others We now know the conditions that appear to be triggering slow performance--a particular type of instance in one particular AZ is much more prone to very slow performance than other infrastructure we care about. In this situation, the glaring difference pointed to what turned out to be an underlying network issue with our cloud provider's entire AZ. We contacted our cloud provider and were also able to independently verify the unreported availability issue when our customers also reported similar issues in the same zone. Not all issues are as immediately obvious as this underlying infrastructure issue. Often you may need to look at other surfaced clues to triage code-related issues. The core analysis loop remains the same, and you may need to slice and dice across dimensions until one clear signal emerges, similar to the preceding example. If this example had instead been a code-related issue, we might have decided to reach out to the users who reported issues or figured out the path they followed through the UI to see those errors, and then fixed the interface or the underlying system. # Honeycomb Intelligence Source: https://docs.honeycomb.io/get-started/honeycomb/honeycomb-intelligence AI-powered features that surface insights from your telemetry so you can investigate faster and resolve incidents with confidence. Honeycomb Intelligence is a suite of AI-powered features built into Honeycomb that surfaces insights from your telemetry data so you can investigate faster, understand your systems more deeply, and resolve incidents with confidence. ## What is Honeycomb Intelligence? Honeycomb Intelligence is not a single feature—it is a set of capabilities that meet you where you are in your workflow. Some features are interactive, responding to your questions and guiding investigations in real time. Others work in the background, learning what normal looks like for your systems and alerting you when something meaningful changes. Use Honeycomb Intelligence to: * **Investigate an incident interactively**: [Canvas](/investigate/canvas) is an AI-guided workspace inside Honeycomb that pairs natural language interaction with rich, interactive visualizations. Ask Canvas a question, explore query results, and share snapshots with teammates, all without leaving Honeycomb. * **Understand what you are looking at**: [Chat about a page](/investigate/canvas/chat-about-a-page) gives you contextual AI help on the Honeycomb page you are viewing, without opening a full investigation. * **Troubleshoot production issues from your IDE**: The [Honeycomb MCP Server](/integrations/mcp) lets AI-powered IDEs and agents query your observability data directly using natural language. Run BubbleUp, detect outliers, and visualize traces without switching tools. * **Get early warning of performance problems**: [Anomaly Detection](/troubleshoot/product-lifecycle/experimental-features#anomaly-detection) (Early Access) learns what normal looks like for your services and automatically surfaces meaningful deviations before they affect your users. It reduces false positives and alert fatigue so your team focuses on real problems. * **Build queries faster**: [Query Assistant](investigate/query/build/query-assistant) is a text-to-query interface that helps you construct valid, runnable Honeycomb queries from a natural language description of what you want to find. * **Create calculated fields faster**: [AI Assisted Calculated Fields](/send-data/standardize/transform-data) helps you write valid calculated field expressions using natural language, drawing on your dataset schema to produce accurate results. ## How Honeycomb Intelligence works Honeycomb Intelligence is designed to fit into your existing workflow with minimal friction and full transparency into how it works. ### AI models Honeycomb Intelligence uses a combination of large language models (LLMs) and statistical machine learning models, depending on the task. Interactive features like Canvas, Query Assistant, and AI Assisted Calculated Fields use LLMs to interpret your input and generate responses grounded in your dataset schema and telemetry. Anomaly Detection uses statistical machine learning models rather than LLMs. It continuously builds a per-service baseline from your existing telemetry and surfaces deviations that are likely to indicate a real problem. ### Data and model training Honeycomb does not use your telemetry data to train foundation models. For details about model providers and data handling, visit [Honeycomb AI Policies](/security-compliance/ai-policies). ### Data pipeline Honeycomb Intelligence works with your existing telemetry data. You don't need to reconfigure your instrumentation, set up a separate AI pipeline, or move data anywhere new to use them. ### Team control Honeycomb Intelligence is optional. Team Owners can enable or disable it at any time. When disabled, no Honeycomb Intelligence features are active, including features that surface insights passively. To learn how to enable or disable Honeycomb Intelligence for yout Team, visit [Manage Team Behavior](/configure/teams/manage-behavior). # Introduction to Honeycomb Source: https://docs.honeycomb.io/get-started/honeycomb/introduction Learn what Honeycomb is, what problem it solves, and how its core concepts fit together. Honeycomb is an observability platform built for understanding complex software systems in production. When something goes wrong, or behaves unexpectedly, Honeycomb gives you the tools to find out why, without knowing in advance what question you need to ask. Many observability tools are built around known failure modes: metrics you decided to track, thresholds you set in advance, dashboards you built before the incident. That works when your systems fail in ways you have already seen. But these tools fall short when your system surprises you, which happens more often as systems grow more distributed and complex. ## Why Honeycomb? The core difference is in how Honeycomb stores and queries data. Many observability tools store raw telemetry but limit what you can query: a fixed set of indexed tags, pre-defined dashboards, or aggregations computed at ingest. Honeycomb runs arbitrary queries across all fields at interactive speed, so the question you ask at 2am during an incident doesn't have to be one you anticipated when you set up your dashboards. A few specific things follow from that design: * **You can instrument richly without penalty:** Add as many fields as you want with many unique values per field, such as user IDs, request IDs, or feature flags. Honeycomb is built to handle high-cardinality data efficiently, with [pricing](https://www.honeycomb.io/pricing) based on event volume rather than field cardinality or dimension count. * **You can ask questions you haven't thought of yet:** Every field in every event is automatically indexed when it arrives. There's no schema to define in advance, no index to build, no field to "activate." If you sent the data, you can query it. * **Queries run in seconds, not minutes:** Honeycomb's purpose-built columnar store returns results on terabytes of raw event data at sub-second to low-second query times. The difference between a two-second query and a two-minute query isn't just convenience; it makes iterative investigation practical. * **The whole team can use it:** All Honeycomb plans include unlimited seats, so you don't have to ration or rotate access. An on-call engineer, a product manager, and a senior engineer debugging together can all query, annotate, and share findings in real time without worrying about per-seat charges. * **AI fits naturally into this model:** Honeycomb's data is high-cardinality, fast to query, and accessible via API and MCP. That makes it a strong foundation for AI-assisted investigation: the data AI needs to reason about your system is already there, already indexed, and already queryable at the speed investigation requires. ## How Honeycomb works Honeycomb is built around a single foundational concept: the *event*. An event is a structured record of a single unit of work. It captures what happened, when it happened, how long it took, and any context your instrumentation includes: user IDs, feature flags, service names, error messages, build IDs. Honeycomb supports three telemetry signals, each of which answers different questions about your system: * **Traces**: Collections of spans that share a trace ID. Each span represents one unit of work in your distributed system. Honeycomb uses the parent-child relationships between spans to render a waterfall view of execution flow across your services. * **Logs**: Records of discrete events: errors, state changes, and application output. Structured logs map directly to Honeycomb events and are immediately queryable. When sent via OpenTelemetry, logs are automatically correlated with the traces they belong to. To learn more about Honeycomb's approach to Logs, visit [Logs in Honeycomb](/get-started/honeycomb/logs-in-honeycomb). * **Metrics**: Numeric measurements of your system captured over time, such as CPU utilization, request rates, and error counts. Honeycomb stores metrics in dedicated metrics datasets built on the OpenTelemetry Metrics Data Model, separate from your trace and log data. You can query metrics alongside your traces and logs, and Honeycomb can surface relevant metrics automatically when you investigate a latency spike or error pattern. To learn more about Honeycomb's approach to Metrics, visit [Metrics in Honeycomb](/get-started/honeycomb/metrics-in-honeycomb). To learn how Honeycomb organizes this data into datasets, environments, and teams, visit [Honeycomb's Data Model](/get-started/honeycomb/data-model). ## What you can do with your data Once your data is in Honeycomb, you can: * **Query across any dimension:** The Query Builder lets you filter, group, and aggregate on any field in your data, including fields you didn't know you'd need when you started instrumenting. * **Explain unusual behavior:** Select any region of your data and BubbleUp highlights which dimensions differ most from the baseline, so you can narrow down what changed without manually checking each field. * **Get proactive alerts on anomalies:** [Anomaly Detection](/troubleshoot/product-lifecycle/experimental-features#anomaly-detection) (Early Access) learns normal patterns per service from your trace and event data, such as error rate and data presence, and notifies you when behavior deviates, without requiring you to define a Trigger for every failure mode. * **Investigate traces:** The trace waterfall shows execution flow across services, with span-level detail and direct links to correlated logs and metrics. * **Explore logs:** The Logs view surfaces log volume, severity breakdowns, and top messages at a glance, so you can scan and filter log data without building queries from scratch. * **Monitor metrics:** The Metrics view surfaces time series data alongside your traces and logs, so you can correlate a latency spike with a CPU saturation event without switching tools. * **Alert and notify:** Set up Triggers to notify your team when your data crosses defined thresholds. SLOs track error budget burn over time and alert when burn rate accelerates. * **Share findings:** Boards collect queries and visualizations into a reusable view. Query links and trace links preserve full context for teammates. * **Investigate with AI:** With [Honeycomb Intelligence](/get-started/honeycomb/honeycomb-intelligence) enabled, [Canvas](/investigate/canvas) can auto-investigate alerts and anomalies you configure, so findings can already be waiting when you open the incident. [Query Assistant](/investigate/query/query-assistant) translates natural language into valid queries, and the [Honeycomb MCP server](/integrations/mcp) lets supported AI tools query your production data directly. These features build on the same event data and fast query model as the rest of the product. ## Where to start Your first step is getting data in. Honeycomb recommends OpenTelemetry as the standard for instrumentation and ingestion. Send traces, logs, and metrics from your application using OpenTelemetry SDKs. Collect logs and metrics from Kubernetes, AWS, and other infrastructure using the OpenTelemetry Collector. Try Honeycomb with sample data before connecting your own systems. Learn the methodology behind debugging from first principles with Honeycomb. # Keyboard Shortcuts Source: https://docs.honeycomb.io/get-started/honeycomb/keyboard-shortcuts Keyboard shortcuts available in the Honeycomb UI, organized by context. Shortcut availability changes based on where you are in the interface. When you're working, your tools should feel effortless, letting you focus on solving problems, not navigating menus. To help you move smoothly, we've made essential keyboard shortcuts easy to access. Keyboard shortcut availability changes based on where you are in the UI. ## Query Keyboard shortcuts available from the **Query** () section of the Honeycomb UI include: | Shortcut | Description | | ----------------------------- | -------------------------------------------------------------------------- | | Open keyboard shortcuts panel | ? | | Toggle right sidebar | h | | Toggle left sidebar | n | | Open query builder | q | | Run query | Shift + Enter
Cmd + Enter | | Undo query change | Cmd + z | | Redo query change | Cmd + Shift + z | | Open dataset selector | d | | Open time range selector | t | | Toggle UTC time | u | | Toggle chart hovers | o | | Toggle markers | m | | Filter markers | l | | Wrap log lines | w | ## Service Map Keyboard shortcuts available from the **Service Map** () section of the Honeycomb UI include: | Shortcut | Description | | ----------------------------- | ------------ | | Open keyboard shortcuts panel | ? | | Toggle right sidebar | h | | Toggle left sidebar | n | | Open time range selector | t | # Log in with SAML SSO Source: https://docs.honeycomb.io/get-started/honeycomb/log-in-with-saml-sso Log in to a Honeycomb Team configured for SAML SSO, whether you are a new user or an existing user switching login methods. EntPro This feature is available as part of the [Honeycomb Pro and Enterprise plans](https://www.honeycomb.io/pricing/). Honeycomb Teams can require authentication through a SAML Identity Provider (IdP). This guide walks you through logging in to a SAML-configured Honeycomb Team. ## Before you begin Before you log in, make sure you have the following: * An account in your team's SAML IdP, such as Okta or Microsoft Entra ID. If you need help determining which IdP your team uses, contact your Team Owner. * Access to the email address associated with your IdP account. You don't need an existing Honeycomb account. If you don't have one, Honeycomb creates one for you during the login process. ## Logging in To reach your Honeycomb team's login page, you must first log in to your IdP. Choose the option that works best for you. If you know your team's slug, go directly to your team's SAML login page: * **US:** `https://ui.honeycomb.io/login/sso/{team_slug}` * **EU:** `https://ui.eu1.honeycomb.io/login/sso/{team_slug}` For example, to log in to a US team with the slug `hny`, go to `https://ui.honeycomb.io/login/sso/hny`. If the team is configured for SAML, the page redirects to the team's SAML IdP. Log in to your company's IdP directly (for example, `yourcompany.okta.com`) and select the `Honeycomb` tile for your team. If you need help choosing an option or locating Honeycomb in your IdP dashboard, contact your Team Owner. Once you have logged in to your IdP, your login flow depends on whether you are a new Honeycomb user or an existing one. If you are new to Honeycomb, Honeycomb asks you to verify your email address before creating your account. To verify: 1. Check your email for an account activation code. The verification email may take a few minutes to arrive. Check your spam folder if you don't see it. 2. Copy the verification code from the email. 3. Enter the code on the Honeycomb landing page. 4. Select **Submit**. Honeycomb redirects you to your team's home page. If you have logged in with this SAML IdP before and already linked your Honeycomb account, Honeycomb redirects you directly to your team's home page. If you have a Honeycomb account not yet linked to this SAML IdP, the flow depends on whether you are currently logged in to Honeycomb. **If you are currently logged in to Honeycomb:** Honeycomb displays a confirmation page asking you to link your account to this SAML IdP. A Honeycomb account can be linked to more than one SAML IdP, so linking this account won't affect any existing IdP connections. 1. Review the information on the page before proceeding: | Field | Description | | ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------- | | `SAML Identity` | Identifier your SAML provider uses to identify your account. Often your email address, but may be another form of identifier. Useful for troubleshooting. | | `Issuer (SAML Provider)` | Identifier for the SAML provider you logged in with. | | `Honeycomb Account` | Email address associated with your currently logged-in Honeycomb account. | | `Team` | Team for which the IdP is configured. Honeycomb adds you to this team after you link your account. | 2. Choose your path: * If everything looks correct, select **Link account** to complete the process. * If something doesn't look right or you don't want to link this account, select **Cancel**. **If you are logged out of Honeycomb:** Honeycomb recognizes your email address and asks you to verify ownership before linking your account. To verify: 1. Check your email for an account activation code. The verification email may take a few minutes to arrive. Check your spam folder if you don't see it. 2. Copy the verification code from the email. 3. Enter the code on the Honeycomb landing page. 4. Select **Submit**. Honeycomb redirects you to the home page for your team. # Logs in Honeycomb Source: https://docs.honeycomb.io/get-started/honeycomb/logs-in-honeycomb Learn how Honeycomb handles log data, how to get the most out of structured and unstructured logs, and how logs fit alongside your traces and metrics. Honeycomb supports all three OpenTelemetry (OTel) signals: traces, logs, and metrics. Whether you are starting with raw, unstructured logs or fully structured OTel output, Honeycomb can work with what you have, and your data becomes more powerful as you add structure over time. If you are new to logs or want to understand how Honeycomb thinks about structured versus unstructured data, visit [Traces, Metrics, and Logs](/get-started/honeycomb/traces-metrics-logs/). ## How logs work in Honeycomb Honeycomb stores and queries logs alongside traces and metrics, using the same event-based data model. ### Logs as events Honeycomb stores logs as events, the same foundational unit as trace spans. A structured log maps naturally to a Honeycomb event: its fields become event fields, automatically indexed and immediately available in the Query Builder. ### Starting with unstructured logs Honeycomb works with unstructured logs, and you can add structure incrementally. * **For application logs:** [Configure an OTel SDK](/send-data/logs/opentelemetry/sdk) to wrap your existing log output and send it to Honeycomb as structured events. * **For infrastructure or file-based logs:** [Configure the OpenTelemetry Collector to parse fields before ingestion](/send-data/logs/unstructured/collector). * **After the fact:** [Use calculated fields to extract structure](/send-data/standardize/transform-data#parsing-unstructured-logs). The more fields you add to your logs over time, the more of Honeycomb's query capabilities become available to you. ### Log dataset identification Honeycomb treats a dataset as a log dataset when it includes a log message field: typically the OpenTelemetry `body` field, or a field you map to `Logs: Message` in your [dataset definitions](/configure/datasets/definitions). That enables the Logs view on Honeycomb Home, which surfaces log volume, error and warning counts, severity breakdowns, and top messages without requiring you to build those queries manually. To populate severity charts and color-coded log lines, also send a `severity` field or map a field to `Logs: Severity`. If your severity values are non-standard, use [calculated fields](/send-data/standardize/transform-data) to normalize them to Honeycomb's expected levels. Log datasets are typically kept separate from trace datasets, both for organizational clarity and so that Honeycomb can apply the appropriate Home visualizations for each signal type. ## Log-trace correlation One of the strongest reasons to send application logs via OTel is automatic correlation with traces (infrastructure and file-based logs can be sent to Honeycomb and queried, but don't automatically carry trace context). When your application is configured with both an OTel log exporter and OTel tracing, logs emitted within the context of a request are automatically tagged with the trace ID and span ID for that request. This makes OTel logs a useful starting point for teams who aren't yet on traces. You can send your existing structured application logs to Honeycomb via OpenTelemetry and get queryable, high-cardinality log data immediately. When you add tracing later, those logs become linked to the traces they belong to. You usually don't need to change how you emit log lines; adding tracing attaches trace context to logs you are already sending. You can build toward fuller observability incrementally, at whatever pace works for your team. OTel log support varies by language; check [Send Logs from OpenTelemetry SDKs](/send-data/logs/opentelemetry/sdk) for current availability before getting started. ## How to query logs Querying logs in Honeycomb works the same way as querying any other data. Use the Query Builder to filter by severity, group by message, aggregate counts over time, or identify outliers with BubbleUp. A few patterns are particularly useful for log data: * **Filter by severity** to focus on errors or warnings: `WHERE severity = error` * **Group by your log message field** (typically `body`) to find which log messages occur most frequently * **Use HEATMAP on a parsed numeric field**, such as a response time extracted from a log line, to visualize distribution over time * **Use BubbleUp** on a spike in log volume to surface which field values are most common in that window compared to the baseline The **Explore Events** view presents log data in a format optimized for scanning, with color-coding by severity level. Color-coding requires a field mapped to `Logs: Severity` in your dataset definitions. To learn more, visit [Map Your Data](/send-data/standardize/map-data). ## How logs work with traces and metrics Logs, traces, and metrics are complementary signals. In practice, you will often use all three together: * A **metrics alert** surfaces a problem: error rate is elevated. * A **log query** narrows the scope: these specific error messages are occurring most frequently. * A **trace investigation** explains the cause: this is where in the request execution the error originates. When logs carry trace context, you can navigate from a log event to its corresponding trace; logs and traces typically live in separate datasets, connected by their shared trace ID. ## Logs and your plan Log data is measured in events per month (EPM) and counts against your event allotment alongside trace data. To learn how Honeycomb measures usage, visit [How Honeycomb Calculates Usage](/get-started/manage-costs/how-honeycomb-calculates-usage). ## Next steps * [Send Logs from OpenTelemetry SDKs](/send-data/logs/opentelemetry/sdk): Send structured application logs from your code, correlated with your traces. * [Send Logs with the OTel Collector](/send-data/logs/unstructured/collector): Parse and forward infrastructure and file-based logs to Honeycomb. * [Investigate Log Data in Honeycomb](/investigate/debug/log-data-in-honeycomb): Query, visualize, and debug your log data once it is in Honeycomb. * [Map Your Data](/send-data/standardize/map-data): Map your field names to Honeycomb standard fields to enable log severity color-coding and Home visualizations. # Metrics in Honeycomb Source: https://docs.honeycomb.io/get-started/honeycomb/metrics-in-honeycomb Learn how Honeycomb handles metrics data, how metrics relate to traces and logs, and when to use metrics in your observability practice. Honeycomb supports three telemetry signals: traces, logs, and metrics. Metrics are the right tool for continuous monitoring of known quantities: infrastructure health, request rates, error counts, and other numeric signals you always care about, regardless of what any individual request is doing. If you are new to metrics or want to understand how Honeycomb thinks about metrics versus events, visit [Traces, Metrics, and Logs](/get-started/honeycomb/traces-metrics-logs/). ## How metrics work in Honeycomb Metrics in Honeycomb are built around two core concepts: data points and time series. Each individual measurement is called a *data point*. A *time series* is the sequence of data points for a single metric with a consistent set of attributes (for example, CPU utilization for a specific host over the past 24 hours). Changing any metric attribute value creates a different time series for that metric. For example, CPU utilization grouped by `host.name` produces one time series per host. ### Supported metric types Honeycomb supports the following [OpenTelemetry metric types](https://opentelemetry.io/docs/concepts/signals/metrics/): * **Gauges**: A snapshot of a value at a point in time, such as current memory usage * **Counters and sums**: Cumulative or delta counts of something over time, such as total requests served * **Histograms**: A distribution of values, such as request latency bucketed by duration ### Connecting your metrics pipeline Honeycomb is built on the [OpenTelemetry Metrics Data Model](https://opentelemetry.io/docs/concepts/signals/metrics/), which means your existing OpenTelemetry metrics pipeline works without modification. If you are already sending OTLP metrics, you can point them at Honeycomb and start exploring your data immediately. No instrumentation changes are required. Honeycomb stores metrics in a dedicated *metrics dataset*, separate from your traces and logs, to keep your data organized and make querying more predictable. ### Automatic handling Honeycomb handles a few things automatically: * **Automatic aggregation defaults:** Honeycomb selects the appropriate temporal aggregate for each metric type. Counters and cumulative sums default to `RATE()`, gauges default to `LAST()`, and histograms are handled as distributed structures. You can override these defaults in your queries. * **Native histogram support:** Honeycomb stores histograms as distributed data structures rather than pre-bucketed values. This enables accurate percentile calculations (p95, p99) and flexible merging across time windows and grouped dimensions. * **Calculated fields:** Apply temporal logic and derived calculations directly in your queries without modifying your dataset schema, so you can compute ratios or rates on the fly. ## How to query metrics Querying metrics works the same way as querying any other data in Honeycomb. You use the Query Builder, filter and group by resource attributes, and visualize results as time series charts. Metrics queries support *temporal aggregation functions*, which account for the time-based nature of metric data: * `RATE(metric)`: Calculates the per-second rate of change of a counter or cumulative sum * `INCREASE(metric)`: Calculates the difference between the first and last values within each time step, accounting for counter resets * `LAST(metric)`: Returns the most recent value for each time step * `SUMMARIZE(metric)`: Sums all data points in a step, interpolating at step boundaries to avoid double-counting and gaps To learn more about how temporal aggregation works and when to use each function, visit [Temporal Aggregation](/investigate/query/temporal-aggregation) and [Applying Temporal Aggregation Functions](/investigate/query/apply-temporal-aggregation). Metrics queries also support *spatial aggregation* (comparing values across multiple time series at the same point in time) and [Query Math](/investigate/query/math), which lets you build multi-step queries with inline mathematical formulas to calculate ratios, percentages, and other derived values. ## How metrics work with traces and logs Metrics give you high-resolution continuous data over time. Events give you the rich context of what happened in a specific request. Having both in Honeycomb means you can move between signals without switching tools. ### Correlations When you run an events-based query, Honeycomb automatically surfaces relevant metrics in the **Correlations** view below your query results. For example, if you are investigating a latency spike, you can explore CPU utilization, memory usage, or network throughput for the relevant hosts alongside your query results. Correlations also appear at the span level in trace waterfalls, surfacing infrastructure metrics for the resource associated with a specific span. To learn more, visit [Correlations](/investigate/analyze/correlate). ### Metrics-based Triggers You can alert on metrics data using the same Trigger system you use for events, with the same notification destinations and reliability. Metrics-based Triggers support temporal aggregation functions, so you can alert on rates and trends rather than just raw values. To learn more, visit [Metrics-based Triggers](/notify/triggers/metrics). ### Boards Add metrics queries to Boards alongside event queries to build a unified view of system health. To learn more, visit [Boards](/investigate/observe/boards). ## When to use metrics Metrics and events serve different purposes and work best together. Use metrics when you want to: * Track the health and resource usage of infrastructure such as hosts, containers, and Kubernetes nodes * Monitor high-volume numeric signals at regular intervals, such as request rates or error counts * Alert on threshold conditions over time using rates and trends * Get a continuous picture of known quantities: things you always care about, regardless of what any individual request is doing Use events (traces and logs) when you want to: * Understand what happened during a specific request or transaction * Debug a problem by examining individual spans, errors, or log lines * Ask open-ended questions across high-cardinality dimensions you didn't anticipate in advance * Identify outliers and unusual patterns using BubbleUp In practice, you will often use both. A metrics alert surfaces a problem; a trace investigation tells you why it happened. ## Metrics and your plan Honeycomb measures metrics usage in *data points per month (DPPM)*. Each plan includes a data point allotment on top of your event allotment. To see the data point allotment for your plan, visit [Honeycomb Pricing Plans](https://www.honeycomb.io/pricing). Honeycomb counts the metric observations you send, not the number of unique time series those observations belong to. High-cardinality attributes, such as host IDs, pod IDs, or CI job IDs, can create many short-lived time series, but they do not add a separate per-series billing charge. To understand what counts as a data point, visit [How Honeycomb Calculates Usage](/get-started/manage-costs/how-honeycomb-calculates-usage#how-we-define-a-data-point). Data point usage is tracked and throttled independently from events, using the same overage model. To learn how Honeycomb measures usage, handles overages, and applies burst protection for both events and data points, visit [How Honeycomb Calculates Usage](/get-started/manage-costs/how-honeycomb-calculates-usage). ## Next steps * [Send application metrics to Honeycomb](/send-data/metrics/application) * [Send system metrics with the OTel Collector](/send-data/metrics/system) * [Set up a Metrics-based Trigger](/notify/triggers/metrics) * [Correlate metrics with your event queries](/investigate/analyze/correlate) # Pricing Plans Source: https://docs.honeycomb.io/get-started/honeycomb/pricing Compare Honeycomb's pricing plans and included features. # Honeycomb Private Cloud Source: https://docs.honeycomb.io/get-started/honeycomb/private-cloud Run the full Honeycomb observability platform in your own infrastructure for enhanced data governance, regulatory compliance, and infrastructure control. Honeycomb Private Cloud brings the observability platform you know into your own infrastructure. You get enhanced data governance, regulatory compliance, and complete infrastructure control, all while keeping the Honeycomb experience your teams rely on. ## What is Honeycomb Private Cloud? Honeycomb Private Cloud is a deployment option that runs Honeycomb in your cloud account instead of on Honeycomb's infrastructure. It uses the same architecture and codebase as Honeycomb SaaS, so the full Honeycomb feature set is available. The key difference is that you control where your data lives and how your infrastructure is configured. Honeycomb Private Cloud works well for organizations that need to: * **Control data governance:** Keep your telemetry data in your environment and maintain full control over data location and access. * **Meet regulatory requirements:** Comply with HIPAA, PCI DSS, FedRAMP, or industry-specific regulations that mandate data residency or isolation. * **Optimize cloud costs:** Apply your existing cloud discounts, Reserved Instances, or Savings Plans to your observability infrastructure. * **Maintain network isolation:** Operate in air-gapped or highly restricted network environments with strict egress controls. * **Customize resource allocation:** Configure infrastructure with adjustable rate limits and dedicated resources for your telemetry volume. Honeycomb Private Cloud runs on AWS, but support for additional cloud platforms is on our roadmap. If you need support for other cloud platforms, let your Honeycomb account team know which platform matters most to you! Your feedback helps us prioritize future development. ## Key Capabilities Honeycomb Private Cloud runs on the same codebase as Honeycomb SaaS, so you have complete feature parity: * **Query high-cardinality data in real-time:** Process millions of events per second with Honeycomb's custom column store. * **Explore telemetry with AI:** Use Canvas for natural language queries and MCP for automated anomaly detection. * **Trace distributed systems:** Understand complex service interactions and identify bottlenecks with Honeycomb's tracing model. * **Query any field:** Analyze data across unlimited custom dimensions without pre-aggregation or indexing delays. * **Resolve issues in real-time:** Identify and fix problems as they happen, not after the fact. You also get the same query performance, APIs, integrations, user interface, and workflows. Private Cloud deployments receive weekly updates with minimal lag behind the latest platform features. ## Deployment Flexibility Honeycomb Private Cloud offers these [deployment models](/private-cloud/deployment-models/): * **[Honeycomb-managed](/private-cloud/deployment-models/#honeycomb-managed):** Honeycomb handles deployment, operations, upgrades, and monitoring while your data stays in your environment. * **[Self-managed](/private-cloud/deployment-models/#self-managed):** Your team deploys and operates Honeycomb with support and upgrade guidance from Honeycomb. Both models support [single-tenant or multi-tenant configurations](/private-cloud/tenancy-options/), so you can balance isolation requirements with operational efficiency. ## Architecture Honeycomb Private Cloud uses multiple cloud services including compute, caching, databases, and object storage. The architecture distributes across multiple availability zones for high availability and scales horizontally to meet your throughput requirements. Your Honeycomb deployment integrates with: * Your authentication provider (Okta, SAML, or other identity providers) * Your email gateway for notifications * Your Slack workspace (via custom Slack app) * GitHub (via custom GitHub app for deployment gates) To learn more about the technical architecture, visit [Honeycomb Private Cloud Architecture](/private-cloud/architecture/) # Honeycomb Private Cloud Architecture Source: https://docs.honeycomb.io/get-started/honeycomb/private-cloud/architecture Find out how Honeycomb Private Cloud is architected, including AWS services used, infrastructure components, scaling, networking, and high availability. Honeycomb Private Cloud runs on the same architecture that powers Honeycomb's SaaS platform, delivering high-speed query performance, AI-native intelligence, and scalable telemetry processing within your AWS environment. ## Architecture Principles Honeycomb Private Cloud uses a distributed, service-oriented architecture designed for performance, scalability, and reliability: * **Horizontally scalable**: Components scale by adding instances rather than increasing individual resource size * **High availability**: Resources distributed across multiple AWS Availability Zones (AZs) for resilience * **Service separation**: Distinct components for ingestion, query processing, storage, and user interface * **Real-time processing**: Event data available for query immediately upon ingestion ## Core Components Your Private Cloud deployment includes: * **Ingestion pipeline**: Receives and processes telemetry data from your applications * **Query engine**: Honeycomb's custom column store for high-speed, high-cardinality queries * **Storage layer**: Durable persistence of telemetry events * **Web application**: Honeycomb UI for exploration, analysis, and visualization * **AI services**: Canvas and MCP for intelligent telemetry exploration * **API services**: Programmatic access for integrations and automation * **Metadata services**: User management, authentication, and configuration ## AWS Infrastructure Honeycomb Private Cloud leverages multiple AWS services: * **Compute**: EC2, EKS, ECS, Lambda * **Storage**: S3, RDS * **Caching**: ElastiCache (Redis, Memcached) * **Networking**: VPC, subnets, load balancers * **Configuration**: SSM Parameter Store * **High Availability**: Multi-AZ, automatic failover, redundant caching * **AI**: Bedrock This list is not exhaustive. ## Infrastructure Requirements To ensure Honeycomb Private Cloud runs smoothly, you need infrastructure that matches your telemetry volume, query patterns, and availability needs. ### Resource Sizing Sizing depends on your telemetry volume and query patterns. Honeycomb provides sizing recommendations based on: * **Expected events per second**: Peak and average telemetry ingestion rate * **Concurrent users**: Number of people actively using Honeycomb * **Query patterns**: Frequency and complexity of queries * **Data retention**: How long telemetry data is kept * **Growth projections**: Expected increase in telemetry volume Work with your Honeycomb account team during planning to determine appropriate infrastructure sizing for your deployment. ### Inbound Traffic Your Honeycomb deployment receives: * Telemetry data from your applications and services * User traffic to the Honeycomb UI (web browser access) * API requests from integrations and automation ### Outbound Traffic Your Honeycomb deployment connects to: * Your authentication provider (SAML/Okta IdP) * Your email gateway (for notifications) * Your Slack workspace (if using Slack integration) ## Integration Requirements Honeycomb Private Cloud connects with your existing systems for secure access, alerts, and team collaboration. Key integrations include: * **Authentication**: SAML 2.0, ADFS, other SAML 2.0-compliant IdPs * **Email notifications**: SMTP relay or email gateway * **Slack (optional)**: Custom app installation and OAuth token * **GitHub (optional)**: Custom GitHub app for deployment gates ## Deployment-Specific Requirements Detailed deployment and networking guidance will be provided closer to deployment. To learn more about operational responsibilities, visit [Deployment Models](/private-cloud/deployment-models/). ## Limitations To guide your deployment decisions, note these constraints: * **AWS GovCloud regions:** AI model access differs, which may affect how Canvas and MCP features work. # Honeycomb Private Cloud Deployment Models Source: https://docs.honeycomb.io/get-started/honeycomb/private-cloud/deployment-models Choose between Honeycomb-managed and self-managed Private Cloud deployments based on your team's operational capabilities and compliance requirements. Honeycomb Private Cloud offers two deployment models to match your operational capabilities and compliance requirements. The difference is who manages the infrastructure. ## Honeycomb-Managed Honeycomb handles all operational aspects of your Private Cloud instance, including installation, upgrades, monitoring, and scaling. You get Honeycomb's operational expertise while keeping the data governance and compliance controls your organization requires. Honeycomb-managed deployments offer two hosting options: ### Honeycomb-Hosted Honeycomb manages and operates your deployment within Honeycomb-controlled cloud infrastructure. You get: * **Hands-off infrastructure management**: Honeycomb handles everything. * **Optimized performance**: Benefit from infrastructure tuned by Honeycomb's platform team. * **Simplified billing**: No separate cloud infrastructure costs to track. * **Faster time to production**: Get up and running quickly with pre-configured environments. This works well for organizations that want dedicated infrastructure and data isolation without managing resources. ### Customer-Hosted Honeycomb manages and operates your deployment within your cloud account. You get: * **Complete data residency control**: Your telemetry data never leaves your cloud account. * **Full network control**: Keep your organization's network security boundaries intact. * **Regulatory compliance**: Meet requirements for data to stay within your governance structure. * **Cost flexibility**: Apply your existing cloud discounts, Reserved Instances, or Savings Plans. This works well for regulated industries that need data to stay fully under their governance. ### What Honeycomb Manages With both Honeycomb-managed options, Honeycomb handles: * **Installation and configuration**: Initial deployment and setup of all components. * **Upgrades and updates**: Weekly deployment of platform updates. * **Monitoring and operations**: 24/7 monitoring of platform health and performance. * **Scaling**: Infrastructure adjustments to meet changing telemetry volumes. * **Incident response**: Resolution of platform-level issues. * **Security patches**: Timely application of security updates. ### What You Manage Your team handles: * **Authentication**: Integration with your identity provider (for example, Okta or SAML). * **Email gateway**: Configuration for notification delivery. * **Slack integration**: Custom Slack app setup (if using Slack notifications). * **User management**: Honeycomb user provisioning and access control. * **Telemetry sources**: Instrumenting applications and sending data to Honeycomb. * **Cloud account management**: Cloud account administration (for customer-hosted deployments). ## Self-Managed Your team manages all infrastructure. Honeycomb provides the software, support, and upgrade guidance. This works well for organizations with highly secure, air-gapped, or tightly controlled environments that require complete infrastructure autonomy and have the operational maturity to manage complex distributed systems. ### What You Control Self-managed deployments give you: * **Complete infrastructure autonomy**: Manage all cloud resources and configurations however you want. * **Flexible update timing**: Apply updates according to your internal policies and change windows. * **Custom infrastructure**: Adjust resource allocation, networking, and scaling to your exact needs. * **Security control**: Implement your organization's security tools, monitoring, and compliance frameworks. * **Air-gapped capability**: Deploy in highly restricted or disconnected environments. ### What Honeycomb Provides Honeycomb supports your self-managed deployment with: * **Deployment guidance**: Get documentation and best practices for installation. * **Upgrade packages**: Receive weekly release packages with update instructions. * **Technical support**: Access Enterprise support channels for troubleshooting and guidance. * **Architecture advice**: Get recommendations for sizing, scaling, and optimization. * **Security advisories**: Receive timely notification of security issues and patches. ### What You Manage Your team handles: * **Infrastructure provisioning**: Set up all required cloud resources. * **Installation and configuration**: Deploy initial Honeycomb components. * **Upgrades and updates**: Apply updates according to your schedule. * **Monitoring and operations**: Watch platform health and respond to incidents. * **Scaling**: Adjust infrastructure to meet demand. * **Backup and disaster recovery**: Implement and test disaster recovery procedures. * **Security management**: Apply security patches and maintain compliance. * **Integration management**: Configure authentication, email gateway, and Slack integration. ## Choosing a Deployment Model Consider these factors when choosing between Honeycomb-managed and self-managed: | Factor | Honeycomb-Managed | Self-Managed | | -------------------------- | ------------------------------------------------ | -------------------------------------------- | | **Operational overhead** | Low | Medium to high | | **Update deployment** | Weekly, managed | Weekly packages | | **Infrastructure control** | Shared (customer-hosted) or Honeycomb-controlled | Complete control | | **Best for** | Focus on observability | Complete autonomy or air-gapped environments | Both models include enterprise support and full Honeycomb capabilities and performance. # Honeycomb Private Cloud Tenancy Options Source: https://docs.honeycomb.io/get-started/honeycomb/private-cloud/tenancy-options Configure Honeycomb Private Cloud as single-tenant for maximum isolation or multi-tenant for organizational separation. Compare isolation levels and use cases. Honeycomb Private Cloud can be configured as single-tenant or multi-tenant to match your organizational structure and isolation requirements. Both [Honeycomb-managed](/private-cloud/deployment-models/#honeycomb-managed) and [self-managed](/private-cloud/deployment-models/#self-managed) deployment models support either tenancy option. ## Single-Tenant A single-tenant deployment gives you a dedicated Honeycomb environment with complete isolation from other tenants. Single-tenant deployments work well for organizations that need to: * **Maximize isolation**: Get complete separation at the infrastructure level with no shared resources. * **Meet strict compliance requirements**: Satisfy regulatory mandates that require dedicated infrastructure. * **Guarantee data privacy**: Ensure telemetry data has no possibility of cross-tenant exposure. * **Isolate performance**: Guarantee that your workload performance is unaffected by other tenants. * **Customize resource allocation**: Configure infrastructure specifically for your telemetry patterns and volume. Single-tenant configurations are common in financial services with strict regulatory requirements, healthcare organizations subject to HIPAA or other health data protection regulations, government agencies requiring FedRAMP or other government compliance certifications, and high-volume enterprises with massive telemetry volumes that require dedicated, optimized infrastructure. ### Architecture In a single-tenant deployment: * All infrastructure components serve only your organization * No resources are shared with other Honeycomb customers * Your data stays completely isolated from other tenants * Infrastructure can be sized and optimized specifically for your workload ## Multi-Tenant A multi-tenant deployment provides logical separation within shared infrastructure between teams or business units. Multiple groups maintain autonomy while benefiting from operational efficiency. Multi-tenant deployments work well for organizations that need to: * **Separate by organization**: Create distinct Honeycomb environments for different business units, regions, or teams. * **Improve operational efficiency**: Share infrastructure management across multiple groups. * **Optimize costs**: Distribute infrastructure costs across multiple teams or business units. * **Enable team autonomy**: Give each group their own Honeycomb environment with independent user management and configuration. Multi-tenant configurations are common in large enterprises with multiple business units that need separate observability environments. ### Architecture In a multi-tenant deployment: * Multiple Honeycomb environments run within shared infrastructure * Each tenant has logical isolation with independent: * User authentication and authorization * Data storage and access controls * Configuration and settings * API keys and integrations * Infrastructure resources are shared across tenants for efficiency * Each tenant maintains operational independence ## Comparing Tenancy Options | Aspect | Single-Tenant | Multi-Tenant | | ---------------------------- | -------------------------------- | ----------------------------------------------------- | | **Infrastructure isolation** | Complete | Logical | | **Data isolation** | Physical and logical | Logical only | | **Compliance suitability** | Highest | suitable for most enterprise needs | | **Performance isolation** | Guaranteed | Shared | | **Administrative overhead** | Single environment | Multiple environments | | **Cost efficiency** | Higher | Lower through sharing | | **Scalability** | Dedicated | Shared | | **Best for** | Maximum isolation and compliance | Organizational separation with operational efficiency | ## Combining Tenancy and Deployment Models You can combine tenancy options with deployment models to match your specific needs: * **Single-tenant, Honeycomb-managed**: Maximum isolation with minimal operational overhead * **Single-tenant, self-managed**: Complete control and isolation for highly regulated or air-gapped environments * **Multi-tenant, Honeycomb-managed**: Efficient support for multiple teams with Honeycomb handling operations * **Multi-tenant, self-managed**: Organizational flexibility with complete infrastructure control # Honeycomb Resource Structure Source: https://docs.honeycomb.io/get-started/honeycomb/resource-structure Understand the organizational structure of Honeycomb: teams, environments, datasets, and events. Honeycomb organizes your telemetry data into a hierarchy: teams contain environments, environments contain datasets, and datasets contain event or metrics data, depending on dataset type. Understanding this structure helps you instrument your systems effectively, manage access, and get the most out of Honeycomb's query capabilities. ## Events An *event* is a structured record of a single unit of work. It captures what happened, when it happened, how long it took, and any contextual information you choose to include, such as user IDs, feature flags, error messages, build IDs, and environment names. Events are JSON objects sent over HTTP. Every *field* in an event is labeled and indexed automatically, which means Honeycomb can filter, group, and aggregate on any field without knowing about it in advance. You don't need to define your schema ahead of time or decide which fields to index before you know what questions you want to ask. Fields appear in the Query Builder as soon as they arrive. Traces and logs arrive in Honeycomb as structured events. Metrics arrive as time-series data points in dedicated metrics datasets. To learn how each signal maps to the event model, visit [Traces, Metrics, and Logs](/get-started/honeycomb/traces-metrics-logs). ## Datasets A *dataset* is a collection of related from a single service or data source. Trace and log datasets contain events; metrics datasets contain time-series data points. Honeycomb can create a dataset automatically when you first send data if your API key is allowed to do so. With OpenTelemetry and Environments, your service name is often the dataset name for new datasets. All events in a dataset share the same schema, which is the set of fields Honeycomb has seen across all events sent to that dataset. Some dataset conventions: * Trace datasets contain spans with `trace.trace_id`, `trace.span_id`, and `duration_ms` fields. * Log datasets contain events with a `body` field or a field mapped to `Logs: Message`. * Metrics datasets contain time-series data points built on the OpenTelemetry Metrics Data Model. To learn how to configure and manage datasets, visit [Manage Datasets](/configure/datasets/manage). ## Environments An *environment* groups datasets that you expect to analyze together. Environments typically separate data by deployment stage (Production, Staging, Development) or by regulatory boundary. Honeycomb queries run within a single environment by design. That boundary keeps production data separate from staging data and prevents accidental cross-environment analysis. Honeycomb has three API key types: * Ingest Keys send telemetry data to a specific environment. * Configuration Keys manage resources within an environment, such as Boards, Triggers, and SLOs. * Management Keys operate at the team level and manage API keys and environments across your whole team. The key you use to send data determines which environment receives it. To learn how to configure and manage environments, visit [Manage Environments](/configure/environments/manage). ## Teams A *team* is the top-level organizational unit in Honeycomb. It represents your organization and contains all of your environments, datasets, and members. When you sign up for Honeycomb, you create a team, typically named after your company or organization. Team members have roles that control what each person can do. To learn about available roles, visit [Manage team permissions](/configure/teams/manage-permissions/). ## Related pages * [Traces, Metrics, and Logs](/get-started/honeycomb/traces-metrics-logs): How each telemetry signal maps to Honeycomb's event model * [Manage Datasets](/configure/datasets/manage): How to create, configure, and delete datasets * [Manage Environments](/configure/environments/manage): How to create and configure environments * [Best Practices for Organizing Data](/get-started/best-practices/organizing-data): Recommendations for structuring environments and datasets * [Map Your Data](/send-data/standardize/map-data): How to map field names to Honeycomb standard fields # Traces, Metrics, and Logs Source: https://docs.honeycomb.io/get-started/honeycomb/traces-metrics-logs Understand the telemetry signals Honeycomb supports, how each one works, and how they fit together. Honeycomb supports three telemetry signals: traces, metrics, and logs. Each one captures different information about your system and works best for different kinds of questions. ## How signals work in Honeycomb In Honeycomb, traces and logs are stored as *structured events*: labeled JSON objects sent over HTTP, indexed automatically on every field at ingest, and queryable without a predefined schema. Metrics are different; they arrive as time-series data points in dedicated metrics datasets rather than as events. Understanding this distinction helps explain why each signal is queried differently in Honeycomb. To learn how Honeycomb organizes events into datasets, environments, and teams, visit [Honeycomb Resource Structure](/get-started/honeycomb/resource-structure). ## Traces A *trace* is a record of a request as it travels through your system. It is made up of *spans*, each representing one unit of work, such as a database query or a service call. Spans share a trace ID that identifies which trace they belong to. In Honeycomb, each span is stored as a structured event: a labeled JSON object you can filter, group, and aggregate on any field. Honeycomb uses the parent-child relationships between spans, expressed via `trace.parent_id` and `trace.span_id`, to render a waterfall view of execution flow across your services. Traces are the right signal when you want to: * Follow a specific request across multiple services * Understand execution flow and latency at the span level * Correlate errors or slowdowns with the exact code path that produced them You create trace spans by instrumenting your code with OpenTelemetry. This example creates a span, adds context as attributes, and closes it when the work is done: ```python theme={} from opentelemetry import trace from opentelemetry.sdk.trace import TracerProvider # Set up the tracer provider = TracerProvider() trace.set_tracer_provider(provider) tracer = trace.get_tracer("my-service") # Create a span (event) with rich context with tracer.start_as_current_span("bucketRequest") as span: span.set_attribute("http.request.method", "GET") span.set_attribute("app.group_bucket", 11) span.set_attribute("db.rows_returned", 42) # do some work ``` Here is an example of what a span looks like as a structured event in Honeycomb: ```json theme={} { "service.name": "retriever", "service.version": "1.4.2", "deployment.environment": "production", "host.name": "retriever-0a8b688312e490d1c", "host.type": "m6gd.2xlarge", "cloud.availability_zone": "us-east-1a", "http.request.method": "GET", "url.path": "/api/v1/bucketRequest", "http.response.status_code": 200, "http.response_content_length": 2326, "app.group_bucket": 11, "app.query_source": "trigger-cron", "app.total_segments": 0, "app.flag.golden_retrievers": false, "db.system": "postgresql", "db.name": "datasets", "duration_ms": 11.668, "build.id": 275663, "build.commit_hash": "9cb3de12faf709cdc9bca5c9900e8259c1719b02", "process.pid": 7585, "process.uptime_seconds": 2298, "trace.trace_id": "845a4de7-8e3a-4605-8476-6aa1592c3134", "trace.span_id": "84c82b34145c22f9", "trace.parent_id": "ab0e166fbbea7dc6" } ``` With OpenTelemetry, Honeycomb calculates `duration_ms` from each span’s start and end time during ingest. Every field is available for querying. You can group by `service.name`, filter by `http.response.status_code`, compute a P95 on `duration_ms`, or use BubbleUp to identify which dimensions differ most across a selected region of your data. To learn how to send traces to Honeycomb, visit [Send Data](/send-data). ## Metrics A *metric* is a numeric measurement of something in your system, captured at regular intervals over time. Metrics describe the state or behavior of a resource (a host, a service, a database connection pool) rather than a specific unit of work. Honeycomb supports metrics as a native signal built on the [OpenTelemetry Metrics Data Model](https://opentelemetry.io/docs/concepts/signals/metrics/), including gauges, counters, sums, and histograms. Metrics are ingested as time-series data points in dedicated metrics datasets and are queried with metric-specific functions like `RATE()`, `INCREASE()`, and `LAST()` that account for the time-based nature of metric data. Metrics are the right signal when you want to: * Monitor infrastructure health consistently: CPU utilization, memory usage, request rates * Alert on threshold conditions over time using rates and trends * Track known quantities you always care about, regardless of what any individual request is doing To learn more, visit [Metrics in Honeycomb](/get-started/honeycomb/metrics-in-honeycomb). ### How Honeycomb metrics differ from pre-aggregated metrics Some systems emit *pre-aggregated metrics*: rollups computed before write time, such as totals, averages, and percentiles calculated before sending to Honeycomb. Pre-aggregated metrics are efficient to produce, but they have a fundamental limitation: you can only ask questions that were anticipated at instrumentation time. For example, if you want to know how your system performs when the storage engine has a cache hit, that dimension needs to have been included in the pre-aggregated rollup: ```txt theme={} { time: 4:03 pm, duration_sec: 60, total_hits: 500, avg_duration: 113, p95_duration: 236, ... (and so on) ... } ``` Adding a new dimension, such as cache hit status, means adding new rows for every combination: `avg_duration_cache_hit_true`, `avg_duration_cache_hit_false`, `p95_duration_cache_hit_true`, and so on. Each new dimension multiplies the number of pre-aggregated rows required; this is the "curse of dimensionality." In contrast, Honeycomb's native metrics preserve the full resolution of your data and let you ask questions at query time rather than instrumentation time. To see this difference in practice, refer to the [Events vs. Pre-aggregated Metrics](#events-vs-pre-aggregated-metrics) section. ## Logs A *log* is a record of a discrete event in your system: an error, a state change, a user action, or any output your application emits at a specific point in time. Honeycomb receives logs as structured events, which means you can query them the same way you query trace data. ### Structured logs A *structured log* has consistent, labeled fields, like JSON output from an application logger or similar to what you might expect to see in a spreadsheet or a comma-separated-value file. Because of this structure, a structured log maps naturally to a structured event: its fields become event fields, immediately queryable in the Query Builder. Here is an example of a structured log line: ```txt theme={} host-ip username datetime cmd URL protocol status size 127.0.0.1 frank 10/Oct/2000:13:55:36 GET /apache_pb.gif HTTP/1.0 200 2326 ``` For new services, the recommended path is to send structured logs via OpenTelemetry, which maps log fields directly to event fields and enables automatic trace correlation. [Honeytail](/send-data/logs/structured/honeytail/) is a tool that can ingest existing structured log files for legacy setups and emit structured events. ### Unstructured logs An *unstructured log* is a sequence of free-form messages, convenient for a person to read but harder to query. When Honeycomb starts its `retriever` service, the console prints something like this: ```log theme={} Running serve cmd: cd cmd/retriever && go run main.go -debug -reader time="2021-01-06T17:44:13-08:00" level=info msg="I'm a reader, using RPC for dataset flushes" DEBU[2021-01-06T17:44:13.368024402-08:00] starting *secrets.YamlSecrets DEBU[2021-01-06T17:44:13.368461794-08:00] starting *retrieverclient.YamlConfig named retriever_config DEBU[2021-01-06T17:44:13.368679356-08:00] starting *config.YamlConfig DEBU[2021-01-06T17:44:13.369046236-08:00] starting *s3.DefaultService DEBU[2021-01-06T17:44:13.369518352-08:00] starting *lambda.DefaultService WARN[2021-01-06T17:44:13.369694698-08:00] debug http server error error="listen tcp 127.0.0.1:6060: bind: address already in use" INFO[2021-01-06T17:44:13.369727168-08:00] Debug service listening on localhost:6061 DEBU[2021-01-06T17:44:13.369728616-08:00] starting *beelineinit.Beeline WARN[2021-01-06T17:44:13.369839218-08:00] debug http server error error="listen tcp 127.0.0.1:6061: bind: address already in use" INFO[2021-01-06T17:44:13.369933256-08:00] Debug service listening on localhost:6062 DEBU[2021-01-06T17:46:15.618320662-08:00] starting *app.ReadApp INFO[2021-01-06T17:46:15.618436383-08:00] Serving at 0.0.0.0:8089... INFO[2021-01-06T17:47:15.618821038-08:00] I'm alive. 2021-01-06 17:47:15.618683749 -0800 PST m=+60.893288862 ``` To understand what happened during startup, you need to read a whole sequence of lines, and even then causality is hard to establish. To find out how long the service took to start, you would need to subtract timestamps from each other. To find out whether an error occurred during startup, you would have to search for lines. Imagine summarizing the same startup as a single structured event: ```txt theme={} { cmdline: "cd cmd/retriever && go run main.go -debug -reader", startTime: "2021-01-06T17:44:13-08:00", mode: "reader", yamlSecrets_offset: "368024402", yamlConfig_offset: "13.368461794", debug_http_error: "listen tcp 127.0.0.1:6061: bind: address already in use", servicePort: 8089, duration_ms: 180262 ... } ``` In this format, you can query for questions like "Which services take the longest to start?" or "Do any slow startups correlate with particular error states?" To learn more, visit [Logs in Honeycomb](/get-started/honeycomb/logs-in-honeycomb). ## Using signals together Honeycomb supports all three signals in the same platform, so you can move between them without switching tools. A common investigation pattern: * A metrics alert surfaces a problem: error rate is elevated. * A log query narrows the scope: these specific error messages are occurring most frequently. * A trace investigation explains the cause: this is where in the request execution the error originates. ### Correlations When you run an events-based query, Honeycomb surfaces related metrics in the **Correlations** view when metrics data exists for your environment. For example, if a latency spike coincides with a host running out of memory, you can see both signals side by side without leaving the Query Builder. To learn more, visit [Correlations](/investigate/analyze/correlate). ### Metrics-based Triggers You can alert on metrics data using the same Trigger system you use for events. A metrics alert can tell you that something is wrong; a trace investigation tells you why. To learn more, visit [Metrics-based Triggers](/notify/triggers/metrics). ### Logs as events Because Honeycomb receives logs as events, you can query log data the same way you query any other dataset: filter, group, and aggregate across any field. To learn more, visit [Logs in Honeycomb](/get-started/honeycomb/logs-in-honeycomb). ## Managing data volume If event volume is a concern, you can sample your data to reduce volume while keeping aggregates statistically accurate. For example, you could send one in a hundred `status:200`s but send every `status:500`. When your instrumentation includes a `sample_rate` on each event, Honeycomb uses it to scale counts so query results reflect your true traffic volume. To learn more, visit [Sampling Guidelines](/manage-data-volume/sample/guidelines). For metrics, factors like your collection interval and the number of active time series affect how many data points you send. To learn more, visit [Manage Metrics Data Volume](/manage-data-volume/adjust-granularity/metrics-events) and [How Honeycomb Calculates Usage](/get-started/manage-costs/how-honeycomb-calculates-usage#how-we-define-a-data-point). ## Code examples The following examples show how the same piece of code can be instrumented in different ways and how the outputs differ. Understanding these differences helps you choose the right signal for each job. ### Events vs. pre-aggregated metrics Events vs. Metrics In this example, the left side is instrumented with events, the right with pre-aggregated metrics. Both capture the duration, but the output is quite different. Events are built up over time, gaining context as they go, whereas pre-aggregated metrics are updated individually and don't carry that same context. #### Events output In this example, Honeycomb was used for events. Although a graph was rendered, the raw data gives a more equal comparison. Events Output #### Pre-aggregated metrics output In this example, pre-aggregated metrics were used. Pre-aggregated Metrics Output #### Comparison Both examples capture the duration in milliseconds and how many times the example app was run. At first glance, the metrics output appears to have more data, but all of those values can be calculated from the event data at query time. Pre-aggregated metrics tools need to do this calculation before write time, which limits what you can ask later. Events let you add richer context, like input, output, and timestamps, and compute any aggregation at query time. ### Events vs. unstructured logs Events vs. Logs The example on the left is instrumented with events, the one on the right with logs. Both capture the duration in milliseconds. With events, duration is available as `duration_ms` on the stored span. With logs, you write it as part of a log statement. In this example, the timestamp for each log statement is included inline and can be parsed out with regex. Each log line includes a description of the data followed by the value itself, in this case, the duration in milliseconds. #### Events output In this example, Honeycomb was used for events. Although a graph was rendered, the raw data gives a more equal comparison. Events Output #### Logs output The logged output: Logs Output #### Comparison All the information is included in both outputs, but events let you see patterns in your data much faster. Both outputs show that one request was much slower than the other. With events, that's visible at a glance. With logs, you have to read through the entire output to find the duration lines and match them to the right input and output. ### Summary All three approaches take roughly the same amount of time and effort to implement. The events and pre-aggregated metrics required slightly more setup initially because they needed configuration with an outside service. For logs, if you are doing more than writing to a terminal, you will need a similar amount of setup. # Manage Costs Source: https://docs.honeycomb.io/get-started/manage-costs Predict and control your Honeycomb costs. Find out how usage is measured, how overages are handled, and how to optimize your implementation to reduce spend. You may not always be able to predict your systems' behaviors, but you should be able to predict your costs, understand how your team's use of Honeycomb is evolving over time, and know how to optimize your implementation to manage costs. Predict your costs. Understand how Honeycomb measures usage, predicts and handles overages, and retains data. # How Honeycomb Calculates Usage Source: https://docs.honeycomb.io/get-started/manage-costs/how-honeycomb-calculates-usage Track how Honeycomb measures your usage in events per month and metrics data points, how Honeycomb predicts and handles overages, and how data retention works across your plan. Honeycomb gives you full visibility into your costs so you can track how your Team's usage evolves over time. ## How we measure usage Honeycomb measures two types of usage: events and metrics data points. All Teams on Free and Pro pricing plans have specific monthly limits for both. For Teams on Enterprise pricing plans, Honeycomb calculates the associated events per month (EPM) limit based on the events per year (EPY) for their annual plan. ## How we define an event An event is a collection of information about what it took to complete a unit of work. For example, accepting an HTTP request, doing the required work, and then passing back a response counts as one event. In traces, which are complex requests that comprise many spans, each span represents a unit of work, so Honeycomb counts each span in a trace (`SpanEvent` or `Link` in OpenTelemetry and OpenCensus) as an event. For example, Honeycomb counts a trace that contains 150 spans as 150 events. To learn more about the format and size of events that Honeycomb accepts, visit [Honeycomb Event API](/api/events/) and [OpenTelemetry](/send-data/opentelemetry/). ## How we define a data point [Time series metrics](/get-started/honeycomb/metrics-in-honeycomb/) data is defined with data points. If you use events-based metrics, Honeycomb stores your metrics as events and calculates usage accordingly. A data point is a single metric measurement captured at a point in time for a specific time series. A time series is a sequence of data points for a single metric with a consistent set of attributes (for example, CPU utilization for a specific host). Honeycomb counts data points based on the number of individual metric observations successfully ingested. Honeycomb does not bill time series metrics by the number of unique time series. Changing attribute values, such as new host IDs or CI job IDs, creates new time series, but it only changes DPPM usage when it changes the number of metric observations you send. Data points that don't count against your DPPM limit include: * Data points Honeycomb rejects due to operational rate limiting or excessive size * Malformed data points that Honeycomb can't ingest * Data points you filter before they reach Honeycomb ## What counts against Event Per Month (EPM) limits All successful events Honeycomb ingests count against your EPM limit. Events that don't count against the EPM limit include: * Events Honeycomb rejects due to operational rate limiting, excessive size, or malformation * Events your application samples before sending to Honeycomb, such as via Refinery, Beelines, or other sampling methods ## What counts against Data Point Per Month (DPPM) limits Each plan includes a data point allotment separate from your event allotment. Honeycomb tracks the two independently, so your Team can exceed one limit without affecting the other. To see the data point allotment for your plan, visit [Honeycomb Pricing Plans](https://www.honeycomb.io/pricing). ## How we predict overages Based on the EPM limit, Honeycomb calculates a daily event target (EPM divided by 30.4). Honeycomb calculates a daily data point target the same way, based on your DPPM limit. We base all event and data point counts on calendar month, regardless of when a team's billing renewal date may fall. You can see your EPM limit, your DPPM limit, and both daily targets in the Honeycomb UI under **Team Settings** > **Usage**. ## How we handle overages Honeycomb surfaces a usage state indicator in the UI for all teams. You can see your Team's warning state in the left-hand navigation menu, next to the **Usage** menu item. ### Events For Teams within their predicted limits, the usage state indicator is OK (green). For Teams on Free and Pro pricing plans in other states of overage, Honeycomb handles overages in the following ways: If your Team is on an Enterprise plan, you are exempt from throttling. To learn about overage handling for your Team, refer to your Honeycomb Enterprise order form, or contact us with any questions. | Status | Usage State | Response | | ------------------------------------------------------------------------------ | ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | A Team is trending toward a possible overage | Warning (Yellow) | Honeycomb notifies Team owners via email. | | A Team exceeds its EPM limit for one month | Warning (Yellow) | Honeycomb notifies Team owners via email at the beginning of the following month. | | A Team exceeds its EPM limit for a second consecutive month | Danger (Red) | Honeycomb notifies Team owners via email and warns them that Honeycomb will throttle incoming events unless they correct the overage within 10 days. Teams can correct the overage by upgrading to a higher capacity plan or by reducing the amount of data they send to Honeycomb. | | After 10 days, a Team's rate of incoming events remains above the daily target | Danger (Red) | Honeycomb begins throttling events. The Honeycomb Event API randomly accepts one of every ten events and rejects the remaining nine, which Honeycomb doesn't ingest or store. Throttling continues until the Team's rate of incoming events stays under the daily event target for at least 72 hours. | Throttling is a last resort, and we want to help you avoid it! If you receive a throttling notification, please contact us. ### Data points Data point overages follow the same warning, danger, and throttling states as event overages, with the same timeline: a second consecutive month of overage triggers a 10-day warning before throttling begins. ### Events and data points together Honeycomb tracks data point and event usage independently. Either limit can escalate your enforcement state on its own, but both event and data point usage need to stay within their limits for at least 72 hours before Honeycomb unthrottles your Team. When your Team has a metrics limit, throttling and overage emails show both your event and data point usage. ## How we handle bursts Burst protection applies to both events and data points for all Teams. When an unexpected spike creates a flood of data, Honeycomb automatically triggers burst protection so your Team can observe incidents without burning through your monthly limits. For events, when your Team sends more than 2x the daily event target in a single day, Honeycomb doesn't count the excess events against your EPM limit. For example, if your daily event target is 30 million events and your Team sends 90 million in one day, Honeycomb doesn't count the excess 60 million against your EPM limit. Burst protection works the same way for data points: when data point ingestion exceeds 2x your daily data point target, Honeycomb doesn't count the excess data points against your DPPM limit. Honeycomb tracks burst protection for events and data points separately. When Honeycomb triggers burst protection, it notifies Team owners via email. You can also see the effect of burst protection in the Honeycomb UI under **Team Settings** > **Usage**. While Honeycomb doesn't count burst protection events or data points against your monthly limits, Honeycomb still ingests and stores them, and they appear in the Per-Environment and Per-Dataset Breakdown sections. Burst protection can trigger up to three times per calendar month for events and up to three times per calendar month for data points. ## How we retain data Retention periods in Honeycomb depend on the type of data: * **Events and logs:** 60-day fixed retention. * **Time-series metrics datasets:** 13-month fixed retention by default. If your environment has a longer retention period configured, Honeycomb honors that longer period for your metrics dataset. Honeycomb calculates the retention period based on the date the events are ingested by Honeycomb rather than on the timestamps within the data. When a Team changes their plan (upgrading from Free to Pro, downgrading from Pro to Free, and so on), Honeycomb retains the Team's existing data up to the applicable retention period. If your Team wants us to retain your data for a shorter period of time or delete it for any reason, contact [Honeycomb Support](/troubleshoot/customer-support/) for assistance. ## Usage mode Normally, Honeycomb [applies sample rate weighting](/manage-data-volume/sample/sampled-data-in-honeycomb/) to calculations, but you can also run queries without it. For example, you might want to know how many actual events are coming in for each category for a dynamic sampler. *Usage mode* provides a query builder that evaluates queries in an unweighted mode where sample rate does not figure into the calculations. To access Usage Mode: 1. Select **Account** from the navigation menu, then select **Team Settings** and **Usage**. 2. Select the **Usage Mode** button on the appropriate row in the Per-environment Breakdown table. Warning for Usage Mode In Usage mode, you have access to the `Sample Rate` field, which reflects what Honeycomb interprets as the sample rate, and `COUNT` (and all other calculation operations) are unweighted. Use Usage mode to diagnose errors in your sampled data and understand how your sampling strategy affects relative changes over time. For example, you may find it useful to monitor the rate at which a dynamic sampler sends data. # Observability Concepts Source: https://docs.honeycomb.io/get-started/observability/concepts Build a foundation in the concepts of modern observability. Given the lack of observability training in official curriculums, many of us learned what we know from whatever ecosystem we were first introduced to and whatever observability solutions were implemented at our employers throughout our career. This method of piecing together information coupled with the breadth of types of telemetry, opinionated platforms, and data formats available today can make it challenging to wrap our heads around the concept of observability. Honeycomb hopes we can help with that by sharing the observability fundamentals that we think we should all know. To fully grasp observability, start with these concepts. Explore what OpenTelemetry is, why Honeycomb uses it as the standard for instrumentation, and how it relates to your telemetry data. Learn about distributed tracing, which helps tie together instrumentation from separate services, so you can understand complex processes. Learn about services, and how they are created and managed in Honeycomb. Learn what high cardinality and high dimensionality are, and understand what makes high cardinality data important. Understand what instrumentation is. Explore best practices and conceptual patterns for instrumenting applications. Learn about eBPF and why it is important to observability. # Distributed Tracing Source: https://docs.honeycomb.io/get-started/observability/concepts/distributed-tracing Trace requests across every service in your distributed system. Find out how distributed tracing ties together instrumentation from separate services to surface cross-service failures. If you are running a user-facing software service, it probably qualifies as a distributed service. You might have a proxy, an application and a database, or a more complicated microservice architecture. Regardless of the level of complexity, a distributed system means that multiple distinct services must work together in concert. Tracing helps tie together instrumentation from separate services, or from different methods within one service. This makes it easier to identify the source of errors, find performance problems, or understand how data flows through a large system. ## What is a Trace? A **trace** tells the story of a complete unit of work in your system. For example, when a user loads a web page, their request might go to an edge proxy. That proxy talks to a frontend service, which calls out to an authorization and a rate-limiting service. There could be multiple backend services, each with its own data store. Finally, the frontend service returns a result to the client. Each part of this story is told by a **span**. A span is a single piece of instrumentation from a single location in your code. It represents a single unit of work done by a service. Each tracing event, one per span, contains several key pieces of data: * A **serviceName** identifying the service the span is from * A **name** identifying the role of the span (like function or method name) * A **timestamp** that corresponds to the start of the span * A **duration** that describes how long that unit of work took to complete * An **ID** that uniquely identifies the span * A **traceID** identifying which trace the span belongs to * A **parentID** representing the parent span that called this span * Any additional metadata that might be helpful [OpenTelemetry](/send-data/opentelemetry/) automatically defines these fields. You can manually [configure which fields on your events](/configure/datasets/definitions/#configure-dataset-definitions) correspond to these pieces of data. A trace is made up of multiple spans. Honeycomb uses the metadata from each span to reconstruct the relationships between them and generate a trace diagram. The image below is a portion of a trace diagram for an incoming API request: Screenshot of a trace diagram In this example, the `/api/v2/tickets/export` endpoint first checks if the request is allowed by the rate limiter. Then, it authenticates the requesting user, and finally, fetches the tickets requested. Each of those calls also called a datastore. In the trace diagram, you can see the order in which these operations were executed, which service called which other service, and how long each call took. ## How do Honeycomb Events Relate to Traces? Each span is one event to Honeycomb. That event has fields, like `parentID` and `traceID`, which describe that span's relationship to other spans. A trace ties together a unit of work that occurs across multiple events (or spans) in a distributed service. A trace is a group of spans that all share the same `traceID`. When using [OpenTelemetry](/send-data/opentelemetry/), `service.name` in each span defines the current service context and creates Service Datasets. Service scoping is supported only for Honeycomb datasets, not for Honeycomb Classic datasets. Learn more about [Honeycomb versus Honeycomb Classic datasets](/troubleshoot/product-lifecycle/recommended-migrations/#migrate-from-honeycomb-classic-to-honeycomb-environments). ## Next Steps * [Sending trace data to Honeycomb](/send-data) describes the different ways to generate tracing metadata and send it to Honeycomb * Learn how to query traces and visualize a trace waterfall with [exploring trace data](/investigate/analyze/explore-traces/) # eBPF Source: https://docs.honeycomb.io/get-started/observability/concepts/ebpf Extend the Linux kernel to collect observability, security, and networking data without changing kernel source code or loading additional modules. eBPF is a technology that allows the Linux kernel to be extended and perform additional tasks without needing to change the kernel source code or load more modules. eBPF works for both user and OS applications and can apply cross-cutting tasks such as observability, security, and networking functionality. It is highly efficient because the operating system executes its extended capabilities by using a Just-In-Time (JIT) compiler. eBPF programs are executed when configured kernel or application hook points are triggered. Pre-defined hooks include system calls, function entry and exit, kernel tracepoints, network events, and several others. If a pre-defined hook does not exist, additional [kernel probes](https://docs.kernel.org/trace/kprobes.html) (Kprobes) or [user probes](https://docs.kernel.org/trace/uprobetracer.html) (Uprobes) can be created to attach eBPF programs almost anywhere in kernel or user applications. ## How eBPF Impacts Observability Typically, applications use language-specific instrumentation libraries to generate application telemetry for generic tasks like routing HTTP traffic, executing SQL queries, counting number of requests, and capturing logs. Developers can add instrumentation libraries to an application either by using an automatic instrumentation tool to automatically configure them or by adding them manually during application start-up, which requires code changes. Because using an automatic instrumentation tool does not require code changes, generally, you can implement automatic instrumentation more easily than manually-configured instrumentation. Unfortunately, not all languages have an automatic instrumentation tool, so sometimes developers must configure instrumentation libraries manually. For applications written in languages lacking automatic instrumentation tools, using eBPF allows developers to still experience a low cost way to implement observability. You can leverage eBPF to generate telemetry outside of the application space by using kernel probes to detect when specific actions are being executed, such as network activity. In addition, eBPF probes have access to system resources that applications typically do not, such as memory and CPU utilization, network interface connection usage and metrics, and more. ## How eBPF Works With OpenTelemetry OpenTelemetry is developing an automatic instrumentation tool for Golang using eBPF. The first release should include a small subset of the functionality provided by the OpenTelemetry instrumentation libraries available in Go--hooks to instrument HTTP clients/servers, gRPC clients/servers, and the gorilla/mux HTTP router--but more should be added in the future. Automatic instrumentation tools for other languages, such as C++ and Rust, using eBPF may also be developed in the future. Honeycomb is committed to working with the OpenTelemetry community to contribute and advance the automatic and manual instrumentation experience for all users and languages. ## Additional Links * [eBPF.io](https://ebpf.io/) * [OpenTelemetry](https://opentelemetry.io/) * [Go Automatic Instrumentation](https://github.com/open-telemetry/opentelemetry-go-instrumentation) * [OpenTelemetry Operator](https://github.com/open-telemetry/opentelemetry-operator) # High Cardinality Source: https://docs.honeycomb.io/get-started/observability/concepts/high-cardinality Discover why high-cardinality, high-dimensionality data lets you isolate problems that low-cardinality tools like metrics would miss. One thing that sets Honeycomb apart is its ability to query on high cardinality and high dimensionality data. What do "high cardinality" and "high dimensionality" mean, and why are they important for observability? Remember that an event is a [collection of information about what it took to do a unit of work](/get-started/honeycomb/traces-metrics-logs/). Honeycomb receives each event as a set of key-value pairs, and each of which is an *attribute* of the event. A collection of events is a dataset. Each attribute of an event is a *field*, or equivalently, a dimension of the dataset. The term "high cardinality" means that there can be many possible values for a single attribute; the term "high dimensionality" means that there can be many different attributes attached to events. For many database architectures, having high-cardinality and high-dimensionality data makes it prohibitively expensive to store and query. Honeycomb's design, however, is powerful enough to allow users to query freely. A user may group or filter on any attribute, no matter how high its cardinality. Let us take a closer look at these. ## What is Dimensionality? The *dimensionality* of a dataset is the number of different attributes that it has. A *high-dimensionality* dataset, then, has many different attributes. In Honeycomb, it is not unusual to have a dataset with many hundreds of dimensions, exploring every possible facet of data. A single event does not need to have a defined value for every possible attribute; an event that describes database operations might not have attributes about HTTP requests, for example. Honeycomb datasets can have very high dimensionality. Any single event has a generous individual size limit; a dataset can have thousands of columns. (Experience has shown that when a dataset approaches that very high number, it is often caused by a programming error.) ## What is Cardinality? The *cardinality* of a data attribute refers to the number of distinct values that it can have. A boolean field, which only can have the values of `true` or `false`, has a cardinality of 2. HTTP status codes -- `200`, `301`, `302`, `404`, `500` -- might have a cardinality under a few dozen. These low cardinality fields are useful to track broad trends in your system: separating your service out by AWS Zone, or by current build of your code, or by endpoint. *High cardinality* refers to a field that can have many possible values. For an online shopping system, fields like `userId`, `shoppingCartId`, and `orderId` are often high-cardinality field that can take take hundreds of thousands of distinct values. Similarly, `requestId` might be in the millions. `request.URL` can be a high-cardinality field if you have many different combinations of `GET` query parameters. A high-cardinality field can help uniquely identify a request: they let you specifically narrow down precisely what caused something to go wrong. ## High Cardinality and High Dimensionality are Critical for Observability The ability to rapidly look at high cardinality fields is a key aspect of observability. Consider, for example, the ["Analyze and Debug an Issue" Sandbox tour](https://play.honeycomb.io/sandbox/tours). The issue can be traced to a single user's actions in the dataset. That one unlucky user managed to find a particular API endpoint that responded extremely slowly. Being able to identify the specific endpoint and user made it easy to see both how badly the endpoint had behaved, and who it had affected. Honeycomb allows you to query on high-cardinality fields. If a user reports an error, it is possible to look only at events generated to service that user's requests, and to examine what is going wrong. It is even possible to query on dimensions like `duration` in order to find only fast-running events. [BubbleUp](/investigate/analyze/identify-outliers/) is Honeycomb's tool to identify attributes that stand out from others. It looks at all dimensions at once, finding which fields stand out. BubbleUp can help identify that a particular latency occurred to a single user, even if cardinality is in the millions. It can also be helpful to store fields with lower cardinality—in the hundreds—like error messages in Honeycomb. You can even store fields like "error message" in Honeycomb; that will help if you might later need to query to find out how many error message contain the text "cannot connect". To learn more about the role that high cardinality plays in observability, visit our blog post: [Understanding High Cardinality and Its Role in Observability](https://www.honeycomb.io/resources/getting-started/understanding-high-cardinality-role-observability). ## The Curse of Dimensionality Why are high-dimensionality and high-cardinality a concern? Some metrics analytics systems are built around the idea of attributes. A data value can be associated with one or more attributes. For example, an attribute might represent `version: 21.3` and another attribute might correspond to `action: save_shopping_cart`. They store a time series for every attribute, and every combination of attributes. This allows them to rapidly query on any of these time series. The cost model for metrics tools is often based on the number of distinct attribute combinations. Adding a high cardinality value, like `user-id`, causes attribute costs to explode. In statistics, this is referred to as the "curse of dimensionality" -- the fact that many dimensions can be exponentially more expensive to store. Honeycomb's internal storage engine is designed to store each event and its data independently. For time series metrics, Honeycomb [counts metric usage as data points](/get-started/manage-costs/how-honeycomb-calculates-usage#how-we-define-a-data-point), not as unique attribute combinations. What this means is that you can send Honeycomb events that have rich context, complex attributes, and contain data that you do not have to think about managing. They are stored inexpensively in a simple format. The query engine then aggregates that data as you analyze it, which makes working with high cardinality and high dimensionality data easy, inexpensive, and fast. # Instrumentation Source: https://docs.honeycomb.io/get-started/observability/concepts/instrumentation Send wide, structured telemetry to Honeycomb. Find out what makes a good event and how to structure your data so you can query and debug your system effectively. The goal of Honeycomb instrumentation is to give you a language for sending **wide, structured** events into Honeycomb, so that they can be queried later. ## What is an Event? Abstractly, an event is anything that happens in your system that is worth tracking. Some common choices of events include http requests to a server, a query to an SQL database, or a single step of a build process. We say that events should be **wide** because they can contain many different **fields**. You can use the fields to associate the events with all of the additional data that it takes to understand what your system did with that event. There are traditional fields -- client IP address, latency, server -- but you can also add others. Did your system need to go through authorization? Did the result hit a cache? Did it go through a branch of an A/B test? Did it get a transient warning? What build of the server code was it using? Which AWS zone hosted it? Any data that can make sense of the event can be accumulated and attached to the event. But at the end of the day, what you will send to Honeycomb is simply a JSON object that you POST to our API. Events get ingested into our storage engine for later querying. Honeycomb's fast storage engine serves queries in seconds, with no need to define schemas or indexes ahead of time. The Honeycomb query engine allows you to ask all sorts of questions of your data. You can filter on any field, or combination of fields, to narrow down on a single page, or even on any user. You can group by error code or error message to spot common or recently occurring problems. You could SUM time spent on certain MySQL queries to identify if there are slow queries, but also if there are queries that are running too often. ## Requests and Tracing One of the most common Honeycomb use cases is to send one event for each HTTP or RPC request in your system. You might even have several services (e.g., A, B, and C) that are touched in the lifecycle of serving what is one request to the end user, and they all send events to Honeycomb. Example execution lifecycle You can then do all sorts of queries within Honeycomb to answer any question under the sun. For instance, you could group by error code or error message to spot common or recently occurring problems fast. You could SUM time spent on certain MySQL queries to identify if there are not just slow queries, but queries that are running too often. Not only that, but this model allows you to take advantage of **distributed tracing**. If you set events to have the [proper fields](/configure/datasets/definitions/#tracing), you can visualize a full waterfall of how a given request flows through the system. That can make it straightforward to spot slow services and sections of code. Example trace Many of the Honeycomb automatic integrations, including [OpenTelemetry](/send-data/opentelemetry/) add this data automatically, so traces are visible out of the box. ## Batch Jobs and Serverless You can instrument background jobs to gain insight into how they operate. For example, you can send an event for every item that a processing job touches. Honeycomb provides a [`buildevents` integration](https://github.com/honeycombio/buildevents) for common Continuous Integration (CI) systems, including Travis-CI, CircleCI, and Jenkins. You can see which parts of your build are taking the most time, and streamline dependencies. Execution flow of a batch job Similarly, serverless requests can be instrumented; a Lambda invocation could easily send a Honeycomb event either using our bindings for that language. Learn more about Honeycomb's [AWS Lambda](/send-data/aws/lambda/) integrations. Example serverless flow execution ## Kubernetes Understanding the behavior of applications running on Kubernetes can be daunting. Honeycomb integrates with Kubernetes to collect your applications' logs, cluster logs, and resource metrics. This data answers questions like: * How did response time change after a canary deployment? * How does application performance vary with container resource limits? * Are application errors happening on specific nodes, or across the fleet? Learn more about Honeycomb's [Kubernetes integrations](/send-data/kubernetes/). ## Ways to Get Started ### OpenTelemetry The automatic instrumentation in OpenTelemetry understand the standard packages you are using, then instrument them to send useful events to Honeycomb. There is no manual instrumentation required to generate basic events but with a little optional configuration, you can include your own fields, too. You can use this scaffolding to instrument your own business logic and attributes of your own service. We have [OpenTelemetry](/send-data/opentelemetry/) support for Go, Python, Node.js, Ruby, Java, .NET, and others. ### CURL, SDKs, and Honeytail Need to stay closer to the metal? We do not blame you! You can POST data directly to us with our [Events API](/api/events/), and we offer [a structured logging library](/send-data/logs/structured/libhoney/) in a variety of languages. Or, you can send us structured text logfiles with [Honeytail](/send-data/logs/structured/honeytail/). ### Example Applications Our [Examples GitHub repository](https://github.com/honeycombio/examples) links to a wide range of instrumented sample applications that illustrate how to generate custom events and send them to Honeycomb. # What is OpenTelemetry? Source: https://docs.honeycomb.io/get-started/observability/concepts/opentelemetry Learn what OpenTelemetry is, why Honeycomb uses it as the standard for instrumentation, and how it relates to your telemetry data. OpenTelemetry (OTel) is an open-source framework for collecting and exporting telemetry data, including traces, metrics, and logs, from your applications and infrastructure. It provides a standardized, vendor-agnostic way to instrument your code so that the telemetry you generate isn't tied to any single observability tool. Honeycomb uses OpenTelemetry as its primary instrumentation standard. When you instrument your application with OTel, you can send that data to Honeycomb, and if you ever want to send it elsewhere, the same instrumentation works with any OTel-compatible backend. ## How OpenTelemetry works OpenTelemetry has two main components: * **Instrumentation libraries**: Language-specific SDKs and auto-instrumentation packages that you add to your application. They capture telemetry data as your code runs: function calls, HTTP requests, database queries, and more. * **Exporters**: Plugins that send the captured telemetry to a backend like Honeycomb over OpenTelemetry Protocol (OTLP), OTel's native wire protocol. When you instrument your application with an OTel SDK, it generates spans and traces that describe what your code did and how long it took. The exporter sends that data to Honeycomb, where you can query and visualize it. ## Why Honeycomb uses OpenTelemetry Honeycomb recommends OpenTelemetry for all new instrumentation because: * **It's vendor-agnostic.** Your instrumentation isn't tied to Honeycomb or any other vendor. You own your telemetry. * **It's the industry standard.** OTel is maintained by the Cloud Native Computing Foundation (CNCF) and widely supported across the observability ecosystem. * **It covers all three signals.** A single OTel SDK can send traces, metrics, and logs from your application. You don't need separate libraries for each signal type. * **It's future-proof.** As OTel evolves and new semantic conventions emerge, your instrumentation stays current without requiring a full rewrite. ## OpenTelemetry and Honeycomb's data model Honeycomb stores telemetry as events: structured records with fields and values. When OTel sends a span to Honeycomb, Honeycomb stores it as an event with fields like `name`, `duration_ms`, `trace.trace_id`, and `service.name`. You can query on any of these fields, group by them, and filter by them the same way you would with any other data in Honeycomb. Traces are collections of spans that share a `trace.trace_id`. Honeycomb uses the parent-child relationships between spans to render the trace waterfall view. ## Already using OTel? If your application already sends OTLP data, you can point your exporter at Honeycomb without changing your instrumentation. Visit [OpenTelemetry configuration reference](/send-data/opentelemetry/) for the endpoint and authentication details. ## Learn more * For a deeper introduction to OpenTelemetry, visit the [OpenTelemetry documentation](https://opentelemetry.io/docs/). * For structured learning, visit the [OpenTelemetry Foundations course](https://academy.honeycomb.io/app/courses/3c8c4ded-ce8c-4df1-8150-b73fdf59f2b0) in Honeycomb Academy. # Services Source: https://docs.honeycomb.io/get-started/observability/concepts/services Find out how Honeycomb organizes telemetry data around services, how services are created from the data you send, and how they appear across the UI. Modern development teams often choose to organize their code into a set of loosely-coupled services that communicate with each other. Honeycomb organizes its data to support this service-oriented concept. ## Services in Honeycomb In service-oriented architecture (SOA), an application is made up a set of services. It can be valuable to separate observability information among different services, because you may want to observe the behavior of a single service. On the other hand, it is also useful to be able to trace requests through a set of linked and connected services. In SOA, then, each Service represents one or more programs sharing a common executable. Many instances of the same Service might run at the same time for scaling; they all share the same name. Honeycomb's approach to organizing Services is to separate your observability data by the different services it comes from, but to connect those services through distributed tracing. ### Tracing and Services [Distributed Tracing](/get-started/basics/observability/concepts/distributed-tracing/) is a method to connect a single request across multiple services. Honeycomb supports distributed tracing across multiple services. A single trace follows a request between different services to help see how they interact. A trace is made up of spans. Each span represents the execution of one piece of code on a service. A span is marked with a start time and a duration, as well as information that shows its connecting spans. Honeycomb can then visualize these spans in the [waterfall view](/reference/honeycomb-ui/query/trace-waterfall/#waterfall-representation). ### How to Define a Service Dataset in Honeycomb Honeycomb organizes your observability data into individual Service Datasets. A Service Dataset represents all the information coming from a single Service. Automatic instrumentation with [OpenTelemetry Tracing](/send-data/opentelemetry/) will properly produce traces in Honeycomb and propagate headers between services to ensure the traces are intact. # Introduction to Observability Source: https://docs.honeycomb.io/get-started/observability/introduction Ask new questions about your distributed system without knowing the answer in advance. Find out what observability is and why it changes how you debug production software. Today's software is built over distributed systems. When microservices, load-balancers, serverless compute, flexible infrastructure, and containers interact, it can be hard to track how the system is behaving, and how errors are manifesting. There are many more potential combinations of things going wrong, and sometimes they sympathetically reinforce each other. This can lead to new types of challenges. The goal of observability is to empower your team to be able to: * address issues before they impact customers * safely experiment and implement optimizations * promote knowledge transfer within and across team boundaries * better manage business risks and support stakeholders You can accomplish that by improving your system's observability. For more structured learning, check out the [Observability Foundations](https://academy.honeycomb.io/app/courses/38f176d1-199a-4520-b8e3-71b93a83f3a6) course from Honeycomb Academy. ## What is Observability? Observability is about being able to ask arbitrary questions about your environment without having to know ahead of time what you wanted to ask. Observability focuses on the development of the application and the rich instrumentation you need, not to poll and monitor it for thresholds or defined health checks, but to ask any arbitrary question about how the software works. We say that a system is "observable" to the extent that you can explain what is happening on the inside just from observing it on the outside, preferably without having to add new, special-case instrumentation to get your new question answered. Monitoring for known problems does not address the growing number of new issues that arise. You need to be able to ask questions you had not anticipated. Honeycomb is designed to help you gather as much context as you can from your production systems so you can investigate and debug new and complex problems. Having an observable system means that everyone on your team has the ability to understand what is happening in your software. ## How Can You Improve Observability? Improving software observability requires two things: the ability to capture telemetry data with a lot of runtime context, and the ability to query that data iteratively in order to find new insights. **Wide, structured events** are the form of telemetry data that truly enables observability in software. Honeycomb works by ingesting your structured events and making them available to interact with in near-real time. You send Honeycomb large numbers of events. Honeycomb allows you explore your data by querying on any dimension, aggregating your events to compute a count or a P95 (95th percentile), or visualize them as a heatmap. You can group and filter them on any dimension. This ability allows you to track down the behavior of a single user, code release, feature flag, server, or endpoint. You can pivot from any of those views to [distributed traces](/get-started/basics/observability/concepts/distributed-tracing/), allowing you to follow the path of execution through your distributed system. Read more about how you can [query your data](/investigate/query/build/) in Honeycomb. To get the most out of Honeycomb's features, get started by instrumenting your code. Ready to try it out? [Start sending data to Honeycomb](/send-data/). ## Learn More About Observability If you are new to this topic and want a deeper introduction, download our whitepaper or e-book: * [**Guide to Achieving Observability**](https://www.honeycomb.io/resources/guides/guide-achieving-observability) [Achieving Observability Guide](https://www.honeycomb.io/resources/guides/guide-achieving-observability) * [**Observability Engineering: Achieving Production Excellence**](https://info.honeycomb.io/observability-engineering-oreilly-book-2022) [Observability Engineering: Achieving Production Excellence E-book](https://info.honeycomb.io/observability-engineering-oreilly-book-2022) # Get Started with Honeycomb for Applications Source: https://docs.honeycomb.io/get-started/start-building/application Send unstructured logs, structured logs, or traces to Honeycomb and start analyzing your application's performance and behavior. [Honeycomb](https://www.honeycomb.io/why-honeycomb/) is a fast analysis tool that helps you analyze your code's performance and behavior to troubleshoot complex relationships within your system to solve problems faster. To use Honeycomb, you first need to get your system's observable external outputs (logs, traces, and metrics) into Honeycomb. Not ready to instrument and deploy an application, but want to see what Honeycomb can do for you? Check out this [interactive demo](https://play.honeycomb.io/sandbox/environments/analyze-debug-tour) that requires no setup, or learn what is possible from the [guided tutorials in our Honeycomb sandbox](https://play.honeycomb.io/sandbox/tours)! Get up and running with Honeycomb for your unstructured logs. Learn how Honeycomb treats unstructured data, explore methods of sending unstructured logs to Honeycomb, and get resources related to enhancing and exploring your data once it is in Honeycomb. Get up and running with Honeycomb for your structured logs. Learn how Honeycomb treats structured data, explore methods of sending structured logs to Honeycomb, and get resources related to enhancing and exploring your data once it is in Honeycomb. Get up and running with Honeycomb for your traces and wide events. Learn how to easily add instrumentation and use Honeycomb to observe and understand your application. ## Frontend Observability Get up and running with Frontend Observability for web applications. Add instrumentation to your web application, send telemetry data to Honeycomb, and use Honeycomb to explore your data. Get up and running with Frontend Observability for Android. Add instrumentation to your Android application, send telemetry data to Honeycomb, and use Honeycomb to explore your data. Get up and running with Frontend Observability for iOS. Add instrumentation to your iOS application, send telemetry data to Honeycomb, and use Honeycomb to explore your data. Get up and running with Frontend Observability for React Native. Add instrumentation to your React Native application, send telemetry data to Honeycomb, and use Honeycomb to explore your data. # Get Started with Honeycomb for Android Source: https://docs.honeycomb.io/get-started/start-building/application/android Instrument your Android application with the Honeycomb OpenTelemetry Android SDK, send telemetry to Honeycomb, and measure real device performance in production. Use the [Honeycomb OpenTelemetry Android SDK](https://github.com/honeycombio/honeycomb-opentelemetry-android) to collect telemetry data from your Android application and send it to Honeycomb. Instrumenting your application lets you measure how it behaves on actual devices, detect performance issues, and better understand how users experience your application. This guide walks you through the process of instrumenting an Android application in your local development environment and verifying that telemetry is successfully flowing to Honeycomb. ## Before You Begin Before getting started, make sure you have: * A Honeycomb account If you don't already have an account, sign up for one. Honeycomb stores your data in either a US-based or EU-based location, depending on your account region: * [Create a US account](https://ui.honeycomb.io/signup) * [Create an EU account](https://ui.eu1.honeycomb.io/signup) * Required Tools * [Kotlin](https://kotlinlang.org/) * An existing Android application to instrument * A Honeycomb Ingest API Key For this guide, you'll need a [Honeycomb Ingest API Key](/configure/environments/manage-api-keys/#create-api-key) with the **Can create services/datasets** permission. This key lets your application send telemetry to Honeycomb and create a dataset for your service. When deploying to production, replace this key with a separate key that does not allow dataset creation. This helps protect your data structure in live environments. ## Add Dependencies Add the required SDK dependencies. The Honeycomb Android SDK relies on the OpenTelemetry Android SDK, so both are required. When adding OpenTelemetry dependencies, make sure [the library is compatible with the Honeycomb Android SDK](https://github.com/honeycombio/honeycomb-opentelemetry-android/?tab=readme-ov-file#honeycomb-opentelemetry-android). In your `build.gradle.kts`, add these dependencies: ```kotlin theme={} dependencies { implementation("io.opentelemetry.android:android-agent:0.11.0-alpha") implementation("io.honeycomb.android:honeycomb-opentelemetry-android:0.0.10") } ``` If your application's `minSDK` version is lower than 26, enable [core library desugaring](https://developer.android.com/studio/write/java8-support#library-desugaring) to support Java 8+ features: ```kotlin theme={} android { // ... compileOptions { isCoreLibraryDesugaringEnabled = true sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = "1.8" } } dependencies { coreLibraryDesugaring(libs.desugar.jdk.libs) } ``` If your application's `minSdk` version is below 24, then running instrumentation tests or debug application builds requires that you: * Use [Android Gradle Plugin](https://developer.android.com/build/releases/gradle-plugin#updating-plugin) (AGP) 8.3.0 or later. * Add `android.useFullClasspathForDexingTransform=true` to your `gradle.properties`. ## Configure the SDK To start collecting telemetry, configure the SDK early in your application's lifecycle. This ensures that events such as startup time and early view loads are captured. We recommend setting it up in the `onCreate()` method of your `Application` class, so configuration happens at application start. Here's a basic example configuration: ```kotlin theme={} import io.honeycomb.opentelemetry.android.Honeycomb import io.honeycomb.opentelemetry.android.HoneycombOptions import io.opentelemetry.android.OpenTelemetryRum class ExampleApp: Application() { var otelRum: OpenTelemetryRum? = null override fun onCreate() { super.onCreate() val options = HoneycombOptions.builder(this) // Uncomment the line below to send to EU instance. Defaults to US. // .setApiEndpoint("https://api.eu1.honeycomb.io:443") .setApiKey("YOUR-API-KEY") .setServiceName("YOUR-SERVICE-NAME") .setServiceVersion("0.0.1") .setDebug(true) .build() otelRum = Honeycomb.configure(this, options) } } ``` In this example, key configuration options include: **apiKey** : Your [Ingest API Key](/configure/environments/manage-api-keys/#create-api-key), which lets your application send telemetry directly to Honeycomb. **serviceName** : The name of your application, which Honeycomb will use as your dataset name. Choose something meaningful and consistent. If you don't provide a service name, the dataset name will default to `unknown_service`. **serviceVersion** : The current version of your application. This helps track changes in behavior over different versions of your application. **debug** : Set to `true` to enable debug logs, which can help troubleshoot configuration issues during development. ## Enable Automatic Instrumentation The [OpenTelemetry Android Agent](https://github.com/open-telemetry/opentelemetry-android) provides automatic instrumentation for common Android application components like activities, fragments, crashes, and rendering performance. ### Enabling All Instrumentations To enable all OpenTelemetry automatic instrumentations by default,include these dependencies: ```kotlin theme={} dependencies { implementation("io.opentelemetry.android:android-agent:0.11.0") implementation("io.honeycomb.android:honeycomb-opentelemetry-android:0.0.9") } ``` ### Enabling Individual Instrumentations To be more selective, add only the modules you need: | Feature | Dependency | | ------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------- | | [Activity navigation](https://github.com/open-telemetry/opentelemetry-android/tree/main/instrumentation/activity) | `io.opentelemetry.android:instrumentation-activity` | | [Application Not Responding (ANR)](https://github.com/open-telemetry/opentelemetry-android/tree/main/instrumentation/anr) | `io.opentelemetry.android:instrumentation-anr` | | [Crash (uncaught exception)](https://github.com/open-telemetry/opentelemetry-android/tree/main/instrumentation/crash) | `io.opentelemetry.android:instrumentation-crash` | | [Fragment navigation](https://github.com/open-telemetry/opentelemetry-android/tree/main/instrumentation/fragment) | `io.opentelemetry.android:instrumentation-fragment` | | [Slow rendering](https://github.com/open-telemetry/opentelemetry-android/tree/main/instrumentation/slowrendering) | `io.opentelemetry.android:instrumentation-slowrendering` | ## Verify That Data is Being Sent Once your application is instrumented, check that telemetry data is reaching Honeycomb: 1. Confirm that debugging is enabled by setting `.setDebug(true)` in your SDK configuration. 2. Build and run your application. 3. Check your logs for output like this: ```text theme={} 🐝 Honeycomb SDK Debug Mode Enabled 🐝 Honeycomb options: HoneycombOptions(...) Not sampling, emitting all spans ``` 4. Log in to Honeycomb, and open your environment. You should see a new dataset named after your `serviceName` value. If you don’t see any data, visit [Troubleshooting](#troubleshooting). ## Explore Your Data Take a look at the data that you have generated using automatic instrumentation through the Android Launchpad or a custom Board. ### Explore with the Android Launchpad If you're using [Honeycomb for Frontend Observability](https://www.honeycomb.io/frontend-observability/), the [Android Launchpad](/observe/android-launchpad/) provides a starting point for reviewing the telemetry from your Android application. The Launchpad helps you: * Monitor cold start and resume times * Detect app hangs and crashes * Identify views with high render times It's a great place to start exploring how your application behaves in real-world conditions. ### Explore using Boards You can also explore your data by creating a [Board](/observe/boards/) from a [pre-configured Board template](/observe/boards/templates/). Our specialized template for mobile Android data includes a curated set of ready-made queries and visualizations based on the fields collected by the Honeycomb OpenTelemetry Android SDK. This template gives you an immediate, actionable view into common mobile metrics, like application start times, cold launches, crashes, and session flows, without needing to build anything from scratch. You can use it as-is or customize it to fit your needs. To learn more, visit [Use Board Templates](/observe/boards/templates/). ## Troubleshooting Running into issues? Here are some common problems and ways to fix them. Still stuck? Check out our [Support Knowledge Base](/troubleshoot/customer-support/) or post a question in our [Pollinators Community](/troubleshoot/community/). ### My dataset isn't showing up in Honeycomb Make sure that you: * Replaced `"YOUR-API-KEY"` with a valid [Ingest API Key](/configure/environments/manage-api-keys/#create-api-key). * Gave the key **Can create datasets** permission. The Honeycomb OpenTelemetry Android SDK uses the value passed to `.setApiKey()` to send your telemetry data. This must be set correctly for data to reach Honeycomb. ### My dataset name looks wrong Check the value passed to `.setServiceName()`. This value determines the name of your dataset in Honeycomb. If you leave it blank, the default will be `unknown_service`, which can make identifying your application harder later on. # Get Started with Honeycomb for iOS Source: https://docs.honeycomb.io/get-started/start-building/application/ios Instrument your iOS application with the Honeycomb OpenTelemetry Swift SDK, send telemetry to Honeycomb, and measure real device performance in production. Use the [Honeycomb OpenTelemetry Swift SDK](https://github.com/honeycombio/honeycomb-opentelemetry-swift) to collect telemetry data from your iOS application and send it to Honeycomb. Instrumenting your application lets you measure how it behaves on actual devices, detect performance issues, and better understand how users experience your application. This guide walks you through the process of instrumenting an application in your local development environment and verifying that telemetry is successfully flowing to Honeycomb. ## Before You Begin Before getting started, make sure you have: * A Honeycomb account If you don't already have an account, sign up for one. Honeycomb stores your data in either a US-based or EU-based location, depending on your account region: * [Create a US account](https://ui.honeycomb.io/signup) * [Create an EU account](https://ui.eu1.honeycomb.io/signup) * Required Tools * [Swift](https://www.swift.org/) 5.10+ * An existing iOS 13+ application to instrument * A Honeycomb Ingest API Key For this guide, you'll need a [Honeycomb Ingest API Key](/configure/environments/manage-api-keys/#create-api-key) with the **Can create services/datasets** permission. This key lets your application send telemetry to Honeycomb and create a dataset for your service. When deploying to production, replace this key with a separate key that does not allow dataset creation. This helps protect your data structure in live environments. ## Add Dependencies To send telemetry from your application, add the Honeycomb OpenTelemetry Swift SDK to your project. The Honeycomb OpenTelemetry Swift SDK is compatible with applications targeting iOS 13+. ### Using Xcode If you manage dependencies using Xcode: 1. In Xcode, navigate to **File** > **Add Package Dependencies...** 2. When prompted for a repository URL, enter `https://github.com/honeycombio/honeycomb-opentelemetry-swift`. 3. Get the version number for the [latest release](https://github.com/honeycombio/honeycomb-opentelemetry-swift/releases). 4. [Add the `Honeycomb` package to your application's target dependencies](https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app). ### Using Package.swift If you manage dependencies manually: 1. Add the SDK to your `Package.swift` file: ```swift theme={} dependencies: [ .package(url: "https://github.com/honeycombio/honeycomb-opentelemetry-swift.git", from: "0.0.10") ], ``` 2. Add `Honeycomb` to your target dependencies: ```swift theme={} dependencies: [ .product(name: "Honeycomb", package: "honeycomb-opentelemetry-swift"), ], ``` ## Configure the SDK To start collecting telemetry, configure the SDK early in your application's lifecycle. This ensures that events such as startup time and early view loads are captured. We recommend setting it up in the `init()` method of your `App` class, or something equivalent. Here's an example configuration using the `HoneycombOptions.Builder()`, which lets us use the builder pattern to set configuration options: ```swift theme={} import Honeycomb import SwiftUI @main struct ExampleApp: App { init() { do { let options = try HoneycombOptions.Builder() // Uncomment the line below to send to EU instance. Defaults to US. // .setAPIEndpoint("https://api.eu1.honeycomb.io:443") .setAPIKey("YOUR-API-KEY") .setServiceName("YOUR-SERVICE-NAME") .setServiceVersion("0.0.1") .setDebug(true) .build() try Honeycomb.configure(options: options) } catch { NSException(name: NSExceptionName("HoneycombOptionsError"), reason: "\(error)").raise() } } } ``` In this example, key configuration options include: **APIEndpoint** : URL where your telemetry is sent. : Defaults to `https://api.honeycomb.io:443` (the Honeycomb US instance URL). : For EU instances, set this to `https://api.eu1.honeycomb.io:443`. : If you're using an OpenTelemetry Collector, use your collector's URL instead. **APIKey** : Your [Ingest API Key](/configure/environments/manage-api-keys/#create-api-key), which authorizes your application to send telemetry directly to Honeycomb. **serviceName** : The name of your application, which Honeycomb will use as your dataset name. Choose something meaningful and consistent. If you don't provide a service name, the dataset name will be inferred from your bundle. **serviceVersion** : The current version of your application. This helps track changes in behavior across different versions of your application. **debug** : Set to `true` to enable debug logs, which can help troubleshoot configuration issues during development. ### Enable Automatic Instrumentation The Honeycomb OpenTelemetry Swift SDK includes built-in support for capturing common system and runtime events. These can provide useful context without requiring additional code. These include: * [MetricKit](https://developer.apple.com/documentation/metrickit) : Captures system-level performance data, such as CPU and memory usage. * [UIKit](https://developer.apple.com/documentation/uikit) : Captures view controller lifecycle events. * Touch Events : Tracks screen touches and gestures. : This is off by default to reduce noise but may be useful for interaction-heavy apps. * URLSession : Captures network requests made with `URLSession`. * Unhandled Exceptions : Records crashes and other unhandled exceptions. By default, most of these instrumentation libraries are enabled. You can selectively turn them on or off in your configuration: ```swift theme={} let options = try HoneycombOptions.Builder() // ... .setMetricKitInstrumentationEnabled(true) .setURLSessionInstrumentationEnabled(true) .setUIKitInstrumentationEnabled(true) .setTouchInstrumentationEnabled(false) .setUnhandledExceptionInstrumentationEnabled(true) // ... .build() try Honeycomb.configure(options: options) ``` ## Verify That Data is Being Sent Once your application is instrumented, check that telemetry data is reaching Honeycomb: 1. Confirm that debugging is enabled by setting `.setDebug(true)` in your SDK configuration. 2. Build and run your application. 3. Check your logs for output like this: ```text theme={} 🐝 Honeycomb SDK Debug Mode Enabled 🐝 Honeycomb options: HoneycombOptions(...) Not sampling, emitting all spans ``` 4. Log in to Honeycomb, and open your environment. You should see a new dataset named after your `serviceName` value. If you don’t see any data, visit [Troubleshooting](#troubleshooting). ## Explore Your Data Take a look at the data that you have generated using automatic instrumentation through the iOS Launchpad or a custom Board. ### Explore with the iOS Launchpad If you're using [Honeycomb for Frontend Observability](https://www.honeycomb.io/frontend-observability/), the [iOS Launchpad](/observe/ios-launchpad/) provides a starting point for reviewing the telemetry from your iOS application. The Launchpad helps you: * Monitor cold start and resume times * Detect app hangs and crashes * Identify views with high render times It's a great place to start exploring how your application behaves in real-world conditions. ### Explore using Boards You can also explore your data by creating a [Board](/observe/boards/) from a [pre-configured Board template](/observe/boards/templates/). Our specialized template for mobile iOS data includes a curated set of ready-made queries and visualizations based on the fields collected by the Honeycomb OpenTelemetry Swift SDK. This template gives you an immediate, actionable view into common mobile metrics, like application start times, cold launches, crashes, and session flows, without needing to build anything from scratch. You can use it as-is or customize it to fit your needs. To learn more, visit [Use Board Templates](/observe/boards/templates/). ## Troubleshooting Running into issues? Here are some common problems and ways to fix them. Still stuck? Check out our [Support Knowledge Base](/troubleshoot/customer-support/) or post a question in our [Pollinators Community](/troubleshoot/community/). ### My dataset isn't showing up in Honeycomb Make sure that you: * Replaced `"YOUR-API-KEY"` with a valid [Ingest API Key](/configure/environments/manage-api-keys/#create-api-key). * Gave the key **Can create datasets** permission. The Honeycomb OpenTelemetry Swift SDK uses the value passed to `.setApiKey()` to send your telemetry data. This must be set correctly for data to reach Honeycomb. ### My dataset name looks wrong Check the value passed to `.setServiceName()`. This value determines the name of your dataset in Honeycomb. If you leave it blank, the default will be inferred from your bundle, which might not be descriptive or consistent across builds. # Get Started with Honeycomb for React Native Source: https://docs.honeycomb.io/get-started/start-building/application/react-native Instrument your React Native application with the Honeycomb OpenTelemetry React Native SDK, send telemetry to Honeycomb, and measure real device performance in production. Learn how to collect telemetry from your React Native application and send it to Honeycomb using the [Honeycomb OpenTelemetry React Native SDK](https://github.com/honeycombio/honeycomb-opentelemetry-react-native). Instrumenting your application lets you measure how it behaves on actual devices, detect performance issues, and better understand how users experience your application. ## Before you begin Before you run the code, you'll need to do a few things. ### Sign up for Honeycomb If you don't already have a Honeycomb account, you can sign up for one. Signup is free. Honeycomb stores your data in either a US-based or EU-based location, depending on your account region: * [Create a US account](https://ui.honeycomb.io/signup) * [Create an EU account](https://ui.eu1.honeycomb.io/signup) ### Get an API key For this guide, you'll need a [Honeycomb Ingest API Key](/configure/environments/manage-api-keys/#create-api-key) with the **Can create services/datasets** permission. This lets your application send telemetry to Honeycomb and create a dataset for your service. When deploying to production, replace this key with a separate key that does not allow dataset creation. This helps protect your data structure in live environments. Make note of your API key; for security reasons, you will not be able to see the key again, and you will need it later. ## Install the SDK Before you can use Honeycomb’s OpenTelemetry React Native SDK, you need to install it and configure platform-specific dependencies. 1. Configure Metro to recognize `package.json` exports. To do this, create a new file, `metro.config.js`, in your application's root directory. [Enable `package.json` exports](https://reactnative.dev/blog/2023/06/21/package-exports-support) in your Metro configuration. ```js theme={} config.resolver.unstable_enablePackageExports = true; ``` Here's an [example Metro configuration](https://github.com/honeycombio/honeycomb-opentelemetry-react-native/blob/main/example/metro.config.js): ```js theme={} const path = require('path'); const { getDefaultConfig } = require('@react-native/metro-config'); const { getConfig } = require('react-native-builder-bob/metro-config'); const pkg = require('../package.json'); const root = path.resolve(__dirname, '..'); const config = getConfig(getDefaultConfig(__dirname), { root, pkg, project: __dirname, }); // Required to use @opentelemetry package.json "exports" field config.resolver.unstable_enablePackageExports = true; module.exports = config; ``` To learn more about Metro configuration, visit [Configuring Metro](https://metrobundler.dev/docs/configuration/). 2. Install Honeycomb’s OpenTelemetry React Native SDK in your application’s root directory using your preferred package manager. **Install with `yarn`:** ```bash theme={} yarn add @honeycombio/opentelemetry-react-native ``` **Install with `npm`:** ```bash theme={} npm install @honeycombio/opentelemetry-react-native ``` 3. Install the necessary dependencies for each mobile platform your application supports. **Android dependencies:** Add the following dependencies to your application's `build.gradle`. ```gradle theme={} dependencies { //... implementation "io.honeycomb.android:honeycomb-opentelemetry-android:0.0.16" implementation "io.opentelemetry.android:android-agent:0.11.0-alpha" } ``` If your application's `minSDK` version is lower than 26, add [core library desugaring](https://developer.android.com/studio/write/java8-support#library-desugaring) to your `android/app/build.gradle`. ```gradle theme={} android { compileOptions { // Enable support for the new language APIs coreLibraryDesugaringEnabled true } dependencies { coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:2.1.5" } } ``` **iOS dependencies**: Add the `use_frameworks!` option to your application's `Podfile`. ```podfile theme={} platform :ios, min_ios_version_supported prepare_react_native_project! use_frameworks! ``` From the `ios` directory, run `pod install` to install the required dependencies. ## Initialize Initialize the SDK at the start of your React Native application. This ensures that events such as startup time and early view loads are captured. ```ts theme={} import { HoneycombReactNativeSDK } from '@honeycombio/opentelemetry-react-native'; import { DiagLogLevel } from '@opentelemetry/api'; const sdk = new HoneycombReactNativeSDK({ // Uncomment the line below to send to EU instance. Defaults to US. // endpoint: "https://api.eu1.honeycomb.io:443", apiKey: "YOUR-API-KEY", serviceName: "YOUR-SERVICE-NAME", logLevel: DiagLogLevel.DEBUG, }); sdk.start(); ``` In the above example, key configuration options include: **endpoint** : URL where your telemetry is sent. Defaults to `https://api.honeycomb.io:443` (the Honeycomb US instance URL). For EU instances, set this to `https://api.eu1.honeycomb.io:443`. If you're using an OpenTelemetry Collector, use your collector's URL instead. **apiKey** : Your [Ingest API Key](/configure/environments/manage-api-keys/#create-api-key), which authorizes your application to send telemetry directly to Honeycomb. **serviceName** : Name of your application, which Honeycomb will use as your dataset name. Choose something meaningful and consistent. If you don't provide a service name, the dataset name will be inferred from your bundle. **logLevel** : Verbosity of logs printed to the console. Enabling debug logs is helpful during development. Can be set to either `.NONE`, `.ERROR`, `.WARN`, `.INFO`, `.DEBUG`, or `.ALL`. For more information, visit [Enumeration DiagLogLevel](https://open-telemetry.github.io/opentelemetry-js/enums/_opentelemetry_api._opentelemetry_api.DiagLogLevel.html). For Android, initialize the SDK at the start of the `onCreate()` method in your main `Application` class. ```kotlin theme={} // MainApplication.kt override fun onCreate() { val options = HoneycombOpentelemetryReactNativeModule.optionsBuilder(this) // Uncomment the line below to send to EU instance. Defaults to US. // .setApiEndpoint("https://api.eu1.honeycomb.io:443") .setApiKey("YOUR-API-KEY") .setServiceName("YOUR-SERVICE-NAME") HoneycombOpentelemetryReactNativeModule.configure(this, options) super.onCreate() } ``` For iOS, initialize the SDK at the start of the `application()` method in your `AppDelegate` class. ```swift theme={} // AppDelegate.swift override func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil ) -> Bool { let options = HoneycombReactNative.optionsBuilder() // Uncomment the line below to send to EU instance. Defaults to US. // .setAPIEndpoint("https://api.eu1.honeycomb.io:443") .setAPIKey("YOUR-API-KEY") .setServiceName("YOUR-SERVICE-NAME") HoneycombReactNative.configure(options) } ``` ## Enable automatic instrumentation The Honeycomb OpenTelemetry React Native SDK includes auto-instrumentation libraries for: * Application startup time, measured from when the native SDKs start to when the JavaScript SDK finishes initializing. * Errors or uncaught exceptions. * [Fetch](https://developer.mozilla.org/en-US/docs/Web/API/Window/fetch) instrumentation, using the [opentelemetry-instrumentation-fetch](https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/opentelemetry-instrumentation-fetch) package. * Slow event loop detection. Automatic instrumentation is enabled by default. You can enable or disable individual auto-instrumentation libraries in your configuration. ```ts theme={} import { HoneycombReactNativeSDK } from '@honeycombio/opentelemetry-react-native'; import { DiagLogLevel } from '@opentelemetry/api'; const sdk = new HoneycombReactNativeSDK({ // Uncomment the line below to send to EU instance. Defaults to US. // endpoint: "https://api.eu1.honeycomb.io:443", apiKey: "YOUR-API-KEY", serviceName: "YOUR-SERVICE-NAME", logLevel: DiagLogLevel.DEBUG, // auto-instrumentation options reactNativeStartupInstrumentationConfig: { enabled: true, }, uncaughtExceptionInstrumentationConfig: { enabled: true, }, fetchInstrumentationConfig: { enabled: true, }, slowEventLoopInstrumentationConfig: { enabled: true, }, }); sdk.start(); ``` ## Verify data is being sent Once your application is instrumented, check that telemetry data is reaching Honeycomb: 1. Confirm that debug logging is enabled by setting `logLevel: DiagLogLevel.DEBUG` in your SDK configuration. 2. Build and run your application. 3. Open your debugger and check for logs with output like this: ```text theme={} 🐝 Honeycomb SDK Debug Mode Enabled 🐝 Honeycomb options: HoneycombOptions(...) Not sampling, emitting all spans ``` 4. Log in to Honeycomb, and open your environment. You should see a new dataset named after your `serviceName` value. If you don’t see any data, visit [Troubleshooting](#troubleshooting). ## Explore your data Take a look at the data that you have generated using automatic instrumentation through the React Native Launchpad or a custom Board. ### Explore with the React Native Launchpad If you're using [Honeycomb for Frontend Observability](https://www.honeycomb.io/frontend-observability/), the [React Native Launchpad](/observe/react-native-launchpad/) provides a starting point for monitoring and analyzing telemetry from your React Native application. The Launchpad helps you: * Find slow event loops * Detect performance slow downs and crashes * Monitor how users interact with your application It's a great place to start exploring how your application behaves in real-world conditions. ### Explore using Boards You can also explore your data by creating a [Board](/observe/boards/) from a [pre-configured Board template](/observe/boards/templates/). Our specialized template for React Native telemetry includes a curated set of ready-made queries and visualizations based on the fields collected by the Honeycomb OpenTelemetry React Native SDK. This template gives you an immediate, actionable view into common mobile metrics like application start times, crashes, and session flows, without needing to build anything from scratch. You can use it as-is or customize it to fit your needs. To learn more, visit [Use Board Templates](/observe/boards/templates/). ## Troubleshooting Running into issues? Here are some common problems and ways to fix them. Still stuck? Check out our [Support Knowledge Base](/troubleshoot/customer-support/) or post a question in our [Pollinators Community](/troubleshoot/community/). ### Dataset isn't showing up in Honeycomb Make sure that you: * Replaced `"YOUR-API-KEY"` with a valid [Ingest API Key](/configure/environments/manage-api-keys/#create-api-key). * Gave the key **Can create datasets** permission. The Honeycomb OpenTelemetry React Native SDK uses the value passed to `apiKey` configuration option to send your telemetry data. This must be set correctly for data to reach Honeycomb. ### Dataset name looks wrong Check the value passed to `serviceName` during initialization. This value determines the name of your dataset in Honeycomb. If you leave it blank, the default will be inferred from your bundle, which might not be descriptive or consistent across builds. ### File not found error on iOS If you see an error like this when running your application on iOS: ```text theme={} 'HoneycombOpentelemetryReactNative/HoneycombOpentelemetryReactNative-Swift.h' file not found when trying to run for iOS ``` It usually means your application's `Podfile` is missing the `use_frameworks!` line. To resolve this error: 1. Add `use_frameworks!` immediately below `prepare_react_native_project!` in your `Podfile`: ```swift theme={} prepare_react_native_project! use_frameworks! ``` 2. Install the iOS dependencies by navigating to your `ios` directory and running `pod install`: ```bash theme={} cd ios pod install ``` ### Not receiving native telemetry data Unlike JavaScript code, native code does not hot reload on changes. So if you updated your `AppDelegate.swift` or `MainApplication.kt` files and are still not getting native telemetry, you'll need to rebuild your application. Stop metro, the simulator, and restart the build. If this still doesn’t work, try uninstalling the application and reinstalling it. # Get Started with Structured Logs Source: https://docs.honeycomb.io/get-started/start-building/application/structured-events Send structured logs and events to Honeycomb and start querying with high cardinality. Find out how Honeycomb treats structured data and the best methods for getting it in. So you want to use Honeycomb. Maybe this is because you want high cardinality or faster querying times. Maybe you are at the beginning of a project to onboard to tracing or OpenTelemetry. Maybe you are ready to start correlating your log data to trace data, or want to add data from technologies that emit structured logs. Regardless of why you want to send your structured logs to Honeycomb, you are in the right place. If you have semi-structured logs, you may also find the resources shared in [Start Building: Get Started with Unstructured Logs](/get-started/start-building/application/unstructured-events/) helpful. ## Structured Data in Honeycomb Honeycomb refers to structured data as information that follows a predefined, standardized data model. Often this information takes the form of logs emitted by applications to log files other log handlers. For example, you may use a logging library that generates JSON-structured logs. ## Sending Structured Data to Honeycomb If you're ready to send your structured logs to Honeycomb, you can use any of the following options: * [Honeycomb Telemetry Pipeline](/send-data/telemetry-pipeline/): Use the Honeycomb Telemetry Pipeline, which lets you standardize the entirety of telemetry operations on OpenTelemetry, whatever the format of existing logs, traces, and metrics. * [OpenTelemetry Collector](/send-data/logs/collector/): Use the OpenTelemetry Collector as a logging agent to send structured logs to Honeycomb. * [Libhoney](/send-data/logs/structured/libhoney/): Use Honeycomb's suite of structured logging libraries to create and send structured logs to Honeycomb’s Events API. ## Enhancing Data in Honeycomb Once your data is in Honeycomb, you will want to enhance it. For structured logs, you may want to: * [Map your data](/send-data/standardize/map-data/) to ensure Honeycomb's log analytics visualizations are populated * [Transform your data](/send-data/standardize/transform-data/) to map source data severities to Honeycomb standard severities * [Add context to your spans](/send-data/standardize/add-context/) by attaching metadata ## Exploring Log Data in Honeycomb For structured logs, Honeycomb lets you easily query on your data using fields, like status or timestamp. To learn how to analyze your data in Honeycomb, visit [Investigate Log Data in Honeycomb](/investigate/debug/log-data-in-honeycomb/). # Get Started with Traces and Wide Events Source: https://docs.honeycomb.io/get-started/start-building/application/traces Add instrumentation to your application, send traces and wide events to Honeycomb, and start analyzing performance and behavior across your system. [Honeycomb](https://www.honeycomb.io/why-honeycomb/) is a fast analysis tool that helps you analyze your code's performance and behavior to troubleshoot complex relationships within your system to solve problems faster. To use Honeycomb, you first need to get your system's traces into Honeycomb. These instructions will guide you through the process of sending trace data from an application in your local development environment to Honeycomb and exploring your data in Honeycomb. Not ready to instrument and deploy an application, but want to see what Honeycomb can do for you? Check out this [interactive demo](https://play.honeycomb.io/sandbox/environments/analyze-debug-tour) that requires no setup, or learn what is possible from the [guided tutorials in our Honeycomb sandbox](https://play.honeycomb.io/sandbox/tours)! ## Before You Begin Before you run the code, you'll need to do a few things. ### Create a Honeycomb Account Before you can use Honeycomb products, you'll need to decide whether you would like Honeycomb to store your data in a US-based or EU-based location. Then, [create a Honeycomb account in the US](https://ui.honeycomb.io/signup) or [create a Honeycomb account in the EU](https://ui.eu1.honeycomb.io/signup). Signup is free! ### Create a Honeycomb Team Complete your account creation by giving us a team name. Honeycomb uses teams to organize groups of users, grant them access to data, and create a shared work history in Honeycomb. We recommend using your company or organization name as your Honeycomb team name. ### Get Your Honeycomb API Key To send data to Honeycomb, you'll need your Honeycomb API Key. Once you create your team, you will be able to view or copy it. Make note of your API Key; for security reasons, you will not be able to see it again, and you will need it later! You can also [find your Honeycomb API Key](/configure/environments/manage-api-keys/#find-api-keys) any time in your Environment Settings. ## Send Telemetry Data to Honeycomb Once you have your Honeycomb API key and have chosen an application, it's time to send telemetry data to Honeycomb! This guide helps users who are new to observability get their trace data into Honeycomb using [OpenTelemetry](/send-data/opentelemetry/). If you already have an OpenTelemetry implementation and are switching to Honeycomb, read about [OpenTelemetry Collector](/send-data/opentelemetry/collector/). ### Choose Your Application Choose a single application or service that will send data to Honeycomb. To successfully complete this Quick Start, you should have access to modify your application's source code. To test the application when you are finished, you must be able to run your application or service in a development environment. Don't have access to an application? Follow along using one of our [example applications](/get-started/start-building/example-applications/)! ### Add Automatic Instrumentation to Your Code The quickest way to start seeing your trace data in Honeycomb is to use [OpenTelemetry](https://opentelemetry.io/), an open-source collection of tools, APIs, and SDKs, to automatically inject instrumentation code into your application without requiring explicit changes to your codebase. Automatic instrumentation works slightly differently within each language, but the general idea is that it attaches hooks into popular tools and frameworks and "watches" for certain functions to be called. When they're called, the instrumentation automatically starts and completes trace spans on behalf of your application. When you add automatic instrumentation to your code, OpenTelemetry will build spans, which represent units of work or operations within your application that you want to capture and analyze for observability purposes. This Quick Start uses the `npm` dependency manager. For instructions with `yarn` or if using TypeScript, read our [OpenTelemetry Node.js documentation](/send-data/javascript-nodejs/opentelemetry-sdk/#add-automatic-instrumentation). #### Acquire Dependencies Open your terminal, navigate to the location of your project on your drive, and install OpenTelemetry's automatic instrumentation meta package and OpenTelemetry's Node.js SDK package: ```shell theme={} npm install --save \ @opentelemetry/auto-instrumentations-node \ @opentelemetry/sdk-node ``` | Module | Description | | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `auto-instrumentations-node` | OpenTelemetry's meta package that provides a way to add automatic instrumentation to any Node application to capture telemetry data from a number of popular libraries and frameworks, like `express`, `dns`, `http`, and more. | | `sdk-node` | OpenTelemetry's Node.js distribution package that streamlines configuration and allows you to instrument as quickly and easily as possible. | Alternatively, install [individual instrumentation packages](https://github.com/open-telemetry/opentelemetry-js#instrumentations). If using TypeScript, install `ts-node` to run the code: ```shell theme={} npm install --save-dev ts-node ``` #### Initialize Create an initialization file, commonly known as the `tracing.js` file: ```javascript theme={} // Example filename: tracing.js 'use strict'; const { startNodeSDK } = require('@opentelemetry/sdk-node'); const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node'); startNodeSDK({ instrumentations: [ getNodeAutoInstrumentations(), ], }); ``` #### Configure the OpenTelemetry SDK Create an `otelconfig.yaml` file with the following content: ```yaml theme={} file_format: "1.1" resource: attributes: - name: service.name value: ${OTEL_SERVICE_NAME:-my-service} tracer_provider: processors: - batch: exporter: otlp_http: endpoint: https://api.honeycomb.io/v1/traces # Use the endpoint below for EU # endpoint: https://api.eu1.honeycomb.io/v1/traces headers: - name: x-honeycomb-team value: ${HONEYCOMB_API_KEY} propagator: composite: - tracecontext: - baggage: ``` Set the following environment variables before running your application: | Environment Variable | Value | | :------------------- | :----------------------- | | `HONEYCOMB_API_KEY` | Your Honeycomb API key | | `OTEL_SERVICE_NAME` | The name of your service | When `OTEL_CONFIG_FILE` is set, the configuration file is the single source of truth for the SDK. Other `OTEL_*` environment variables are ignored by design, so set all SDK options in the YAML file. You can still reference environment variables from inside the YAML using `${VAR_NAME}` substitution. The OpenTelemetry declarative configuration is stable at the specification level. Individual fields still under active development are marked with a `/development` suffix in the YAML (see [configuration versioning](https://github.com/open-telemetry/opentelemetry-configuration/blob/main/VERSIONING.md#experimental-features)). Check the [language support status](https://github.com/open-telemetry/opentelemetry-configuration/blob/main/language-support-status.md) for per-SDK maturity. Add `meter_provider` and `logger_provider` sections to the same file to export metrics and logs. This version also enables resource detectors, which add attributes such as `host.*` and `process.*` automatically: ```yaml theme={} file_format: "1.1" resource: attributes: - name: service.name value: ${OTEL_SERVICE_NAME:-my-service} detection/development: detectors: - host: - os: - process: - service: - env: tracer_provider: # traces processors: - batch: exporter: otlp_http: endpoint: https://api.honeycomb.io/v1/traces headers: - name: x-honeycomb-team value: ${HONEYCOMB_API_KEY} meter_provider: # metrics readers: - periodic: exporter: otlp_http: endpoint: https://api.honeycomb.io/v1/metrics headers: - name: x-honeycomb-team value: ${HONEYCOMB_API_KEY} # Legacy metrics only; omit with the current metrics experience: # - name: x-honeycomb-dataset # value: ${HONEYCOMB_METRICS_DATASET} logger_provider: # logs processors: - batch: exporter: otlp_http: endpoint: https://api.honeycomb.io/v1/logs headers: - name: x-honeycomb-team value: ${HONEYCOMB_API_KEY} propagator: composite: - tracecontext: - baggage: ``` For the EU instance, replace `https://api.honeycomb.io` with `https://api.eu1.honeycomb.io` throughout the file. If you use [Honeycomb Classic](/troubleshoot/product-lifecycle/recommended-migrations/#migrate-from-honeycomb-classic-to-honeycomb-environments), you must also specify the Dataset using the `x-honeycomb-dataset` header. ```shell theme={} export OTEL_EXPORTER_OTLP_HEADERS="x-honeycomb-team=your-api-key,x-honeycomb-dataset=your-dataset" ``` If you are sending data directly to Honeycomb, you must configure the API key and service name. If you are using an [OpenTelemetry Collector](/send-data/opentelemetry/collector/), configure your API key at the Collector level instead. #### Run Your Application Point the SDK at your configuration file using the `OTEL_CONFIG_FILE` environment variable, then run the Node.js app with the initialization file: ```shell theme={} OTEL_CONFIG_FILE=./otelconfig.yaml node -r ./tracing.js YOUR_APPLICATION_NAME.js ``` Be sure to replace `YOUR_APPLICATION_NAME` with the name of your application's main file. Alternatively, you can import the initialization file as the first step in your application lifecycle. In Honeycomb's UI, you should now see your application's incoming requests and outgoing HTTP calls generate traces. This Quick Start uses the `pip` package manager. For instructions with `poetry`, read our [OpenTelemetry Python documentation](/send-data/python/opentelemetry-sdk/#add-automatic-instrumentation). #### Acquire Dependencies 1. Install the OpenTelemetry Python packages: ```shell theme={} python -m pip install "opentelemetry-sdk[file-configuration]" \ opentelemetry-instrumentation \ opentelemetry-distro \ opentelemetry-exporter-otlp ``` The `[file-configuration]` extra installs the optional dependencies needed to load a YAML configuration file. 2. Install instrumentation libraries for the packages used by your application. We recommend using the `opentelemetry-bootstrap` tool that comes with the OpenTelemetry SDK to scan your application packages and print out a list of available instrumentation libraries. You should then add these libraries to your `requirements.txt` file: ```shell theme={} opentelemetry-bootstrap >> requirements.txt pip install -r requirements.txt ``` If you do not use a `requirements.txt` file, you can install the libraries directly in your current environment: ```shell theme={} opentelemetry-bootstrap --action=install ``` #### Configure the OpenTelemetry SDK Create an `otelconfig.yaml` file with the following content: ```yaml theme={} file_format: "1.0" resource: attributes: - name: service.name value: ${OTEL_SERVICE_NAME:-my-service} tracer_provider: processors: - batch: exporter: otlp_http: endpoint: https://api.honeycomb.io/v1/traces # Use the endpoint below for EU # endpoint: https://api.eu1.honeycomb.io/v1/traces headers: - name: x-honeycomb-team value: ${HONEYCOMB_API_KEY} propagator: composite: - tracecontext: - baggage: ``` Set the following environment variables before running your application: | Environment Variable | Value | | :------------------- | :----------------------- | | `HONEYCOMB_API_KEY` | Your Honeycomb API key | | `OTEL_SERVICE_NAME` | The name of your service | When `OTEL_CONFIG_FILE` is set, the configuration file is the single source of truth for the SDK. Other `OTEL_*` environment variables are ignored by design, so set all SDK options in the YAML file. You can still reference environment variables from inside the YAML using `${VAR_NAME}` substitution. The OpenTelemetry declarative configuration is stable at the specification level. Individual fields still under active development are marked with a `/development` suffix in the YAML (see [configuration versioning](https://github.com/open-telemetry/opentelemetry-configuration/blob/main/VERSIONING.md#experimental-features)). Check the [language support status](https://github.com/open-telemetry/opentelemetry-configuration/blob/main/language-support-status.md) for per-SDK maturity. Add `meter_provider` and `logger_provider` sections to the same file to export metrics and logs. This version also enables resource detectors, which add attributes such as `host.*` and `process.*` automatically: ```yaml theme={} file_format: "1.0" resource: attributes: - name: service.name value: ${OTEL_SERVICE_NAME:-my-service} detection/development: detectors: - host: - os: - process: - service: tracer_provider: # traces processors: - batch: exporter: otlp_http: endpoint: https://api.honeycomb.io/v1/traces headers: - name: x-honeycomb-team value: ${HONEYCOMB_API_KEY} meter_provider: # metrics readers: - periodic: exporter: otlp_http: endpoint: https://api.honeycomb.io/v1/metrics headers: - name: x-honeycomb-team value: ${HONEYCOMB_API_KEY} # Legacy metrics only; omit with the current metrics experience: # - name: x-honeycomb-dataset # value: ${HONEYCOMB_METRICS_DATASET} logger_provider: # logs processors: - batch: exporter: otlp_http: endpoint: https://api.honeycomb.io/v1/logs headers: - name: x-honeycomb-team value: ${HONEYCOMB_API_KEY} propagator: composite: - tracecontext: - baggage: ``` For the EU instance, replace `https://api.honeycomb.io` with `https://api.eu1.honeycomb.io` throughout the file. If you use [Honeycomb Classic](/troubleshoot/product-lifecycle/recommended-migrations/#migrate-from-honeycomb-classic-to-honeycomb-environments), you must also specify the Dataset using the `x-honeycomb-dataset` header. ```shell theme={} export OTEL_EXPORTER_OTLP_HEADERS="x-honeycomb-team=your-api-key,x-honeycomb-dataset=your-dataset" ``` If you are sending data directly to Honeycomb, you must configure the API key and service name. If you are using an [OpenTelemetry Collector](/send-data/opentelemetry/collector/), configure your API key at the Collector level instead. #### Run Your Application Point the SDK at your configuration file using the `OTEL_CONFIG_FILE` environment variable, then run your Python application with the OpenTelemetry Python automatic instrumentation tool `opentelemetry-instrument`: ```shell theme={} OTEL_CONFIG_FILE=./otelconfig.yaml opentelemetry-instrument python YOUR_APPLICATION_NAME.py ``` Be sure to replace `YOUR_APPLICATION_NAME` with the name of your application's main file. In Honeycomb's UI, you should now see your application's incoming requests and outgoing HTTP calls generate traces. #### Acquire Dependencies The automatic instrumentation agent for OpenTelemetry Java will automatically generate trace data from your application. The agent is packaged as a JAR file and is run alongside your app. In order to use the automatic instrumentation agent, you must first download it: ```shell theme={} curl -L -O https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar ``` #### Configure the OpenTelemetry SDK Create an `otelconfig.yaml` file with the following content: ```yaml theme={} file_format: "1.1" resource: attributes: - name: service.name value: ${OTEL_SERVICE_NAME:-my-service} tracer_provider: processors: - batch: exporter: otlp_http: endpoint: https://api.honeycomb.io/v1/traces # Use the endpoint below for EU # endpoint: https://api.eu1.honeycomb.io/v1/traces headers: - name: x-honeycomb-team value: ${HONEYCOMB_API_KEY} propagator: composite: - tracecontext: - baggage: ``` Set the following environment variables before running your application: | Environment Variable | Value | | :------------------- | :----------------------- | | `HONEYCOMB_API_KEY` | Your Honeycomb API key | | `OTEL_SERVICE_NAME` | The name of your service | When `OTEL_CONFIG_FILE` is set, the configuration file is the single source of truth for the SDK. Other `OTEL_*` environment variables are ignored by design, so set all SDK options in the YAML file. You can still reference environment variables from inside the YAML using `${VAR_NAME}` substitution. The OpenTelemetry declarative configuration is stable at the specification level. Individual fields still under active development are marked with a `/development` suffix in the YAML (see [configuration versioning](https://github.com/open-telemetry/opentelemetry-configuration/blob/main/VERSIONING.md#experimental-features)). Check the [language support status](https://github.com/open-telemetry/opentelemetry-configuration/blob/main/language-support-status.md) for per-SDK maturity. Add `meter_provider` and `logger_provider` sections to the same file to export metrics and logs. This version also enables resource detectors, which add attributes such as `host.*` and `process.*` automatically: ```yaml theme={} file_format: "1.1" resource: attributes: - name: service.name value: ${OTEL_SERVICE_NAME:-my-service} detection/development: detectors: - host: - process: - service: tracer_provider: # traces processors: - batch: exporter: otlp_http: endpoint: https://api.honeycomb.io/v1/traces headers: - name: x-honeycomb-team value: ${HONEYCOMB_API_KEY} meter_provider: # metrics readers: - periodic: exporter: otlp_http: endpoint: https://api.honeycomb.io/v1/metrics headers: - name: x-honeycomb-team value: ${HONEYCOMB_API_KEY} # Legacy metrics only; omit with the current metrics experience: # - name: x-honeycomb-dataset # value: ${HONEYCOMB_METRICS_DATASET} logger_provider: # logs processors: - batch: exporter: otlp_http: endpoint: https://api.honeycomb.io/v1/logs headers: - name: x-honeycomb-team value: ${HONEYCOMB_API_KEY} propagator: composite: - tracecontext: - baggage: ``` For the EU instance, replace `https://api.honeycomb.io` with `https://api.eu1.honeycomb.io` throughout the file. #### Run Your Application Point the agent at your configuration file using the `OTEL_CONFIG_FILE` environment variable, then run your application: ```shell theme={} OTEL_CONFIG_FILE=./otelconfig.yaml java -javaagent:opentelemetry-javaagent.jar -jar /path/to/myapp.jar ``` In Honeycomb's UI, you should now see your application's incoming requests and outgoing HTTP calls generate traces. This Quick Start uses ASP.NET Core. #### Acquire Dependencies Install the OpenTelemetry .NET packages. For example, with the .NET CLI, use: ```shell theme={} dotnet add package OpenTelemetry dotnet add package OpenTelemetry.Extensions.Hosting dotnet add package OpenTelemetry.Instrumentation.AspNetCore dotnet add package OpenTelemetry.Instrumentation.Http ``` #### Initialize Initialize the TracerProvider during application setup. ```csharp theme={} services.AddOpenTelemetry().WithTracing(builder => builder .AddAspNetCoreInstrumentation() .AddHttpClientInstrumentation() .AddOtlpExporter()); ``` #### Configure Use environment variables to configure the OpenTelemetry SDK: ```shell theme={} export OTEL_SERVICE_NAME="your-service-name" export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf" export OTEL_EXPORTER_OTLP_ENDPOINT="https://api.honeycomb.io:443" # US instance #export OTEL_EXPORTER_OTLP_ENDPOINT="https://api.eu1.honeycomb.io:443" # EU instance export OTEL_EXPORTER_OTLP_HEADERS="x-honeycomb-team=" ``` | Variable | Description | | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `OTEL_SERVICE_NAME` | Service name. When you send data, Honeycomb creates a dataset in which to store your data and uses this as the name. Can be any string. | | `OTEL_EXPORTER_OTLP_PROTOCOL` | The data format that the SDK uses to send telemetry to Honeycomb. For more on data format configuration options, read [Choosing between gRPC and HTTP](/send-data/dotnet/#choosing-between-grpc-and-http). | | `OTEL_EXPORTER_OTLP_ENDPOINT` | Honeycomb endpoint to which you want to send your data. | | `OTEL_EXPORTER_OTLP_HEADERS` | Adds your Honeycomb API Key to the exported telemetry headers for authorization. [Learn how to find your Honeycomb API Key](/configure/environments/manage-api-keys/#find-api-keys). | #### Run Run your application. You will see the incoming requests and outgoing HTTP calls generate traces. ```shell theme={} dotnet run ``` In Honeycomb's UI, you should now see your application's incoming requests and outgoing HTTP calls generate traces. #### Acquire Dependencies Install OpenTelemetry Go packages: ```shell theme={} go get \ go.opentelemetry.io/contrib/otelconf/x \ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp ``` #### Initialize Prepare your application to send spans to Honeycomb. Open or create a file called `main.go`: ```go theme={} package main import ( "context" "fmt" "log" "net/http" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" otelconf "go.opentelemetry.io/contrib/otelconf/x" "go.opentelemetry.io/otel" ) // Implement an HTTP Handler function to be instrumented func httpHandler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello, World") } func main() { // Use otelconf/x to set up the OpenTelemetry SDK. The `/x` package // adds support for experimental spec fields such as resource detectors. sdk, err := otelconf.NewSDK() if err != nil { log.Fatalf("error setting up OTel SDK - %e", err) } defer sdk.Shutdown(context.Background()) otel.SetTracerProvider(sdk.TracerProvider()) otel.SetTextMapPropagator(sdk.Propagator()) // Initialize HTTP handler instrumentation handler := http.HandlerFunc(httpHandler) wrappedHandler := otelhttp.NewHandler(handler, "hello") http.Handle("/hello", wrappedHandler) // Serve HTTP server log.Fatal(http.ListenAndServe(":3030", nil)) } ``` #### Configure the OpenTelemetry SDK Create an `otelconfig.yaml` file with the following content: ```yaml theme={} file_format: "1.1" resource: attributes: - name: service.name value: ${OTEL_SERVICE_NAME:-my-service} tracer_provider: processors: - batch: exporter: otlp_http: endpoint: https://api.honeycomb.io/v1/traces # Use the endpoint below for EU # endpoint: https://api.eu1.honeycomb.io/v1/traces headers: - name: x-honeycomb-team value: ${HONEYCOMB_API_KEY} propagator: composite: - tracecontext: - baggage: ``` Set the following environment variables before running your application: | Environment Variable | Value | | :------------------- | :----------------------- | | `HONEYCOMB_API_KEY` | Your Honeycomb API key | | `OTEL_SERVICE_NAME` | The name of your service | When `OTEL_CONFIG_FILE` is set, the configuration file is the single source of truth for the SDK. Other `OTEL_*` environment variables are ignored by design, so set all SDK options in the YAML file. You can still reference environment variables from inside the YAML using `${VAR_NAME}` substitution. The OpenTelemetry declarative configuration is stable at the specification level. Individual fields still under active development are marked with a `/development` suffix in the YAML (see [configuration versioning](https://github.com/open-telemetry/opentelemetry-configuration/blob/main/VERSIONING.md#experimental-features)). Check the [language support status](https://github.com/open-telemetry/opentelemetry-configuration/blob/main/language-support-status.md) for per-SDK maturity. Add `meter_provider` and `logger_provider` sections to the same file to export metrics and logs. This version also enables resource detectors, which add attributes such as `host.*` and `process.*` automatically: ```yaml theme={} file_format: "1.1" resource: attributes: - name: service.name value: ${OTEL_SERVICE_NAME:-my-service} detection/development: detectors: - host: - container: - process: - service: tracer_provider: # traces processors: - batch: exporter: otlp_http: endpoint: https://api.honeycomb.io/v1/traces headers: - name: x-honeycomb-team value: ${HONEYCOMB_API_KEY} meter_provider: # metrics readers: - periodic: exporter: otlp_http: endpoint: https://api.honeycomb.io/v1/metrics headers: - name: x-honeycomb-team value: ${HONEYCOMB_API_KEY} # Legacy metrics only; omit with the current metrics experience: # - name: x-honeycomb-dataset # value: ${HONEYCOMB_METRICS_DATASET} logger_provider: # logs processors: - batch: exporter: otlp_http: endpoint: https://api.honeycomb.io/v1/logs headers: - name: x-honeycomb-team value: ${HONEYCOMB_API_KEY} propagator: composite: - tracecontext: - baggage: ``` For the EU instance, replace `https://api.honeycomb.io` with `https://api.eu1.honeycomb.io` throughout the file. #### Run Your Application Point the SDK at your configuration file using the `OTEL_CONFIG_FILE` environment variable, then run your application: ```shell theme={} OTEL_CONFIG_FILE=./otelconfig.yaml go run YOUR_APPLICATION_NAME.go ``` Be sure to replace `YOUR_APPLICATION_NAME` with the name of your application's main file. In Honeycomb's UI, you should now see your application's incoming requests and outgoing HTTP calls generate traces. #### Acquire Dependencies Add these gems to your Gemfile: ```ruby theme={} gem 'opentelemetry-sdk' gem 'opentelemetry-exporter-otlp' gem 'opentelemetry-instrumentation-all' ``` | Gem | Description | | ----------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `opentelemetry-sdk` | Required to create spans | | `opentelemetry-exporter-otlp` | An exporter to send data in the OTLP format | | `opentelemetry-instrumentation-all` | A meta package that provides instrumentation for Rails, Sinatra, several HTTP libraries, [and more](https://github.com/open-telemetry/opentelemetry-ruby#instrumentation-libraries) | Install the gems using your terminal: ```shell theme={} bundle install ``` #### Initialize Initialize OpenTelemetry early in your application lifecycle. For Rails applications, we recommend that you use a Rails initializer. For other Ruby services, initialize as early as possible in the startup process. ```ruby theme={} # config/initializers/opentelemetry.rb require 'opentelemetry/sdk' require 'opentelemetry/exporter/otlp' require 'opentelemetry/instrumentation/all' OpenTelemetry::SDK.configure do |c| c.use_all() # enables all instrumentation! end ``` #### Configure the OpenTelemetry SDK Use environment variables to configure OpenTelemetry to send events to Honeycomb: ```ruby theme={} export OTEL_EXPORTER_OTLP_ENDPOINT="https://api.honeycomb.io" # US instance #export OTEL_EXPORTER_OTLP_ENDPOINT="https://api.eu1.honeycomb.io" # EU instance export OTEL_EXPORTER_OTLP_HEADERS="x-honeycomb-team=your-api-key" export OTEL_SERVICE_NAME="your-service-name" ``` | Variable | Description | | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `OTEL_EXPORTER_OTLP_ENDPOINT` | Base endpoint to which you want to send your telemetry data. | | `OTEL_EXPORTER_OTLP_HEADERS` | List of headers to apply to all outgoing telemetry data. Place your API Key generated in Honeycomb in the `x-honeycomb-team` header. [Learn how to find your Honeycomb API Key](/configure/environments/manage-api-keys/#find-api-keys). | | `OTEL_SERVICE_NAME` | Service name. When you send data, Honeycomb creates a dataset in which to store your data and uses this as the name. Can be any string. | #### Run Your Application Run your Ruby application. In Honeycomb's UI, you should now see your application's incoming requests and outgoing HTTP calls generate traces. Refer to [Honeycomb for Kubernetes Overview](/send-data/kubernetes/) for a Quick Start and all configuration options to get Kubernetes metrics, logs, events, as well as Kubernetes attributes added to application traces, logs, and metrics in Honeycomb. If your preferred language is not covered here, you can find relevant instrumentation information in the [OpenTelemetry community documentation](https://opentelemetry.io/docs/languages/). For Rust, we recommend you use the [opentelemetry](https://crates.io/crates/opentelemetry) and [opentelemetry-otlp](https://crates.io/crates/opentelemetry-otlp) crates to send data to Honeycomb over OTLP. For any required configuration values, see [Using the Honeycomb OpenTelemetry Endpoint](/send-data/opentelemetry/#using-the-honeycomb-opentelemetry-endpoint). ### Generate Automated Data Now that you have added automatic instrumentation to your application and have it running in your development environment, interact with your application by making a few requests. Making requests to your service will generate telemetry data and send it to Honeycomb where it will appear in the Honeycomb UI within seconds. If you have made several service requests in your development environment and after several minutes, you still do not see any data, reach out for help in our [Pollinators Community Slack](/troubleshoot/community/#join-pollinators-community-slack). ### View an Example Trace Before you move on, take a look at the data that you have generated using automatic instrumentation by [viewing an example trace](/investigate/analyze/explore-traces/), which is a visual diagram that represents the complete journey of a request or transaction as it traverses a distributed system. Traces provide a way to visualize and understand the flow of execution and the interactions between various components involved in serving a request. They can help you find the source of errors in a system, identify the slowest processes, and break down the user experience in great detail. While Honeycomb helps you analyze all of your outputs, where we particularly shine is when working with traces to give you a visual representation of where requests spend time in your system. In this example, we want to see a count of events, an average latency for those events, and a heatmap of latency. To see your trace: 1. Depending on where you created your account, either [log in to Honeycomb US](https://ui.honeycomb.io/) or [log in to Honeycomb EU](https://ui.eu1.honeycomb.io) using your Honeycomb account. 2. From the left sidebar, navigate to **Query**. 3. In the **SELECT** clause, add `HEATMAP(duration_ms)` 4. Select **Run Query**. 5. In the heatmap results, click on a dot to get a trace. We generated the following examples after adding automatic instrumentation to a simple greeting service application written in Node.js. You can [see the code in our GitHub repository](https://github.com/brianlangbecker/best-practices-blog). Here's our example heatmap: Heatmap for our automatically-instrumented example application, showing three dots, each of which represents a trace And here is our example trace: First trace for our automatically-instrumented example application In this trace, you can see: * the spans within the trace * how long each span took * which spans contain errors (none, in this example) All of this is useful information, but more information will allow us to dig even more deeply! To get the most insight into your system, you should enhance your automatic instrumentation by [adding custom instrumentation](/send-data/standardize/add-custom-instrumentation/) surrounding your business logic. ## What's Next? Excellent work! If you made it this far, you should now have telemetry data from your application flowing into Honeycomb. You can deploy to production and start gaining new insights on real traffic! But there is so much more to explore! To learn more about what you can do with Honeycomb, check out: * [Customize Instrumentation](/send-data/standardize/add-custom-instrumentation/): Walk through the process of adding custom instrumentation, so you can get additional visibility into the inner workings of your business logic. * [Ways to Explore Your Data](/observe/): Get a quick run-through of the different ways you can explore your data in Honeycomb. * [Board Templates](/observe/boards/): Get key insights with one-click with out-of-the-box Board Templates. * [Honeycomb's Sandbox](https://play.honeycomb.io/sandbox/tours): Explore common scenarios with real data. * [DevRel Office Hours](https://www.honeycomb.io/devrel/observability-office-hours/): Join in on observability talk with world-class experts. * [Integrations](/integrations/): Learn about other types of data you can explore with Honeycomb. # Get Started with Unstructured Logs Source: https://docs.honeycomb.io/get-started/start-building/application/unstructured-events Send unstructured logs to Honeycomb and start querying them with high cardinality. Find out how Honeycomb parses unstructured data and which ingestion methods work best. So you want to use Honeycomb. Maybe this is because you want high cardinality or faster querying times. Maybe you are at the beginning of a project to onboard to tracing or OpenTelemetry. But right now, you rely on unstructured logs for core analysis. Event logs are good for debugging, easy to generate, and unstructured logs are often the easiest to implement. The downside? The lack of standardization makes debugging using unstructured logs challenging, and querying unstructured logs is highly inefficient. You can sometimes do post-processing with regular expressions, but if you have to use regular expressions to understand what is happening in production, you are wasting your analytical skills on what amounts to a data formatting problem instead of actually analyzing the information the system is sending. The best solution is to transform your unstructured logs into a structured format before sending to Honeycomb. But regardless of whether you are ready to migrate to structured logs, if you have unstructured logs that you would like to get into Honeycomb, then you are in the right place. If you have semi-structured logs, you may also find the resources shared in [Start Building: Get Started with Structured Logs](/get-started/start-building/application/structured-events/) helpful. ## Unstructured Data in Honeycomb Honeycomb refers to unstructured data as information that does not follow a predefined data model. Often this information takes the form of logs emitted by applications to log files, but it can also include raw text or any kind of event data that has not been formatted into a structured format like JSON or key-value pairs. Some examples: * **Raw log files**: Traditional log files generated by systems or applications. Example: `2024-10-15 12:00:00 ERROR Connection timeout while accessing database` * **Text-based application logs**: Logs that contain text messages, but no clear structure or predefined format. Example: `User login failed: username=admin, reason=invalid password` * **Freeform event data**: Events that capture information in a narrative or free-form text. Example: `Server xyz failed to respond due to high CPU usage` * **Error or debug messages**: Messages output during application runtime, typically for debugging or error reporting, but without a structured schema. Example: `Stacktrace: at main.py: line 23` If you send unstructured logs to Honeycomb without transforming them into structured logs, then we will accept the data, but treat it as a single, opaque field, which will be harder to filter or query on. This also means you will miss out on some powerful observability features, such as tracing, high-cardinality querying, and exploring data interactively. To avoid this, we recommend transforming unstructured data into structured data. For example, you might transform this unstructured log: ```text theme={} 2024-10-15 12:00:00 ERROR connection timeout ``` Into this structured log: ```text theme={} {"timestamp": "2024-10-15T12:00:00Z", "status": "error", "message": "connection timeout"} ``` ## Sending Unstructured Logs to Honeycomb If you're ready to transform your unstructured logs into structured logs, you can use any of the following options: * [Honeycomb Telemetry Pipeline](/send-data/telemetry-pipeline/): Use the Honeycomb Telemetry Pipeline, which lets you standardize the entirety of telemetry operations on OpenTelemetry, whatever the format of existing logs, traces, and metrics. * [OpenTelemetry Collector](/send-data/logs/collector/): Use the OpenTelemetry Collector as a logging agent along with the [Filelog Receiver](/send-data/logs/collector/#collect-any-log-with-the-filelog-receiver) to parse unstructured logs and sending them to Honeycomb as structured logs. * [HoneyTail + RegEx](/send-data/logs/unstructured/honeytail-regex/): Ingest unstructured logs using custom regular expressions and Honeytail, our lightweight tool that will tail your existing log files, parse the content, and send it to Honeycomb. ## Enhancing Data in Honeycomb Once your data is in Honeycomb, you will want to enhance it. If you've transformed your data to structured logs, you can use the resources shared in [Start Building: Structured Logs](/get-started/start-building/application/structured-events/#enhancing-data-in-honeycomb). Otherwise, consider [adding metadata](/send-data/standardize/add-context/) like timestamps or categories to help you query later. ## Exploring Log Data in Honeycomb For structured logs, Honeycomb lets you easily query based on fields like status or timestamp. For unstructured logs, you can still use Honeycomb, but it will be harder to filter or analyze your data because the information is contained in one text blob. To learn how to analyze your data in Honeycomb, visit [Investigate Log Data in Honeycomb](/investigate/debug/log-data-in-honeycomb/). # Get Started with Honeycomb for Web Source: https://docs.honeycomb.io/get-started/start-building/application/web Instrument your web application with the Honeycomb Web Instrumentation package, built on OpenTelemetry, and get full visibility into your customer experience. Honeycomb offers web instrumentation, so you can get complete visibility into your customer experience, much like a Real User Monitoring (RUM) solution, but without any need for a proprietary agent. Our Honeycomb Web Instrumentation package, a wrapper for the official OpenTelemetry Javascript SDK, allows you to get a rich set of data for your web service, so you can understand what users are experiencing when using your service and identify areas you can optimize. If you're using micro frontend architecture, visit [Observability and Micro Frontends](/get-started/best-practices/micro-frontends/) to see our recommendations for implementing OpenTelemetry and the Honeycomb OpenTelemetry Web SDK. In this guide, we walk you through installing and configuring the default Honeycomb Web Instrumentation package, which will help you collect data on a variety of performance concerns for web services, as well as give you the necessary foundation for extending traces to any backend services that have OpenTelemetry instrumentation. We will cover how to: * Set up instrumentation on your web site or web app * Send data to Honeycomb * Start exploring your data in Honeycomb After following this guide, you will: * Have a rich set of default instrumentation available to help you debug your web service * Know how to access your data in Honeycomb and find items of interest to investigate * Be able to start improving your (and your team's) Observability practices For more structured learning, check out the [Honeycomb for Frontend Observability](https://academy.honeycomb.io/app/courses/beaa9b6e-0656-4722-a584-f4b8e6ca09f3) course from Honeycomb Academy. ## Before You Begin Before you run the code, you'll need to do a few things. ### Sign up for Honeycomb If you don't already have a Honeycomb account, you can sign up for one. Signup is free. Honeycomb stores your data in either a US-based or EU-based location, depending on your account region: * [Create a US account](https://ui.honeycomb.io/signup) * [Create an EU account](https://ui.eu1.honeycomb.io/signup) ### Get an API Key For this guide, you'll need a [Honeycomb Ingest API Key](/configure/environments/manage-api-keys/#create-api-key) with the **Can create services/datasets** permission. This lets your application send telemetry to Honeycomb and create a dataset for your service. When deploying to production, replace this key with a separate key that does not allow dataset creation. This helps protect your data structure in live environments. Make note of your API key; for security reasons, you will not be able to see the key again, and you will need it later. ## Install the Honeycomb Web Instrumentation Package We make our Honeycomb Web Instrumentation package available as an NPM package, so you can include it in your web bundle. Navigate to the root directory of your service's repo, and then install the package: If your repo does not contain a `yarn.lock` file, install with NPM. ```shell NPM theme={} npm install @honeycombio/opentelemetry-web '@opentelemetry/auto-instrumentations-web' ``` ```shell Yarn theme={} yarn add @honeycombio/opentelemetry-web '@opentelemetry/auto-instrumentations-web' ``` Confirm that the install was successful by opening your `package.json` file and checking that the `Dependencies` list now contains `@honeycomb/opentelemetry-web`. ## Send Data to Honeycomb Once you have your Honeycomb Ingest API key and have installed Honeycomb's Web Instrumentation package, it's time to send telemetry data to Honeycomb! ### Instantiate Your Instrumentation To get a comprehensive set of data about your application, you need to instantiate your instrumentation as early as possible in your application's lifecycle. You can set up your web instrumentation using a popular JavaScript framework, using inline JavaScript, or using a JavaScript helper file. To get started the most quickly, add your package configuration inline in the root instantiation file of your application: Be sure to replace `[YOUR API KEY HERE]` and `[YOUR APPLICATION NAME HERE]` with the value of your Honeycomb API Ingest Key and the name of your service, respectively. We use the `serviceName` variable to name your dataset in Honeycomb, so replace it with a name that you will find useful. ```javascript theme={} // index.js or main.js // other import statements... import { HoneycombWebSDK } from '@honeycombio/opentelemetry-web'; import { getWebAutoInstrumentations } from '@opentelemetry/auto-instrumentations-web'; const configDefaults = { ignoreNetworkEvents: true, // propagateTraceHeaderCorsUrls: [ // /.+/g, // Regex to match your backend URLs. Update to the domains you wish to include. // ] } const sdk = new HoneycombWebSDK({ // endpoint: "https://api.eu1.honeycomb.io/v1/traces", // Send to EU instance of Honeycomb. Defaults to sending to US instance. debug: true, // Set to false for production environment. apiKey: '[YOUR API KEY HERE]', // Replace with your Honeycomb Ingest API Key. serviceName: '[YOUR APPLICATION NAME HERE]', // Replace with your application name. Honeycomb uses this string to find your dataset when we receive your data. When no matching dataset exists, we create a new one with this name if your API Key has the appropriate permissions. instrumentations: [getWebAutoInstrumentations({ // Loads custom configuration for xml-http-request instrumentation. '@opentelemetry/instrumentation-xml-http-request': configDefaults, '@opentelemetry/instrumentation-fetch': configDefaults, '@opentelemetry/instrumentation-document-load': configDefaults, })], }); sdk.start(); // Application instantiation code ``` #### Tips for Common JavaScript Frameworks In this section, we show you how to set up your web instrumentation in popular JS frameworks. Depending on the framework your application uses, instantiation may be handled differently. If you run into trouble, please ask for help in our [Pollinators Community](/troubleshoot/community/). If you are using React (such as with `create-react-app` or via Next.js), you will need to wrap the Honeycomb code snippet in a component to instantiate it. 1. Create a file called `observability.jsx|tsx` in your `components` directory, and insert the code: ```javascript theme={} // observability.jsx|tsx "use client"; // browser only: https://react.dev/reference/react/use-client import { HoneycombWebSDK } from '@honeycombio/opentelemetry-web'; import { getWebAutoInstrumentations } from '@opentelemetry/auto-instrumentations-web'; const configDefaults = { ignoreNetworkEvents: true, // propagateTraceHeaderCorsUrls: [ // /.+/g, // Regex to match your backend URLs. Update to the domains you wish to include. // ] } export default function Observability(){ try { const sdk = new HoneycombWebSDK({ // endpoint: "https://api.eu1.honeycomb.io/v1/traces", // Send to EU instance of Honeycomb. Defaults to sending to US instance. debug: true, // Set to false for production environment. apiKey: '[YOUR API KEY HERE]', // Replace with your Honeycomb Ingest API Key. serviceName: '[YOUR APPLICATION NAME HERE]', // Replace with your application name. Honeycomb uses this string to find your dataset when we receive your data. When no matching dataset exists, we create a new one with this name if your API Key has the appropriate permissions. instrumentations: [getWebAutoInstrumentations({ // Loads custom configuration for xml-http-request instrumentation. '@opentelemetry/instrumentation-xml-http-request': configDefaults, '@opentelemetry/instrumentation-fetch': configDefaults, '@opentelemetry/instrumentation-document-load': configDefaults, })], }); sdk.start(); } catch (e) {return null;} return null; } ``` 2. In your `Layout.jsx|tsx` file, import the component, and add it to your layout code: ```javascript theme={} // components/layout.tsx|jsx import Observability from "@/components/observability"; // ... return ( {children} ); ``` **Recommended file location:** `src/main.ts` Place code early, ideally just above the Vue instantiation, to ensure that your instrumentation is as accurate as possible. Find the line that imports `main.css`, and add the code directly afterwards: ```javascript theme={} import '._assets/main.css' // HONEYCOMB SNIPPET HERE // import { createApp } from 'vue' ``` Make sure that your `package.js` lists version 0.37.0 or greater for `@opentelemetry/auto-instrumentations-web`. Versions prior to this had a conflict with Angular that prevented automatic instrumentation data from working. The best place to put your code to instantiate early is the `src/main.ts` file, which is the [entry point](https://angular.io/guide/file-structure#application-source-files) of your application. If you are using [ember-auto-import](https://github.com/embroider-build/ember-auto-import), then you can import the Honeycomb instrumentation packages directly. The best way to use Honeycomb in an Ember application is through an [Application Initializer](https://guides.emberjs.com/release/applications/initializers/#toc_application-initializers), which ensures that Honeycomb starts up as soon as possible. 1. Use the Ember CLI to generate a new initializer named `observability`: ```shell theme={} ember generate instance-initializer observability ``` You should see a new JS file named `observability.js` in the `app/instance-initializers/` directory. 2. Add Honeycomb configuration code to the `observability.js` file: ```javascript theme={} import { HoneycombWebSDK } from '@honeycombio/opentelemetry-web'; import { getWebAutoInstrumentations } from '@opentelemetry/auto-instrumentations-web'; const configDefaults = { ignoreNetworkEvents: true, // propagateTraceHeaderCorsUrls: [ // /.+/g, // Regex to match your backend URLs. Update to the domains you wish to include. // ] } export function initialize(owner) { const sdk = new HoneycombWebSDK({ // endpoint: "https://api.eu1.honeycomb.io/v1/traces", // Send to EU instance of Honeycomb. Defaults to sending to US instance. debug: true, // Set to false for production environment. apiKey: '[YOUR API KEY HERE]', // Replace with your Honeycomb Ingest API Key. serviceName: '[YOUR APPLICATION NAME HERE]', // Replace with your application name. Honeycomb uses this string to find your dataset when we receive your data. When no matching dataset exists, we create a new one with this name if your API Key has the appropriate permissions. instrumentations: [getWebAutoInstrumentations({ // Loads custom configuration for xml-http-request instrumentation. '@opentelemetry/instrumentation-xml-http-request': configDefaults, '@opentelemetry/instrumentation-fetch': configDefaults, '@opentelemetry/instrumentation-document-load': configDefaults, })], }); sdk.start(); } export default { initialize, }; ``` ### Confirm Data is Sent Start up your application and look in the browser console to see debug information. Once you see traces being sent in the console, you're ready to start using Honeycomb to explore your data. If you encounter an error, visit [Troubleshooting](#troubleshooting) to explore solutions to common issues. ## Refine Your Implementation Once data flows into Honeycomb, you can add custom data about your application to help with investigations. ### Add Application-Specific Resource Attributes To optimize your data collection, we recommend that you add custom attributes that are specific to your application to every span. You can specify extra attributes through the `resourceAttributes` configuration option. This data will be available on every span your instrumentation emits, making it easier to correlate your data to the business information you care about. ```javascript theme={} // index.js or main.js // Other import statements import { HoneycombWebSDK } from '@honeycombio/opentelemetry-web'; import { getWebAutoInstrumentations } from '@opentelemetry/auto-instrumentations-web'; const configDefaults = { ignoreNetworkEvents: true, // propagateTraceHeaderCorsUrls: [ // /.+/g, // Regex to match your backend URLs. Update to the domains you wish to include. // ] } const sdk = new HoneycombWebSDK({ // endpoint: "https://api.eu1.honeycomb.io/v1/traces", // Send to EU instance of Honeycomb. Defaults to sending to US instance. debug: true, // Set to false for production environment. apiKey: '[YOUR API KEY HERE]', // Replace with your Honeycomb Ingest API Key. serviceName: '[YOUR APPLICATION NAME HERE]', // Replace with your application name. Honeycomb uses this string to find your dataset when we receive your data. When no matching dataset exists, we create a new one with this name if your API Key has the appropriate permissions. instrumentations: [getWebAutoInstrumentations({ // Loads custom configuration for xml-http-request instrumentation. '@opentelemetry/instrumentation-xml-http-request': configDefaults, '@opentelemetry/instrumentation-fetch': configDefaults, '@opentelemetry/instrumentation-document-load': configDefaults, })], resourceAttributes: { // Data in this object is applied to every trace emitted. "user.id": user.id, // Specific to your app. "user.role": user.role, // Specific to your app. }, }); sdk.start(); // Application instantiation code ``` ### Connect Browser Traces with Backend Traces To trace a request all the way from your browser through your distributed system, connect your frontend request traces to your backend traces. If your application's backend and frontend are served from the same domain, you can connect traces automatically by using either `instrumentation-fetch` or `instrumentation-xml-http-request` automatic instrumentation. If your browser application calls a separate API endpoint, then you must specify the requests to which you want the trace context header added in order to connect the traces. To do this with the Honeycomb web instrumentation and send traces, uncomment the `propagateTraceHeaderCorsUrls` array and add regex to include all target domains. This method allows you to propagate to your backend services without leaking trace IDs to third-party services. ```javascript theme={} const configDefaults = { ignoreNetworkEvents: true, propagateTraceHeaderCorsUrls: [ /.+/g, // Regex to match your backend URLs. Update to the domains you wish to include. ] } ``` ### Send Data to an OpenTelemetry Collector In production, we recommend that you run an [OpenTelemetry Collector](/send-data/opentelemetry/collector/#browser-telemetry) and send traces to it from your browser application, which will allow you to control your Honeycomb API key and any data transformation. Your OpenTelemetry Collector can then send the traces on to Honeycomb using your API key that you store in the Collector's configuration. This example configuration of the Honeycomb Web Instrumentation package sends traces to your Collector: ```js theme={} const sdk = new HoneycombWebSDK({ debug: true, // Set to false for production environment. endpoint: "http(s)://", skipOptionsValidation: true // Because we are not including apiKey serviceName: '[YOUR APPLICATION NAME HERE]', // Replace with your application name. Honeycomb uses this string to find your dataset when we receive your data. When no matching dataset exists, we create a new one with this name if your API Key has the appropriate permissions. instrumentations: [getWebAutoInstrumentations({ // Loads custom configuration for xml-http-request instrumentation. '@opentelemetry/instrumentation-xml-http-request': configDefaults, '@opentelemetry/instrumentation-fetch': configDefaults, '@opentelemetry/instrumentation-document-load': configDefaults, })], }); sdk.start(); ``` ## Troubleshooting Running into issues? Here are some common problems and ways to fix them. Still stuck? Check out our [Support Knowledge Base](/troubleshoot/customer-support/) or post a question in our [Pollinators Community](/troubleshoot/community/). ### Dataset Not Appearing in Honeycomb We use the `apiKey` variable to send your data to Honeycomb. Be sure you have replaced the placeholder value for it with your Honeycomb Ingest API Key and that your API key permissions include "Can create datasets". If Honeycomb is successfully instantiating, but your API key is not included, you should see output similar to the following in your browser console: Screenshot of Honeycomb UI on the API Keys page, showing the heading Ingest Keys and the button named 'Create Ingest Key' ### Dataset in Honeycomb has Unexpected Name We use the `serviceName` variable to name your dataset in Honeycomb. Be sure you have replaced the placeholder value for it with a name that you will find useful. ### "Navigator is undefined" Error in Next.js Application If a "navigator is undefined" error appears when you attempt to start your local server while following Next.js instructions, it means the instrumentation is being run in a server-side rendering path. To fix, try the first suggested solution before implementing the second solution: 1. **Add "use client" directive**: At the top of the file where you instantiate Honeycomb's web instrumentation, you can add the ["use client" directive](https://react.dev/reference/react/use-client), which tells React to only execute the file in a client environment. If that solution does not resolve the error, try step 2. 2. **Wrap the function in a try/catch block**: If you're using the client directive and still seeing an error, you can catch the error and avoid instantiation in server-side environments. By adding this, you ensure your app starts up even if the code is executed in a server-side environment. Refer to the example below: ```javascript theme={} try { const sdk = new HoneycombWebSDK({ // endpoint: "https://api.eu1.honeycomb.io/v1/traces", // Send to EU instance of Honeycomb. Defaults to sending to US instance. debug: true, // Set to false for production environment. apiKey: '[YOUR API KEY HERE]', // Replace with your Honeycomb Ingest API Key. serviceName: '[YOUR APPLICATION NAME HERE]', // Replace with your application name. Honeycomb uses this string to find your dataset when we receive your data. When no matching dataset exists, we create a new one with this name if your API Key has the appropriate permissions. instrumentations: [getWebAutoInstrumentations({ // Loads custom configuration for xml-http-request instrumentation. '@opentelemetry/instrumentation-xml-http-request': configDefaults, '@opentelemetry/instrumentation-fetch': configDefaults, '@opentelemetry/instrumentation-document-load': configDefaults, })], }); } catch (e) {} ``` ### Instrumentation is too Noisy If there is an unexpected volume of events, we recommend disabling some auto-instrumentation. The User Interaction instrumentation, specifically, can be quite noisy. Disabling specific instrumentation is outlined in the example below: ```javascript theme={} // index.js or main.js // other import statements... import { HoneycombWebSDK } from '@honeycombio/opentelemetry-web'; import { getWebAutoInstrumentations } from '@opentelemetry/auto-instrumentations-web'; const sdk = new HoneycombWebSDK({ // ... rest of the config instrumentations: [getWebAutoInstrumentations({ '@opentelemetry/instrumentation-xml-http-request': { enabled: false }, '@opentelemetry/instrumentation-fetch': { enabled: false }, '@opentelemetry/instrumentation-document-load': { enabled: false }, '@opentelemetry/instrumentation-user-interaction': { enabled: false } })], }); sdk.start(); // Application instantiation code ``` # Get Started with Embrace & Honeycomb Source: https://docs.honeycomb.io/get-started/start-building/embrace Forward metrics and network spans from Embrace to Honeycomb. If your web or mobile applications use [Embrace](https://embrace.io/), you can forward metrics and network spans to Honeycomb. Sending your Embrace telemetry to Honeycomb lets you: * Analyze your mobile and web client telemetry and backend traces in one place * Go from a backend trace in Honeycomb to the originating Embrace session (`emb.dashboard_session`) * Set up [trigger alerts](/notify/triggers/) or [SLOs](/notify/slos/) for web/mobile performance * Monitor frontend sessions and performance by [creating a new board with the Embrace board template](#create-a-board-from-the-embrace-dashboard-template) ## Before you begin Before starting, confirm you have: * A Honeycomb environment with at least one backend service sending OpenTelemetry traces * An Embrace account on an Enterprise plan * A mobile or web application using an Embrace SDK that supports [network spans forwarding](https://embrace.io/docs/data-forwarding/network-spans-forwarding/#sdk-version-requirements) If you haven't added Embrace to your application, visit [Embrace's documentation](https://embrace.io/docs/) for guides on how to install and set up the Embrace SDK for your platform: * [Android](https://embrace.io/docs/android/integration/) * [iOS](https://embrace.io/docs/ios/6x/getting-started/installation/) * [Web](https://embrace.io/docs/web/getting-started/basic-setup/) * [React Native](https://embrace.io/docs/react-native/integration/) * [Flutter](https://embrace.io/docs/flutter/integration/) ## Set up network spans forwarding [Network spans forwarding](https://embrace.io/docs/data-forwarding/network-spans-forwarding/) stitches Embrace client spans into your backend traces in Honeycomb. Network spans forwarded from Embrace will have a `emb.dashboard_session` link. This link connects a Honeycomb trace to the originating Embrace session. Network spans forwarding requires you to specify which apps and domains to forward spans from. Configure this in the Embrace dashboard: 1. Navigate to **Settings** > **Integrations**. 2. Select the **Network Spans Forwarding** view. 3. Select **Honeycomb** as the data destination. 4. Select the apps you want to forward spans from. 5. Add the domain names of the backend services you want to trace. Embrace forwards spans only for configured, internet-reachable domains. You can add domains as exact matches or use regex patterns for more flexible matching. The Embrace SDK uses a Honeycomb Ingest Key to forward spans to your environment. If you already have an Ingest Key for this environment, you can use it here. To learn how to create a new Ingest Key, visit [Manage Environment API Keys](/configure/environments/manage-api-keys). When creating the key, enable **Create datasets**, so Embrace can create a dataset for the forwarded spans. You will use this key in the next step to configure the SDK exporter. The exporter tells the Embrace SDK where to send spans. Add a Honeycomb OTLP exporter to your Embrace SDK configuration, using your Ingest Key as the `x-honeycomb-team` header. Here is an example using the Embrace Web SDK: ```javascript highlight={6-10} theme={} import { EmbraceWebSDK } from '@embrace-io/web-sdk'; const embrace = new EmbraceWebSDK({ appId: "YOUR_EMBRACE_APP_ID", appVersion: "YOUR_APP_VERSION", exporters: [{ type: 'otlp', endpoint: 'https://api.honeycomb.io/v1/traces', headers: { 'x-honeycomb-team': YOUR_HONEYCOMB_INGEST_KEY } }] }); if (embrace) { console.log("Successfully initialized the Embrace SDK"); embrace.start(); } else { console.log("Failed to initialize the Embrace SDK"); } ``` The SDK automatically attaches a W3C `traceparent` header to every network request your app makes and forwards the resulting spans to Honeycomb with `emb.*` attributes included. ## Set up metrics forwarding [Metrics forwarding](https://embrace.io/docs/metrics-forwarding/) sends session data from Embrace to Honeycomb, so you can query and alert on user experience signals alongside your backend traces. Embrace uses a Honeycomb Configuration Key to authenticate when forwarding metrics to your environment. To learn how to create one, visit [Manage Environment API Keys](/configure/environments/manage-api-keys). Adding Honeycomb as a Data Destination tells Embrace where to send session metrics. In the Embrace dashboard: 1. Navigate to **Settings** > **Integrations**. 2. Select the **Data Destinations** view. 3. Select **Add Data Destination**. 4. Choose **Honeycomb** and enter your Honeycomb Configuration Key. Once configured, Embrace forwards metrics to Honeycomb where you can query them alongside your trace data. To learn which metrics are forwarded, visit [Embrace Integration Overview: Session Metrics](/integrations/embrace/overview#session-metrics). ## Verify the integration Verification confirms that both flows are working: spans appearing in the trace view means the SDK exporter is forwarding correctly, and metrics appearing in Honeycomb means the Data Destinations configuration is correct. ### Network spans Spans appear in Honeycomb after the SDK exporter is configured and application traffic flows through a configured domain. 1. In Honeycomb, open the dataset that corresponds to your backend service. 2. Run a query and filter for `emb.app_id` exists. 3. Select a result row and open the trace view. 4. Confirm that the trace includes a span labeled **forwarded via Embrace** at the top of the waterfall, with `emb.*` attributes visible in the span detail panel. 5. Confirm that `emb.dashboard_session` appears as a clickable link in the span detail panel. If you don't see spans after 15 minutes, refer to the [troubleshooting section](https://embrace.io/docs/data-forwarding/network-spans-forwarding/#troubleshooting) in Embrace's network spans forwarding documentation. ### Metrics Metrics should appear in Honeycomb within a few minutes of adding it as a Data Destination. 1. In Honeycomb, open the dataset that corresponds to your Embrace metrics. 2. Run a query and filter for `session.count` exists. 3. Confirm that data is appearing. ## Create a Board from the Embrace Dashboard template Once you've verified your Embrace telemetry is showing up in Honeycomb, create a Board so you can see your Embrace stuff at a glance. 1. Select **Boards** () from the navigation menu. 2. Go to the **Templates** view, or select **Create Boards** and **From Template**. 3. Choose the **Embrace Dashboard** template. In the template preview, review the data displayed in the query panels. If some queries aren't displaying correctly, you may need to map required fields to your data: 1. Go to the **Setup** view. 2. Find any queries marked **Unable to display**. 3. In the **Required fields** column, select the target field, then choose the appropriate replacement field. Your field mapping applies to all template queries using that target field. To revert to the original template field, select the remove icon () next to the replacement field name. 4. Repeat this process for any additional fields or queries. 5. Select **Use Template**. Your new Embrace Board appears on the Boards page. Any queries marked as unable to display during creation are not included. ## Next steps Now that your Embrace integration is configured, put it to work: * [Investigate backend latency](/integrations/embrace/use-cases/investigate-backend-latency) * [Diagnose mobile ANRs and hangs](/integrations/embrace/use-cases/diagnose-mobile-anrs) * [Investigate with Embrace and Honeycomb MCP](/integrations/embrace/use-cases/investigate-with-mcp) # Example Applications Source: https://docs.honeycomb.io/get-started/start-building/example-applications Try pre-instrumented example applications to get hands-on with Honeycomb tracing before adding instrumentation to your own code. These example applications are pre-instrumented with tracing data. Use them to quickly learn about Honeycomb. [Create a free Honeycomb account](https://ui.honeycomb.io/signup) to try these applications with Honeycomb. ## Honeycomb Academy Example Applications Each example application, listed below, is for use in [Honeycomb Academy](https://academy.honeycomb.io/app) lab activities. Their GitHub repository contains instructions on how to get started. Enter your [Honeycomb API Key](/configure/environments/manage-api-keys/) within the example application and run the example application to send telemetry data to Honeycomb. * Browser - [GitHub](https://github.com/honeycombio/academy-instrumentation-browser) * Go - [GitHub](https://github.com/honeycombio/academy-instrumentation-go) * Java - [GitHub](https://github.com/honeycombio/academy-instrumentation-java) * Node.js - [GitHub](https://github.com/honeycombio/academy-instrumentation-nodejs) * Python - [GitHub](https://github.com/honeycombio/academy-instrumentation-python) * Ruby - [GitHub](https://github.com/honeycombio/academy-instrumentation-ruby) If you did not find your language as an example application, let us know in the Docs Feedback Form below. We want to know what languages you would like to see supported! # Get Started with Honeycomb for Kubernetes Source: https://docs.honeycomb.io/get-started/start-building/kubernetes Add observability to your Kubernetes cluster and send telemetry to Honeycomb using OpenTelemetry, the Collector, or the OpenTelemetry Operator. Use OpenTelemetry to collect Kubernetes resource and status metrics from nodes, pods, containers, and volumes. This data answers questions like: * Which pods are using the most CPU? * How do resource limits compare to container resource use? * What do system metrics look like at the node level? * Why are pods failing to start? Adding telemetry to Kubernetes and then analyzing with Honeycomb provides a flexible way to aggregate, structure, and enrich events from applications running on Kubernetes. This data answers questions like: * How did response time change after a canary deployment? * How does application performance vary with container resource limits? * Are application errors happening on specific nodes, or across the fleet? ## Getting Started: Create Your Telemetry Pipeline Do you have 10 minutes? Then you've come to the right place. Use our Quick Start to create a telemetry pipeline, which will prepare you to instrument your application code. Use Helm to deploy OpenTelemetry Collectors that set up a telemetry pipeline to send Kubernetes metrics and events from your cluster to Honeycomb. ## Add Low-Code Automatic Instrumentation to Your Applications Once you have a telemetry pipeline in place, add automatic instrumentation to your applications. If you have already used OpenTelemetry to instrument your applications to send data to Honeycomb, you can skip this step and jump straight to [configuring OpenTelemetry to forward telemetry data to your Collectors](/send-data/kubernetes/opentelemetry/collect-instrumented-code/). Set up the OpenTelemetry Operator for Kubernetes to add automatic instrumentation to your applications--using very little code. ## Getting Help To ask questions and learn more, join our [Pollinators Community Slack](/troubleshoot/community/#join-pollinators-community-slack). # Sandbox Source: https://docs.honeycomb.io/get-started/start-building/sandbox Try Honeycomb without sending your own data. The Sandbox gives you a pre-loaded environment to run queries and get familiar with the Honeycomb UI. # Supported Integrations Source: https://docs.honeycomb.io/integrations Connect Honeycomb to your existing infrastructure and tooling. Find integrations for AWS, HashiCorp, Prometheus, log forwarders, service meshes, build pipelines, and more. ## Overview Honeycomb natively supports any system that can send data using OpenTelemetry. This section covers integrations with dedicated Honeycomb documentation. For a full list of Honeycomb integrations, including third-party integrations, check out the Honeycomb Integrations directory. For community-contributed integrations, visit our [Community Contribution repository on GitHub](https://github.com/honeycombio/third-party-contrib/). ## CI/CD CircleCI logo

CircleCI

Generate distributed traces from CircleCI pipelines using Honeycomb's Buildevents tool.
GitHub Actions logo

GitHub Actions

Generate distributed traces from GitHub Actions workflows using Honeycomb's Buildevents tool.
GitLab logo

GitLab CI

Generate distributed traces from GitLab CI pipelines using Honeycomb's Buildevents tool.
Buildkite logo

Buildkite

Generate distributed traces from Buildkite pipelines using Honeycomb's Buildevents tool.
Jenkins logo

Jenkins X

Generate distributed traces from Jenkins X pipelines using Honeycomb's Buildevents tool.
Google DevOps Category logo

Google Cloud Build

Generate distributed traces from Google Cloud Build pipelines using Honeycomb's Buildevents tool.
Bitbucket logo

Bitbucket Pipelines

Generate distributed traces from Bitbucket Pipelines using Honeycomb's Buildevents tool.
Travis CI logo

Travis CI

Generate distributed traces from Travis CI pipelines using Honeycomb's Buildevents tool.
GitHub logo

GitHub Deployment Protection

Gate GitHub deployments based on Honeycomb SLO health using GitHub Deployment Protection Rules.
*** ## Cloud platforms AWS Lambda logo

AWS Lambda

Send telemetry from AWS Lambda functions to Honeycomb using OpenTelemetry or the Honeycomb Lambda extension.
AWS Cloudwatch logo

AWS Cloudwatch

Stream CloudWatch metrics to Honeycomb using AWS Kinesis Data Firehose.
Microsoft logo

Azure

Send telemetry from Azure to Honeycomb using OpenTelemetry.
Google Cloud logo

Google Cloud

Send telemetry from Google Cloud to Honeycomb.
*** ## Developer tools Claude logo

Claude

Connect Claude to your Honeycomb observability data using the Honeycomb MCP server.
Cursor logo

Cursor

Connect Cursor to your Honeycomb observability data using the Honeycomb MCP server.
Visual Studio Code logo

Visual Studio Code

Connect VS Code to your Honeycomb observability data using the Honeycomb MCP server.
Amazon Q logo

Amazon Q

Give Amazon Q built-in observability skills for Honeycomb queries and production debugging.
GitHub Copilot logo

GitHub Copilot

Give GitHub Copilot built-in observability skills for Honeycomb queries and production debugging.
*** ## Web & mobile Embrace logo

Embrace

Connect Honeycomb and Embrace to correlate backend traces with mobile and web user sessions. Partner
*** ## Infrastructure Kubernetes logo

Kubernetes

Send traces, metrics, and logs from Kubernetes clusters to Honeycomb using OpenTelemetry.
*** ## Service meshes & API gateways Istio logo

Istio

Send distributed traces from Istio service mesh to Honeycomb using the OpenTelemetry Collector.
Kong logo

Kong

Send distributed traces from Kong API Gateway to Honeycomb using the OpenTelemetry Collector.
Ambassador logo

Ambassador

Send distributed traces from Ambassador API Gateway to Honeycomb using the OpenTelemetry Collector.
*** ## Infrastructure as Code HashiCorp Terraform logo

HashiCorp Terraform

Manage Honeycomb environments, datasets, API keys, triggers, and SLOs as code using the Honeycomb Terraform provider.
*** ## Log sources Nginx logo

Nginx

Parse and send Nginx access logs to Honeycomb for high-cardinality querying.
MySQL logo

MySQL

Parse and send MySQL slow query logs to Honeycomb for database performance analysis.
PostgreSQL logo

PostgreSQL

Parse and send PostgreSQL logs to Honeycomb for database performance analysis.
JSON logo

JSON logs

Ingest and backfill JSON log files into Honeycomb.
*** ## Log shippers Fastly logo

Fastly

Stream logs from Fastly CDN to Honeycomb for visibility into content delivery behavior.
Fluentd logo

Fluentd

Forward structured logs from Fluentd to Honeycomb using the Fluentd output plugin.
Logstash logo

Logstash

Send logs from Logstash to Honeycomb using the Logstash output plugin.
*** ## Metrics sources Prometheus logo

Prometheus

Scrape Prometheus metrics using the OpenTelemetry Collector and send them to Honeycomb.
HashiCorp Consul logo

HashiCorp Consul

Send HashiCorp Consul cluster metrics to Honeycomb using the OpenTelemetry Collector.
HashiCorp Nomad logo

HashiCorp Nomad

Send HashiCorp Nomad workload metrics to Honeycomb using the OpenTelemetry Collector.
HashiCorp Vault logo

HashiCorp Vault

Send HashiCorp Vault server metrics to Honeycomb using the OpenTelemetry Collector.
Anthropic logo

Anthropic

Monitor Anthropic API token consumption, feature usage, and cost attribution using a custom OpenTelemetry Collector.
*** ## Network AWS PrivateLink logo

AWS PrivateLink

Send telemetry to Honeycomb over AWS PrivateLink without traversing the public internet.
*** ## Notification channels PagerDuty logo

PagerDuty

Send Honeycomb trigger and SLO burn alerts to PagerDuty.
Slack logo

Slack

Send Honeycomb trigger and SLO burn alerts to Slack channels.
Microsoft Teams logo

Microsoft Teams

Send Honeycomb trigger and SLO burn alerts to Microsoft Teams.
Webhooks logo

Webhooks

Send Honeycomb trigger and SLO alerts to any endpoint using configurable webhooks.
# Agent Skills for AI Coding Assistants Source: https://docs.honeycomb.io/integrations/agent-skills Give your AI coding assistants deep knowledge of observability, OpenTelemetry instrumentation, production debugging, and Honeycomb features. [Honeycomb Agent Skills](https://github.com/honeycombio/agent-skill) is a collection of skills, agents, and hooks for enhancing AI-assisted code workflows. These skills provide OpenTelemetry best practices, Honeycomb feature usage, production issue debugging, and more. ## Available skills Installing the Honeycomb plugin gives your AI assistant eight skills for observability workflows: * **query-patterns**: Build effective Honeycomb queries with patterns for column selection, filtering, and aggregation. * **production-investigation**: Debug latency spikes, error rates, and other production anomalies with step-by-step reasoning. * **slos-and-triggers**: Define and manage SLOs and alert triggers in Honeycomb. * **otel-instrumentation**: Instrument applications with OpenTelemetry, including span creation, attribute naming, and context propagation. * **otel-migration**: How to migrate proprietary or legacy instrumentation to OpenTelemetry. * **beeline-migration**: Guidlines for migrating from Honeycomb Beelines to OpenTelemetry SDKs. * **observability-fundamentals**: Core concepts around distributed tracing, wide events, and production-grade observability. * **create-honeycomb-board**: Create Honeycomb boards to capture investigations and share insights. ## Available agents Two autonomous agents are included for more complex tasks: * **honeycomb-investigator**: Autonomously investigates production issues by querying Honeycomb data, identifying patterns, and summarizing findings. * **instrumentation-advisor**: Analyzes your codebase to find instrumentation gaps and suggest improvements based on OpenTelemetry best practices. ## Additional capabilities * **Column validation hooks**: Prevent queries with invalid or mistyped column names before they are sent to Honeycomb. * **Schema caching**: Reduce repeated lookups by caching dataset column schemas locally during a session. * [Honeycomb MCP](/integrations/mcp/) integration: Query traces, check SLOs and triggers, run BubbleUp analysis, and create boards. ## Install the plugin The following tools support direct plugin installation, which sets up all skills, agents, hooks, and MCP configuration. ### Claude Code ```bash theme={} claude plugin marketplace add honeycombio/agent-skill claude plugin install honeycomb ``` After installation, run `/honeycomb-setup` to connect the Honeycomb MCP server and complete authentication. ### Cursor Add as a remote rule in the Cursor settings: 1. Open **Settings** > **Rules** > **Project Rules**. 2. Select **Add Rule** > **Remote Rule**. 3. Enter the URL: `https://github.com/honeycombio/agent-skill` ### Augment (Auggie CLI) ```bash theme={} auggie plugin marketplace add honeycombio/agent-skill auggie plugin install honeycomb ``` ### GitHub Copilot CLI ```bash theme={} copilot plugin install honeycombio/agent-skill:honeycomb ``` ### Other tools Many AI coding tools support skills and MCP servers through their own configuration. To use Honeycomb with these tools, you'll generally need to: 1. **Add skills**: Copy the skill files from the [agent-skill repository](https://github.com/honeycombio/agent-skill) into the skills directory your tool expects. 2. **Configure the MCP server**: Point your tool at the Honeycomb MCP endpoint — `https://mcp.honeycomb.io/mcp` (or `https://mcp.eu1.honeycomb.io/mcp` for EU). Refer to your tool's documentation for specifics: | Tool | Skills Docs | MCP Docs | | --------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------- | | VS Code with GitHub Copilot | [Agent Skills](https://code.visualstudio.com/docs/copilot/customization/agent-skills), [Agent Plugins](https://code.visualstudio.com/docs/copilot/customization/agent-plugins) | [MCP Servers](https://code.visualstudio.com/docs/copilot/chat/mcp-servers) | | OpenAI Codex CLI | [Skills](https://developers.openai.com/codex/skills) | [Configuration](https://developers.openai.com/codex/config-reference) | | Cline | [Rules](https://docs.cline.bot/features/cline-rules) | [MCP Servers](https://docs.cline.bot/mcp/mcp-overview) | | Windsurf | — | [MCP Configuration](https://docs.windsurf.com/windsurf/mcp) | | Amazon Q Developer | — | [MCP Servers](https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/mcp.html) | For tools that only support MCP (not skills), your agent will have access to Honeycomb query tools but won't have the built-in observability reasoning and instrumentation guidance that skills provide. See the [Honeycomb MCP configuration guide](/integrations/mcp/configuration-guide/) for more details on connecting to the MCP server. Don't see your tool listed? [Open an issue on GitHub](https://github.com/honeycombio/agent-skill/issues) to request support. ## Connecting to Honeycomb ### OAuth (recommended) OAuth is the recommended authentication method. It uses a browser-based flow and does not require you to manage API keys. When you first invoke a Honeycomb MCP tool, your agent will open a browser window to complete the authorization flow. Pick your Honeycomb environment and grant the required permissions. Once authorized, your agent can access Honeycomb data for the rest of the session. ### API Key (headless environments) For autonomous or unattended agents that cannot complete an interactive OAuth flow, use an API key. 1. Generate a Management API key in Honeycomb under **Account** > **Team Settings** > **API Keys**. 2. Grant the **Model Context Protocol** and **Environments** scopes with **Read** permissions (and **Write** if you want the `create_board` tool). 3. Format the key as `KEY_ID:SECRET_KEY` and pass it as a Bearer token in the `Authorization` header. See the [configuration guide](/integrations/mcp/configuration-guide/#setting-up-an-api-key) for a full example configuration. ### EU region If your Honeycomb team is on the EU instance, use `https://mcp.eu1.honeycomb.io/mcp` in place of the US endpoint in all configurations above. ## Next steps * [Getting Started with Honeycomb Using MCP](https://academy.honeycomb.io/app/courses/13ad6a1c-2cd9-46d3-b6c3-c7dc45b5bf4f) * [Connect your AI agent to Honeycomb MCP](/integrations/mcp/configuration-guide/) * Browse the [honeycomb/agent-skill repo](https://github.com/honeycombio/agent-skill), open issues, or contribute new skills and improvements. # Connect to Honeycomb with AWS PrivateLink Source: https://docs.honeycomb.io/integrations/aws-privatelink Send telemetry to Honeycomb over a private AWS network connection without exposing traffic to the public internet using AWS PrivateLink. Ent This feature is available as part of the [Honeycomb Enterprise plan](https://www.honeycomb.io/pricing/). [AWS PrivateLink](https://aws.amazon.com/privatelink/) lets you create a private connection to Honeycomb's API over AWS networks. Comparison of the networking with and without PrivateLink. With PrivateLink, network traffic stays in AWS, and without, it goes over the public internet. This has the following advantages: * Limits API traffic over the internet as requests to our API server are transparently handled within AWS networks * If your infrastructure relies on outbound firewalls, you can manage access to the Honeycomb API with security groups (or rules on your firewall appliance) * Reduced costs for high volume traffic with [other services on PrivateLink](https://docs.aws.amazon.com/vpc/latest/privatelink/aws-services-privatelink-support). Contact your Honeycomb account team for details. ## Before You Begin Honeycomb must grant access to each AWS account that requires access to the Honeycomb API via AWS PrivateLink. Contact your Honeycomb account team for details. Honeycomb offers AWS PrivateLink to our US instance from the `us-east-1` region and to our EU instance from the `eu-west-1` region. VPCs within each region may access it directly, while outside VPCs can use [VPC Peering](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-peering#vpc-peer-region-example). Honeycomb also offers [cross-region endpoint support](#cross-region-endpoint-support). ## Configuration Using the AWS Console These instructions configure AWS PrivateLink via the AWS Console. Configuration of AWS PrivateLink through infrastructure-as-code tools like [Terraform](https://www.terraform.io/) or [CloudFormation](https://aws.amazon.com/cloudformation/) is recommended but not shown. Refer to the [Terraform example below](#example-configuration-using-terraform). 1. Visit the [Amazon VPC console](https://console.aws.amazon.com/vpc/) in the appropriate region: 1. US instance: `us-east-1` 2. EU instance: `eu-west-1` 2. From the left navigation, select **Endpoints** and choose **Create endpoint**. Display of the AWS VPC console with the Endpoint section open and an arrow pointing at Create Endpoint. 3. For **Service category**, choose **PrivateLink Ready partner services**. 4. For the **Service name**, enter the name of the service: 1. US instance: `com.amazonaws.vpce.us-east-1.vpce-svc-0878e9afcbb4c4333` 2. EU instance: `com.amazonaws.vpce.eu-west-1.vpce-svc-077ead63dd7ebe330` 5. If you are establishing the endpoint from a different region than the Honeycomb instance it will run in, check the **Enable Cross Region endpoint** box, and specify the right region 1. US instance: `us-east-1` 2. EU instance: `eu-west-1` 6. Select **Validate**. Display of the Endpoint Configuration screen with the service category and service name filled in. If the service fails to validate, reach out to your Honeycomb account team. Endpoint validation with the message: Service name could not be verified. 7. From the **Select a VPC** list, select the VPCs that contain the services sending traffic to Honeycomb. 8. From the **Additional settings** dropdown, ensure that **Enable DNS name** is enabled. [This requires that "Enable DNS hostnames" and "Enable DNS support" are enabled for this VPC](https://docs.aws.amazon.com/vpc/latest/privatelink/concepts). 9. Select one subnet per Availability Zone that the PrivateLink Endpoint will be created in. This subnet must contain your services or the ability to route to all subnets where your services are run. 10. Select a security group that allows inbound access on port `443` from your VPC's network block, such as `10.0.0.0/8`. If you do not see a security group, you may need to create one. 11. Choose **Create endpoint**. The Endpoint console shows a "Pending" status until it is "Available." Once available, your infrastructure transparently sends data through the connection. Refer to the AWS documentation on [Interface Endpoints](https://docs.aws.amazon.com/vpc/latest/privatelink/interface-endpoints) for more details about endpoint configuration. ## Cross-Region Endpoint Support Cross-Region endpoints are supported in the following regions: * `af-south-1` * `ap-east-1` * `ap-northeast-1` * `ap-northeast-2` * `ap-northeast-3` * `ap-south-1` * `ap-south-2` * `ap-southeast-1` * `ap-southeast-2` * `ap-southeast-3` * `ap-southeast-4` * `ca-central-1` * `eu-central-1` * `eu-central-2` * `eu-north-1` * `eu-south-1` * `eu-south-2` * `eu-west-1` * `eu-west-2` * `eu-west-3` * `me-central-1` * `me-south-1` * `sa-east-1` * `us-east-1` * `us-east-2` * `us-west-1` * `us-west-2` ## Example Configuration Using Terraform ```terraform theme={} resource "aws_vpc_endpoint" "honeycomb" { vpc_id = aws_vpc.main.id vpc_endpoint_type = "Interface" service_name = "com.amazonaws.vpce.us-east-1.vpce-svc-0878e9afcbb4c4333" service_region = "us-east-1" # only specify if going cross region from yours subnet_ids = data.aws_subnets.private.ids security_group_ids = [ aws_security_group.honeycomb_private_endpoint.id, ] private_dns_enabled = true } data "aws_subnets" "private" { filter { name = "vpc-id" values = [aws_vpc.main.id] } } resource "aws_security_group" "honeycomb_private_endpoint" { name = "honeycomb_private_endpoint" description = "Traffic to Honeycomb endpoint" vpc_id = aws_vpc.main.id ingress { description = "TLS from VPC" from_port = 443 to_port = 443 protocol = "tcp" cidr_blocks = [aws_vpc.main.cidr_block] ipv6_cidr_blocks = [aws_vpc.main.ipv6_cidr_block] } egress { from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] ipv6_cidr_blocks = ["::/0"] } tags = { Name = "honeycomb_private_endpoint" } } ``` ## Monitoring the PrivateLink Endpoint AWS captures metrics for each VPC endpoint. These metrics are accessible through the AWS Console and published to [CloudWatch](https://docs.aws.amazon.com/vpc/latest/privatelink/privatelink-cloudwatch-metrics). Learn how to [send AWS CloudWatch metrics to Honeycomb](/integrations/metrics/aws-cloudwatch/). From the AWS Console: 1. Visit the [Amazon VPC console](https://console.aws.amazon.com/vpc/) in the appropriate region: 1. US instance: `us-east-1` 2. EU instance: `eu-west-1` 2. From the left navigation, select **Endpoints** and choose the endpoint ID. 3. Select the **Monitoring** tab. # Generate Traces from Build Pipelines Source: https://docs.honeycomb.io/integrations/build-pipelines Generate distributed traces from your CI/CD build pipelines using Honeycomb's Buildevents tool and analyze build performance in Honeycomb. Use Honeycomb to instrument your CI/CD build pipelines and generate distributed traces that give you visibility into build performance, test duration, and pipeline failures. Honeycomb's [`buildevents`](https://github.com/honeycombio/buildevents) generates distributed traces from work in a build pipeline. It is installed during the setup phase and invoked as part of each step to visualize the build as a trace in Honeycomb. The resulting trace represents the entire build. It includes spans for each section and subsection of the build, representing groups of actual commands that are run. The duration of each span is how long that stage or specific command took to run and includes whether or not the command succeeded. The following is an example trace that shows a build that ran on CircleCI. It goes through starting the trace to building services to running tests. Each span has a custom and standard context representing each part of the build pipeline. CircleCI Tracing View To use your pipeline telemetry to gate deployments, use Buildevents traces as the data source for [GitHub Deployment Protection Rules](/integrations/github-deployment-protection-rules/). ## Before You Begin Determine if your build environment is supported by `buildevents`: * Travis CI * CircleCI * GitLab CI * Buildkite * Jenkins X * Google Cloud Build * GitHub Actions * Bitbucket Pipelines ## Installation Using `buildevents` requires the following: * Installation of the [`buildevents` binary](https://github.com/honeycombio/buildevents) within the build environment. * Configuration of the `BUILDEVENT_APIKEY` and `BUILDEVENT_DATASET` environment variables. For more information, refer to the [complete environment variables list](https://github.com/honeycombio/buildevents#environment-variables). Use the step-by-step guides below for **CircleCI**, **GitHub Actions**, or **GitLab**. Each guide provides a hands-on walkthrough on how to use and configure the `buildevents` for a specific CI/CD build environment against a sample app with a predefined build pipeline. Each guide shows how to: * Use `buildevents` for the respective build * Iteratively construct a trace by adding more incremental visibility to each step * Use the Honeycomb UI to visualize and debug your build pipeline * Avoid common pitfalls when working with the CI tool and Honeycomb's `buildevents` If using a provider **not** listed in a guide above, you can still use the `buildevents` binary by following the steps described in the [`buildevents` repository](https://github.com/honeycombio/buildevents). ## Generate Queries and Boards for CI/CD Honeycomb provides a Terraform module, which automatically generates a set of [queries](/investigate/query/build/) and [boards](/observe/boards/) within Honeycomb for CI/CD integrations. Use this "Honeycomb Buildevents Starter Pack" as a starting point when exploring your pipeline data. To install, refer to the [Terraform module README](https://registry.terraform.io/modules/honeycombio/buildevents-starter-pack/honeycombio/latest). Installation requires a minimal configuration added to a `.tf` file and setting an API key environment variable. # Community Contributions Source: https://docs.honeycomb.io/integrations/community-contributions # Connect Honeycomb and Embrace Source: https://docs.honeycomb.io/integrations/embrace/overview Connect Honeycomb and Embrace to correlate backend traces with mobile and web user sessions. ## Overview Embrace is a mobile and web observability platform that captures user session data, including network requests, ANRs, hangs, crashes, Core Web Vitals, and rage taps. Honeycomb and Embrace together give your engineering teams complete visibility across the full request path, from the user's device to your backend services and back. The integration connects the two using standard OpenTelemetry trace context, so the full request path appears in a single Honeycomb trace view. When something goes wrong, you can move between backend traces and user session context. ## How it works The integration uses two mechanisms to connect Honeycomb and Embrace: network spans forwarding and W3C trace context propagation. ### Network spans forwarding Embrace automatically attaches a W3C `traceparent` header to every network request your app makes. The Embrace SDK forwards a span representing that network call directly to Honeycomb via OTLP, using an exporter configured in your SDK setup. ```mermaid actions={false} theme={} flowchart LR subgraph Client["Client"] mobile["Mobile App"] web["Web App"] end subgraph SDK["Embrace SDK"] embrace["Embrace"] otel["OpenTelemetry"] embrace --- otel end subgraph Platform["Embrace Platform"] dashboard["Embrace Dashboard"] end honeycomb["Honeycomb"] mobile --> SDK web --> SDK SDK -->|"Frontend\nTelemetry\n(OTLP)"| Platform SDK -->|"Network\nSpans\n(OTLP)"| honeycomb Platform -->|"Metrics\n(OTLP)"| honeycomb ``` Each span carries both standard OpenTelemetry attributes and Embrace-specific attributes prefixed with `emb.`. Your backend services pick up the incoming `traceparent` header and continue the trace using their existing OpenTelemetry instrumentation. Because the client span and the backend spans share the same trace ID, Honeycomb stitches them together automatically in the trace view. The forwarded client span appears at the top of the waterfall with the backend service spans below it. ### Embrace attributes in Honeycomb Every span Embrace forwards to Honeycomb includes mobile and web context that your backend instrumentation cannot provide on its own. These attributes include: * `emb.app_version`: Version of the app that made the request * `emb.device_id`: ID of the device that made the request * `emb.device_model`: Device model * `emb.os_version`: Operating system version * `emb.country_iso`: Country where the request originated * `emb.dashboard_session`: Direct link to the user's session in Embrace Because these attributes arrive as standard span attributes, you can use them in Honeycomb queries, BubbleUp analysis, and trigger conditions just like any other dimension. ### Session metrics When you configure metrics forwarding, Embrace also sends session and network metrics to Honeycomb: * `exceptions`: Unhandled exception count per session * `logcount`: Log event count per session * `network.request`: Total network requests * `network.successful.request`: Successful network requests * `network.successful.request.duration.total`: Total duration of successful network requests * `root.span.count`: Root span count per session * `root.span.duration.total`: Total duration of root spans * `session.count`: Total session count * `session.duration.total`: Total session duration * `span.count`: Total span count per session * `span.duration.total`: Total span duration * `user.flow.count`: User flow count per session ### Session deep links When a forwarded span includes `emb.dashboard_session`, Honeycomb renders it as a clickable link in the span detail view. Selecting it opens the exact user session in Embrace, with the network entry for that request already selected in the session timeline. ### BubbleUp on mobile dimensions Because Embrace attributes are first-class span dimensions in Honeycomb, BubbleUp can use them to surface patterns in your trace data. If a latency spike or error rate is concentrated in a specific app version, device model, or OS version, BubbleUp will identify it alongside your backend dimensions. ## What you can do Once you have [configured the integration](/integrations/embrace/configure/), you can: * Pivot from a backend trace to originating user session in Embrace * Use BubbleUp to identify whether a latency issue is concentrated in a specific app version, device, or OS * Query Embrace attributes alongside your backend dimensions in any Honeycomb query * Confirm user impact before escalating a backend incident * Monitor Embrace session metrics, including crash rates, ANR rates, session counts, and network request performance, alongside your backend trace data For step-by-step workflows, visit our use case guides: * [Investigate backend latency](/integrations/embrace/use-cases/investigate-backend-latency) * [Diagnose mobile ANRs and hangs](/integrations/embrace/use-cases/diagnose-mobile-anrs) * [Investigate with Embrace and Honeycomb MCP](/integrations/embrace/use-cases/investigate-with-mcp) # Diagnose Mobile ANRs and Hangs Source: https://docs.honeycomb.io/integrations/embrace/use-cases/diagnose-mobile-anrs Use Embrace and Honeycomb together to move from a mobile ANR alert to the exact backend span responsible, without escalating to the backend team blind. ## Overview When Embrace alerts on a spike in Application Not Responding (ANR) errors or hangs, the first question is whether the cause is on the client or upstream. Use Embrace's session data and Honeycomb's trace analysis together to answer that question quickly and hand off to the right team with evidence. ## Before you begin Before you begin, make sure you have: * [Configured the Embrace integration](/integrations/embrace/configure) and are forwarding network spans to Honeycomb. * Configured an Embrace alert on ANR rate or hang rate for the relevant screen or flow. ## Investigate the ANR spike When Embrace fires a critical alert (for example, ANR rate on a checkout screen crossing a threshold), the notification includes a direct link to the alert detail in Embrace. Open it to see the affected user count, the screen, and the platform breakdown. In Embrace, open the ANR issue breakdown. Embrace groups ANR sessions by stack group and shows what was blocking the main thread at the time of the freeze. If the top cause is **HTTP request in-flight**, the issue is upstream: the app was waiting on a network response when the OS killed the activity. This rules out client-side causes like JSON parsing, disk I/O, or animation jank, and points the investigation toward the backend. From the issue breakdown, select a representative session to open the session timeline. The timeline shows the sequence of user actions leading up to the ANR: the screens visited, the taps made, and the network request that was in-flight when the hang occurred. The hung network request appears in the timeline as a span with a long duration and no response status, marking the point where the OS gave up waiting. The `traceparent` value on the forwarded span is the bridge between Embrace and Honeycomb. It contains the trace ID you need to find the matching backend trace. 1. In the session timeline, expand the hung network request to view its span details. If Embrace forwarded this span to Honeycomb, the expanded row shows a **Forwarded** badge and the full W3C `traceparent` value. The `traceparent` value follows the format `00---`. The trace ID is the second segment: the 32-character hex value between the first and second hyphens. 2. Copy the trace ID. You will use it to find the matching trace in Honeycomb. With the trace ID in hand, you can find the exact backend trace in Honeycomb and walk the full request waterfall to identify where the time was spent. In Honeycomb: 1. Open Query Builder and filter for `trace.trace_id = `, replacing `` with the value you copied from Embrace. The query returns the matching backend trace. 2. Select the **Traces** view, then the **Trace ID** to open the trace waterfall. The waterfall representation shows the backend service spans, with the Embrace-forwarded client span at the top. 3. Examine the waterfall to find where the time was spent. Look for spans with unexpectedly long durations, error statuses, or external dependency calls that timed out. From the waterfall, open the slow span in Query Builder and run BubbleUp to confirm whether this is an isolated event or a broader pattern. BubbleUp surfaces the dimensions that differentiate the slow spans (for example, `aws.region` and `dependency`), so you can confirm whether the issue is concentrated in a specific region or external service. ## Hand off with evidence With the BubbleUp results, you have a specific, falsifiable bug to file: * The trace ID * The name of the hung backend span * The external dependency or region responsible * The affected user count from Embrace File the ticket against the owning backend team with the Honeycomb trace link and the Embrace session link. The mobile investigation is complete: you have confirmed the cause is upstream, identified the responsible team, and provided the evidence they need to reproduce and fix it. # Investigate Backend Latency Source: https://docs.honeycomb.io/integrations/embrace/use-cases/investigate-backend-latency Use Honeycomb and Embrace together to move from a backend latency trigger to confirmed user impact in a single investigation. ## Overview When a Honeycomb trigger fires on a backend service, the immediate question is whether real users are affected and how badly. This workflow takes you from a Honeycomb trigger to a confirmed user impact assessment in Embrace, without leaving your investigation context. ## Before you begin Before you begin, make sure you have: * [Configured the Embrace integration](/integrations/embrace/configure) and are forwarding network spans to Honeycomb. * A Honeycomb trigger on a backend service that includes mobile or web traffic. ## Investigate the trigger When a Honeycomb trigger fires, the notification includes a direct link back to the triggering query in Honeycomb. Select that link to open the query in Query Builder. The query shows the condition that fired, along with the current state of the data. If the trigger fired on `p95(duration_ms)`, the heatmap shows where the outlier band is concentrated. From the heatmap, draw a selection around the outlier band to run BubbleUp. BubbleUp compares the selected events against the baseline and surfaces the dimensions that differ most between them. Look for `emb.*` attributes in the BubbleUp results. If Embrace-forwarded spans are present in the outlier population, you will see dimensions like `emb.app_version` or `emb.device_model` ranking highly. This indicates the latency issue is concentrated in a specific mobile or web client slice. From the heatmap or query results, select a point in the outlier region and select **View trace**. The trace detail view opens with the waterfall representation of the trace. If the trace includes an Embrace-forwarded span, it appears at the top of the waterfall, labeled as forwarded via Embrace, with the backend service spans below it. The forwarded span carries the full set of `emb.*` attributes in the trace sidebar, including `emb.app_version`, `emb.device_model`, and `emb.dashboard_session`. In the trace sidebar, select the `emb.dashboard_session` value. Selecting it opens the exact user session in Embrace, with the network entry for the request already selected in the session timeline. In Embrace, the session timeline shows the full user journey around the slow request: the screens visited, the taps made, and any errors or rage taps that followed. The aggregate impact view shows how many users are affected, what their UX score is, and whether checkout conversion or other key flows are degraded. ## Make the call With the Embrace session data in hand, you have what you need to decide how to respond: * If the impact view shows a large affected user count, a poor cohort UX score, or a significant conversion drop, escalate the incident and notify the relevant teams. * If the impact is limited to a handful of users, an isolated carrier issue, or a specific edge-case device, you can close the investigation with confidence rather than paging additional teams. # Investigate with Embrace and Honeycomb MCP Source: https://docs.honeycomb.io/integrations/embrace/use-cases/investigate-with-mcp Use the Embrace and Honeycomb MCP servers together to run end-to-end observability investigations from your AI assistant. ## Overview Both Honeycomb and Embrace provide MCP servers that give AI assistants direct access to your observability data. When you connect both servers to the same agent, you can investigate the full request path—from mobile session data in Embrace to backend traces in Honeycomb—without leaving your development environment. ## Before you begin Before you get started, make sure you have: * [Configured the Embrace integration](/integrations/embrace/configure) and are forwarding network spans to Honeycomb. * [Configured Honeycomb MCP for your AI assistant](/integrations/mcp/configuration-guide). * [Configured Embrace MCP for the same AI assistant](https://embrace.io/docs/mcp/). * [Installed Honeycomb Agent Skills](/integrations/agent-skills) for your AI assistant. Before running a combined investigation, confirm both servers are connected by asking your agent: "List the tools available from Honeycomb MCP and Embrace MCP." If either server is missing, revisit [Agent Skills](/integrations/agent-skills) or [Embrace MCP](https://embrace.io/docs/mcp/) setup before continuing. ## How it works With both MCP servers connected, your AI assistant has access to tools from each platform simultaneously. Honeycomb MCP gives your agent access to backend traces, BubbleUp analysis, and query execution. Embrace MCP gives it access to mobile session data, crash and ANR details, and network endpoint performance. The `trace.id` and `emb.dashboard_session` attributes on forwarded spans connect the two: your agent can follow a trace ID from Honeycomb into the originating Embrace session, or follow a session ID from Embrace into the corresponding backend trace in Honeycomb. Your agent handles the pivot between servers automatically within a single conversation. You don't need to copy IDs or switch tools yourself. ## Example investigations The examples below are illustrative. Adapt the service names, app versions, and time windows to match your environment. ### Triage a backend latency spike with user context Ask your agent to investigate a latency spike in a specific service and determine whether real users are affected: > "There's a latency spike in the checkout-api service in the last hour. Use Honeycomb to identify which endpoint and dimension is responsible, then use Embrace to tell me how many users are affected and what their experience looked like." The agent can use Honeycomb MCP to run BubbleUp on the slow spans, identify the top differentiating dimension, and retrieve a representative trace ID. It can then use Embrace MCP to look up the session associated with that trace and report on user impact, UX score, and conversion data. ### Diagnose a mobile ANR with a backend root cause Ask your agent to investigate an ANR spike and determine whether the cause is on the client or upstream: > "Embrace is showing an ANR spike on the checkout screen in the last 30 minutes. Find out what's blocking the main thread and whether the backend is responsible." The agent can use Embrace MCP to retrieve the ANR breakdown, identify the in-flight network request, and extract the `trace.id` from the forwarded span. It can then use Honeycomb MCP to open that trace, walk the waterfall, and run BubbleUp to name the culprit backend service or dependency. ### Check the health of a release across both platforms Ask your agent to compare mobile and backend health before and after a deployment: > "We deployed version 7.15.0 of the mobile app this morning. Compare crash rates, ANR rates, and backend latency for checkout-api before and after the deploy." The agent can use Embrace MCP to retrieve crash and ANR metrics segmented by app version, and Honeycomb MCP to query backend latency for the same time window, surfacing any correlated degradation. ## Writing effective prompts The more context you give your agent, the less time it spends figuring out where to look. Include: * The service name, dataset, or environment in Honeycomb * The app name or app ID in Embrace * The time window you want to investigate * The specific metric or signal you are concerned about To learn more about prompting agents effectively with Honeycomb MCP, visit [Honeycomb MCP Use Cases](/integrations/mcp/use-cases). # Gate Deployments with GitHub Actions Deployment Protection Rules Source: https://docs.honeycomb.io/integrations/github-deployment-protection-rules Use Honeycomb query data to automatically gate deployments in GitHub Actions workflows, promoting or blocking based on real telemetry. Beta This feature is in [beta](/troubleshoot/product-lifecycle/release-stages/#beta), and we would love your feedback! Use Honeycomb query data to automatically gate deployments in your GitHub Actions workflows, promoting or blocking based on real telemetry from your systems. GitHub Actions Deployment Protection Rules are automatic controls that let you use data from external tools to gate deployments in Actions workflows. Honeycomb provides the Honeycomb Deployment Protection Rule that plugs into this framework. For each GitHub environment, you define a Honeycomb query and an allowable threshold that must pass before a deployment proceeds. Because rules are defined in a file in your repository, you can manage your deployment gates as code alongside the rest of your pipeline configuration. You can use the Honeycomb Deployment Protection Rule across a range of deployment scenarios: * Gate deployments based on error rates introduced by the current build * Run automated performance checks in blue/green style deployments * Drive canary release patterns * Check SLI error rates in staging before promoting to production * Prevent automated deployments during an ongoing incident * Ensure deployments are sensitive to the current service status in any environment If you are also instrumenting your build pipelines, you can generate distributed traces with [Buildevents](/integrations/build-pipelines/) and use those traces as the data source for your deployment protection rules. The Honeycomb Deployment Protection Rule is available to all Honeycomb customers. However, you must be a [GitHub Enterprise Cloud customer](https://docs.github.com/en/enterprise-cloud@latest/admin/overview/about-github-enterprise-cloud) to use GitHub Actions Deployment Rules. ## How It Works When enabled, the Honeycomb Deployment Protection Rule runs as a check prior to any deployment actions. It determines whether a deployment into the target GitHub environment is allowed to proceed. Honeycomb deployment protection rules consist of a Honeycomb query, a threshold, and an operator (`>`, `<`, or `=`). When a deployment is requested in your Actions workflow, the rule sends its payload to Honeycomb for evaluation, where it asks if the deployment is allowed to proceed. After Honeycomb completes the query evaluation, it returns a pass/fail response. All deployment protection rules are configured in a `.honeycomb.yaml` file that **must be** checked and located in the root directory of your GitHub repository. Otherwise, Honeycomb does not have permission to access this file. The `.honeycomb.yaml` file can contain a configuration block for each GitHub environment that the repository is deployed. Diagram of how GitHub Deployment Protection Rules work. ## Prerequisites and Limitations * GitHub Actions Deployment Protection Rules are only available to [GitHub Enterprise Cloud customers](https://docs.github.com/en/enterprise-cloud@latest/admin/overview/about-github-enterprise-cloud). * Completing the GitHub App installation requires a **GitHub Owner** to grant authorization and allows Honeycomb access to your GitHub organization and its repositories. * Linking GitHub to a Honeycomb team requires [**Honeycomb Team Owner** permissions](/configure/teams/manage-permissions/) in Honeycomb. * [Maximum Honeycomb query limits](#maximum-query-limits) exist. * Deployment protection rules only work with GitHub Actions workflows that use [GitHub environments as part of deployments](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment). ## Installation and Setup ### Install the Honeycomb GitHub App The Honeycomb Deployment Protection Rule is provided via the Honeycomb GitHub App. To install: 1. Navigate to the Honeycomb GitHub App. 1. [If using the Honeycomb US instance accessed via ui.honeycomb.io](https://github.com/apps/honeycomb-io/) 2. [If using the Honeycomb EU instance accessed via ui.eu1.honeycomb.io](https://github.com/apps/honeycomb-io-eu/) 2. Select **Install**. 3. Then, select which organization to install the Honeycomb GitHub App. The GitHub App installation flow requires a **GitHub Owner** to grant authorization that allows Honeycomb access to your GitHub organization and its repositories. 4. Authorize the Honeycomb GitHub App to your GitHub organization. An example of requested permissions appears below. GitHub app authorization modal 5. Once the GitHub authorization is complete, you are taken to Honeycomb to continue the installation process. 6. In Honeycomb, select the Honeycomb team to connect. The Honeycomb team selection flow requires [**Honeycomb Team Owner** permissions](/configure/teams/manage-permissions/) to complete. 7. Then, confirm which team's Honeycomb environments and datasets can be queried from your deployment protection rules. Refer to [Troubleshooting](#troubleshooting) if you encounter any issues during installation. ### Enable the Honeycomb Deployment Protection Rule in Each GitHub Environment After installing the Honeycomb GitHub App, it must be enabled as an environment protection rule for your various GitHub environments. GitHub Actions Deployment Protection Rules apply at the GitHub environment level, not at the repository level. Therefore, you **must repeat this step** for each GitHub environment where you wish to use the Honeycomb Deployment Protection Rule. To enable: 1. Navigate to your GitHub repository. 2. Under **Settings** > **Environments**, select the GitHub environment by its name. 3. Next, under **Deployment protection rules**, select the **Honeycomb.io** option. Optionally, select **Allow administrators to bypass configured protection rules** to allow GitHub Owners the ability to [force a deployment](#forcing-a-deployment) when a deployment protection rule is in a failure state. 4. Select **Save Protection Rules** to continue. Enable Honeycomb Deployment Protection Rule in GitHub Refer to GitHub documentation for more about [environment protection rules](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment). ### Configure Honeycomb Deployment Protection Rules You must create a `.honeycomb.yaml` file in the `root` of your repository to configure the queries and thresholds that act as a deployment protection rule for each GitHub environment. The YAML file must have a configuration block for every environment with a deployment protection rule enabled; otherwise, the stage fails. The `.honeycomb.yaml` file **must be** in the root directory of your repository. Honeycomb cannot access this file in a subdirectory. If the query defined as a deployment protection rule evaluates within the acceptable threshold, it "passes" and the deployment continues. Otherwise, it "fails" and the deployment is blocked. Honeycomb supports a [query specification](/investigate/collaborate/share-query/define-query-json/) for defining queries via JSON. Queries for Honeycomb deployment protection rules can be composed directly as JSON in your `.honeycomb.yaml` file. Guidance and resources exist for [writing deployment protection queries](#writing-deployment-protection-queries). Below is an example of a standard `.honeycomb.yaml` file. ```yaml theme={} version: 1 honeycomb_team: my-team # the honeycomb team where queries for all deployment protection rules runs deployment_protection_rules: staging: # name of github environment where a deployment occurs queries: - honeycomb_environment: qa # honeycomb environment where the query runs honeycomb_dataset: my-cool-application # (optional, but necessary when using Honeycomb Classic) When left empty, an environment-wide Honeycomb query runs, which is not supported by Honeycomb Classic. spec: &queryspec '{ "time_range": 1800, "calculations": [ { "op": "COUNT" } ], "filters": [ { "column": "status_code", "op": "=", "value": "500" }, { "column": "build_id", "op": "=", "value": ${GITHUB_RUN_ID} # NOTE: when deployment protection rules run, they can map the special GITHUB_RUN_ID variable } ], "filter_combination": "AND" }' threshold: operator: '>' value: 3 production: # name of github environment where a deployment occurs queries: - honeycomb_environment: staging # honeycomb environment where the query runs honeycomb_dataset: my-cool-application # (optional, but necessary when using Honeycomb Classic) When left empty, an environment-wide Honeycomb query runs, which is not supported by Honeycomb Classic. spec: *queryspec # example of a YAML alias to reuse a query spec created for a different deployment protection rule threshold: operator: '>' value: 1 ``` where: * `honeycomb_team` must be the team where queries for all deployment protection rules runs. This is checked against the team authorized when installing the GitHub App. * `GITHUB_RUN_ID` is a special variable interpolated by the GitHub App as the [unique identifier of the GitHub Actions workflow run](https://docs.github.com/en/rest/actions/workflow-runs?apiVersion=2022-11-28#get-a-workflow-run). To configure GitHub Deployment Protection Rules against Honeycomb Classic: * Specify `$classic$` as the environment slug * Specify the dataset (because environment-wide queries are not compatible with Honeycomb Classic) #### Writing Deployment Protection Queries When writing Deployment Protection Queries, remember the following: * **They operate similar to Triggers.** The same queries and thresholds used to define [Triggers](/notify/triggers/) can be used in deployment protection rules. For inspiration, visit our [Trigger Examples](/notify/triggers/examples/). * **Use the Query Builder UI to generate Query Spec JSON.** As an alternative to composing JSON directly, you can use Honeycomb's [Query Builder](/investigate/query/build/) to create the JSON for you. To write a deployment protection query: 1. Compose the query you wish to use as a deployment protection rule in the Query Builder and select **Run Query**. 2. After you are satisfied with the query results that appear, select the three-dot overflow menu, located to the left of Run Query. Then, select **View Query Definition for API**. options-query-builder.png 3. A modal appears with the Query JSON. Use the copy button to copy the content, and paste it into the `spec` of your `.honeycomb.yaml` file. copy-json.png * **Deployment Protection Queries can be extremely versatile.** The only constraint is that query results must be evaluated against a numeric threshold. Otherwise, deployment protection rules can be used to extract very granular data about the state of your application and its systems. For detailed information on queries, refer to [Honeycomb Query Builder documentation](/investigate/query/build/). ### View the Result of Your Actions Workflow Deployments After being configured and merged into your repository, Honeycomb deployment protection rules runs when a deployment is requested and waits to receive a pass/fail status **before** a deployment can occur to the target GitHub environment. View the results of the Honeycomb deployment protection rules in the [GitHub Actions Workflow run](https://docs.github.com/en/actions/using-workflows/about-workflows#viewing-the-activity-for-a-workflow-run). Examples of passing and failing deployment rules appear below. passing-deployment-rule.png failing-deployment-rule.png Whenever a Honeycomb deployment protection rule runs, it is included in the list of all rules protecting deployments in a particular workflow run. The Honeycomb GitHub App appends a permalink to the exact query results used to protect each environmental deployment during the run. Select that permalink to show the data in Honeycomb that allowed your deployment to pass or fail. If your deployment failed, this link provides a jumping off point to begin your investigation. To re-run a deployment protection rule, you must re-run the GitHub Actions workflow stage(s). ## Troubleshooting ### GitHub App not Authorized If the deployment protection rule fails with "GitHub App not authorized to access Honeycomb team", uninstall and reinstall the [GitHub App](https://github.com/apps/honeycomb-io/). ### Changing the Honeycomb Team Only one Honeycomb team can be configured during installation of the [Honeycomb GitHub App](https://github.com/apps/honeycomb-io/). You cannot change the Honeycomb team where deployment protection rule queries run without re-initializing the authorization flow. To change the Honeycomb team, you must uninstall and reinstall the GitHub App, and select the desired team during the new installation. ### Checking GitHub App Permissions You can use Honeycomb to verify the status of the GitHub App installation. In Honeycomb's left navigation menu, select **Account** and then select **Team settings**. Then, select the **Integrations** tab. Refer to the **Honeycomb + GitHub** section to determine the installation status. github-app-integration-page.png ### Forcing a Deployment GitHub Owners can force a deployment when a deployment protection rule is in a failure state. Ensure you have the [**Allow administrators to bypass configured protection rules** setting enabled](https://docs.github.com/en/actions/deployment/targeting-different-environments/using-environments-for-deployment#environment-protection-rules) when [enabling the Honeycomb Deployment Protection Rule in your GitHub Environment](#enable-the-honeycomb-deployment-protection-rule-in-each-github-environment) to allow for this. admin-config.png ### Maximum Query Limits * Honeycomb deployment protection rules may only query up to the past 24 hours of data * No more than one Honeycomb query may be defined per GitHub environment in your deployment # Provision and Manage Resources with HashiCorp Terraform Source: https://docs.honeycomb.io/integrations/hashicorp-terraform Use the Honeycomb Terraform provider to programmatically create and manage datasets, triggers, SLOs, boards, and other Honeycomb resources as code. [HashiCorp Terraform](https://www.terraform.io) is an infrastructure automation tool that enables programmatic provisioning and management of resources. ## Honeycomb Terraform Provider The Honeycomb Terraform provider is available through the [Terraform Registry](https://registry.terraform.io/providers/honeycombio/honeycombio/latest/docs). It allows you to codify, create, and manage Honeycomb resources such as Boards, Calculated Fields, SLOs, and Triggers via the Honeycomb API. The [full documentation](https://registry.terraform.io/providers/honeycombio/honeycombio/latest/docs) is in the Terraform Registry. ### Setup 1. Ensure you have [installed Terraform](https://learn.hashicorp.com/tutorials/terraform/install-cli). 2. If you don't yet have one, create a Terraform configuration file. Learn more in the [configuration section](https://registry.terraform.io/providers/honeycombio/honeycombio/latest/docs#example-usage) of the Terraform documentation. 3. Run `terraform init` to fetch the Honeycomb Terraform provider from the [Terraform Registry](https://registry.terraform.io/providers/honeycombio/honeycombio/latest/docs). 4. Start codifying your resources! ## Honeycomb AWS Integration Honeycomb provides a [Terraform module](https://github.com/honeycombio/terraform-aws-integrations) to automate configuration of various AWS services to Honeycomb. Read more about it [here](/integrations/hashicorp-terraform/#honeycomb-aws-integration). # Full Integrations Directory Source: https://docs.honeycomb.io/integrations/honeycomb-integrations-directory # Stream Logs from Fastly Source: https://docs.honeycomb.io/integrations/logs/fastly Stream logs from your Fastly CDN to Honeycomb using Fastly's log streaming feature for deeper visibility into your content distribution system behavior. [Fastly](https://fastly.com) supports [streaming logs](https://docs.fastly.com/guides/streaming-logs/). Send this data to Honeycomb for more insight into the behavior of your content distribution system. ## Configuration To send Fastly logs to Honeycomb, refer to the [Fastly documentation](https://docs.fastly.com/guides/streaming-logs/log-streaming-honeycomb). ## Sampling with VCL Use [Sampling](/manage-data-volume/sample/guidelines/) to reduce data volume in your Honeycomb datasets where you are gathering Fastly data. To implement sampling, we recommend a configuration that uses: 1. A **Logging** rule, which only forwards logs for requests if they are included in the sampled data. 2. **Varnish Configuration Language (VCL) snippet(s)**, which determines if the request should be sampled and at what rate. ### Configure Sampling 1. Update your Fastly configuration to create a logging rule, which forwards requests to Honeycomb only if the `req.http.log_request` local variable is set to `"1"`. Fastly logging endpoints 2. Create two **VCL snippets**: 1. **A table of sample rates for status codes** For example, this table describes the number of events which flow through per sampled event based on status code. `1` does not sample at all, `20` samples every 20th event, and so on. To use, copy and adjust the rates in this table based on your projection traffic: ```varnish theme={} table codes {     "200s": "20",     "300s": "5",     "400s": "3",     "500s": "1", } ``` 2. **Code that sets the sample rate based on HTTP status** Use the following code to set the `req.http.log_request` variable (as mentioned in the logging rule) if sampling should be applied: ```varnish theme={} set req.http.samplerate = table.lookup(codes, regsub(resp.status, "^([1-5])..", "\100s"), "1"); if (randombool(1, std.atoi(req.http.samplerate))) { set req.http.log_request = "1"; } else { set req.http.log_request = "0"; } ``` Fastly VCL snippet 3. To ensure that the sample rate is included as a property of the JSON event and sent to Honeycomb, add this line at the same level of the `time` and `data` keys: ```varnish theme={} "samplerate": %{req.http.samplerate}V, ``` This line encodes `samplerate` as a top0-level key sent to the Honeycomb API and causes all visualizations rendered by Honeycomb to appear as if **all** of the events, even ones which were sampled out, were sent. You can extend this basic configuration to sample based on cache status or other fields if desired. # Forward Fluentd Data Source: https://docs.honeycomb.io/integrations/logs/fluentd Forward structured logs from Fluentd to Honeycomb using Fluentd's out_http plugin or the OpenTelemetry Collector for richer telemetry context. [Fluentd](https://www.fluentd.org/) is a widely-used data router. If you are using Fluentd to aggregate structured logs, Fluentd's [`out_http` plugin](https://docs.fluentd.org/output/http) makes it easy to forward data to Honeycomb. If your system uses logspout as a log router for Docker containers, you can send logs to Honeycomb with one of the [logspout third-party modules](https://github.com/gliderlabs/logspout#third-party-modules) that integrates with [logstash](/integrations/logs/logstash/) or [fluentd](/integrations/logs/fluentd/). ## Getting Started To set up the plugin, first grab your team API key from your [Honeycomb account page](https://ui.honeycomb.io/account), and then update your Fluentd configuration file (usually found in `/etc/fluentd/fluentd.conf` or `/etc/td-agent/td-agent.conf`). A basic configuration to forward events with the `my.logs` tag to the Honeycomb dataset `fluentd_dataset` looks like this: ```xml theme={} @type record_transformer enable_ruby true renew_record true data ${ record } time ${ time.iso8601() } @type http endpoint https://api.honeycomb.io/1/batch/fluentd_dataset headers {"X-Honeycomb-Team":"YOUR_API_KEY"} @type json json_array true flush_interval 2s ``` ## Set Event Timestamps In Fluentd, each event has a distinguished `time` attribute. In general, you will use a [parser plugin](https://docs.fluentd.org/parser) to extract the time attribute from log lines. You can read more about the structure of a Fluentd event [here](https://docs.fluentd.org/quickstart/life-of-a-fluentd-event#event-structure). For example, if you have a JSON log file containing timestamps in the format: ```json theme={} {"timestamp": "2018-02-04T14:55:10Z", "host": "app22", ...} ``` Then, you would extract the time value using the following Fluentd configuration: ```xml theme={} @type tail path /var/log/my.logs @json # Use the JSON parser plugin to parse records time_key timestamp # Extract the time value from the `timestamp` key time_type string # Expect a string timestamp time_format %Y-%m-%dT%H:%M:%SZ # Specify the timestamp format tag my.logs @type record_transformer enable_ruby true renew_record true data ${ record } time ${ time.iso8601() } @type http endpoint https://api.honeycomb.io/1/batch/myapp_dataset headers {"X-Honeycomb-Team":"YOUR_API_KEY"} @type json json_array true flush_interval 2s ``` # Filter and Send Logstash Data Source: https://docs.honeycomb.io/integrations/logs/logstash Fork your Logstash pipeline to send a copy of all log traffic to Honeycomb using Logstash's flexible plugin architecture and HTTP output plugin. Thanks to [Logstash](https://www.elastic.co/downloads/logstash)'s flexible plugin architecture, you can send a copy of all the traffic that Logstash is processing to Honeycomb. This topic explains how to use Logstash plugins to convert incoming log data into events and then send them to Honeycomb. If your system uses logspout as a log router for Docker containers, you can send logs to Honeycomb with one of the [logspout third-party modules](https://github.com/gliderlabs/logspout#third-party-modules) that integrates with [logstash](/integrations/logs/logstash/) or [fluentd](/integrations/logs/fluentd/). ## Data Format Requirements Honeycomb is at its best when the events you send are broad and capture lots of information about a given process or transaction. To process the log data coming into Logstash into Honeycomb events, you can use Logstash filter plugins. These filter plugins transform the data into top-level keys based on the original source of the data. We have found these to be especially useful: * [grok](https://www.elastic.co/guide/en/logstash/current/plugins-filters-grok.html) matches regular expressions and has configs for many common patterns (such as the apache, nginx, or haproxy log format). * [json](https://www.elastic.co/guide/en/logstash/current/plugins-filters-json.html) matches JSON-encoded strings and breaks them up in to individual fields. * [kv](https://www.elastic.co/guide/en/logstash/current/plugins-filters-kv.html) matches `key=value` patterns and breaks them out into individual fields. To add and configure filter plugins, refer to [Working with Filter Plugins](https://www.elastic.co/guide/en/logstash/current/working-with-plugins.html) on the Logstash documentation site. ### Example: Using Logstash Filter Plugins to Process Haproxy Logs for Honeycomb Ingestion Let us say you are sending haproxy logs (in HTTP mode) to Logstash. A log line describing an individual request looks something like this (borrowed from the [haproxy config manual](https://www.haproxy.org/download/1.6/doc/configuration.txt)): ```log theme={} Feb 6 12:14:14 localhost \ haproxy[14389]: 10.0.1.2:33317 [06/Feb/2009:12:14:14.655] http-in \ static/srv1 10/0/30/69/109 200 2750 - - ---- 1/1/1/1/0 0/0 {1wt.eu} \ {} "GET /index.html HTTP/1.1" ``` Logstash puts this line in a `message` field, so in the filter parameter of the `logstash.yaml` config fragment below, we use the `grok` filter plugin and tell it to parse the message and make all the content available in top-level fields. And, since we do not need it anymore, we tell `grok` to remove the `message` field. The `mutate` filter plugin takes the numeric fields extracted by haproxy and turns them into integers so that Honeycomb can do math on them (later). ```ruby theme={} filter { grok { match => ["message", "%{HAPROXYHTTP}"] remove_field => ["message"] } mutate { convert => { "actconn" => "integer" "backend_queue" => "integer" "beconn" => "integer" "bytes_read" => "integer" "feconn" => "integer" "http_status_code" => "integer" "retries" => "integer" "srv_queue" => "integer" "srvconn" => "integer" "time_backend_connect" => "integer" "time_backend_response" => "integer" "time_duration" => "integer" "time_queue" => "integer" "time_request" => "integer" } } } ``` ## Sending Data to Honeycomb Now that all the fields in the `message` are nicely extracted into events, send them on to Honeycomb! To send events, configure an output plugin. You can use [Logstash's HTTP output plugin](https://www.elastic.co/guide/en/logstash/current/plugins-outputs-http.html) to craft HTTP requests to the Honeycomb API. This configuration example sends the data to a dataset called "logstash." ```ruby theme={} filter { ruby { code => 'event.to_hash.each { |k, v| event.set("[data][" + k + "]" , v) }' } prune { whitelist_names => [ "^data$" ] } } output { http { url => "https://api.honeycomb.io/1/batch/logstash" # US instance #url => "https://api.eu1.honeycomb.io/1/batch/logstash" # EU instance http_method => "post" headers => { "X-Honeycomb-Team" => "YOUR_API_KEY" } format => "json_batch" http_compression => true } } ``` To complete configuration in the example above: * Use `filter` to nest the Logstash JSON fields under a `data` element in the JSON payload to Honeycomb. This filter is **required** for Honeycomb to ingest your Logstash logs. Learn more about `filter` in the [Elastic documentation](https://www.elastic.co/guide/en/logstash/current/filter-plugins.html). * Specify a URL (`url`) to send the data to: * for our US instance: `https://api.honeycomb.io/1/batch/` * for our EU instance: `https://api.eu1.honeycomb.io/1/batch/` * Add your Honeycomb [API key](/configure/environments/manage-api-keys/) to `"X-Honeycomb-Team"` so that Logstash is authorized to send data to Honeycomb. * Specify the output format as JSON batch (`json_batch`). * Specify the use of HTTP compression (`http_compression => true`). Then, restart Logstash. When it is back up, you will find the new dataset on [your landing page](https://ui.honeycomb.io/). ### Set Event Timestamps In Logstash, each event has a special `@timestamp` field. In general, use the [date filter plugin](https://www.elastic.co/guide/en/logstash/current/plugins-filters-date.html) to extract the time attribute from log lines. For example, if you have a JSON log line containing timestamps in the format: ```json theme={} {"timestamp": "2018-02-04T14:55:10Z", "host": "app22", ...} ``` Then, extract the time value using the following Logstash configuration: ```ruby theme={} filter { mutate{ rename => {"timestamp" => "time"} } date { match => ["time", "ISO8601"] } ruby { code => 'event.to_hash.each { |k, v| event.set("[data][" + k + "]" , v) unless k == "time" }' } prune { allowlist_names => [ "^data$", "^time$" ] } } output { http { url => "https://api.honeycomb.io/1/batch/logstash" # US instance #url => "https://api.eu1.honeycomb.io/1/batch/logstash" # EU instance http_method => "post" headers => { "X-Honeycomb-Team" => "YOUR_API_KEY" } format => "json_batch" http_compression => true } } ``` # Core Concepts of Honeycomb MCP Source: https://docs.honeycomb.io/integrations/mcp/concepts Find out what Model Context Protocol is, how it works, and how Honeycomb MCP uses it to let AI agents query and analyze your observability data. Understand how Honeycomb MCP uses Model Context Protocol to let AI agents explore your observability data. ## What is Model Context Protocol? Model Context Protocol (MCP) is a standard that lets AI agents and large language models (LLMs) interact with external tools and services in a consistent, structured way. With MCP, you can enable AI agents to perform specific actions, like browsing the web, editing local files, or fetching GitHub issues and pull requests. ### Why does it matter? You may already use AI tools like Cursor, Claude Code, Codename Goose, or one of the many (many) AI assistants that have emerged in the developer ecosystem since 2024. These tools have empowered developers and operators by expanding what LLMs, such as Anthropic Claude, OpenAI GPT, and DeepSeek R1, can do. Instead of only answering questions and generating text snippets, LLMs can now perform tasks by using tools. MCP provides a standardized way to define and expose those tools, making it easier for AI agents to discover and use them reliably. ### How MCP servers fit in An MCP server is the implementation of the MCP standard. It exposes your tools in a structured, machine-readable format. Think of the server as the bridge between AI agents and the services or data sources they need to interact with. ### Honeycomb MCP Server Honeycomb MCP Server brings Honeycomb's observability investigation approach to LLMs via AI agents. It lets AI agents query, explore, and iterate on telemetry data just like you do in our UI. In practice, we have seen that AI agents using Honeycomb MCP can do meaningful work. They can: * Investigate and diagnose latency or error spikes * Identify performance outliers and suggest optimization opportunities * Translate existing dashboards and alerts into Honeycomb's query language We are excited to see the new ways you will use this integration to enhance your workflows. ## Key concepts Get familiar with how the Honeycomb MCP server works. Understanding these concepts will help you configure the server effectively, write better prompts, and get more useful results from your agents. ### Tools MCP makes Honeycomb functionality available to AI agents by exposing it as discrete tools. Each tool performs a specific task, like running a query, fetching a trace, creating a Board, or starting a Canvas investigation. To explore the full list of tools your agent can call, visit the [MCP Tools Reference](/integrations/mcp/tools/). ## Security model Honeycomb MCP follows the same security standards as the rest of the Honeycomb platform. Most tools are read-only. Write tools require the `mcp:write` scope, which you grant explicitly during OAuth consent or when configuring an API key. Write tools include creating or updating Boards, Triggers, SLOs, notification recipients, and Canvas investigations. The [MCP Tools Reference](/integrations/mcp/tools/#required-scopes-for-write-tools) lists every write tool and the scope it requires. This design limits agent access by default and expands it only when you explicitly grant permission. The [Activity Log Environment](/configure/teams/investigate-activity/#investigate-team-activity-using-activity-log-datasets) is surfaced through the MCP server only to [Team Owners](/configure/teams/manage-permissions/). Team members of other roles can access the Activity Log Environment in the Honeycomb UI, but it is not exposed to AI agents acting on their behalf. ## Best practices Getting your agent connected is just the start. How you prompt it, what context you give it, and how you configure your data all affect the quality of what it returns. ### Write effective prompts Your agent is only as good as the context you give it. Without clear direction, it has to guess at what you mean, and in observability, a wrong guess wastes time you don't have during an incident. Some ways to guide your agent effectively include: * **Be specific**: Vague prompts like "Why is the system slow?" leave too much room for guesswork. Instead, try something more focused: "Investigate a latency spike between 12:00 and 13:00 in the `api-gateway` service." Include details like service names, attributes, or signal types. * **Provide context up front**: If you are working with a specific codebase, run the agent from that repo and let it know that it can look at the code for details. Mention relevant services, environments, or datasets in your prompt to narrow its focus. * **Use files to manage context across steps**: For multi-step tasks, like plotting series data or comparing results over time, ask the agent to store responses in files. It can read those files later as it continues to reason or assemble output. ### Customize attribute descriptions The better your agent understands your data, the more useful its analysis will be. Investing time in describing your attributes pays off every time your agent runs a query or writes instrumentation. MCP tools like `find_columns`, `get_dataset_columns`, and `search_semconv` use Honeycomb's attribute registry to describe your data to your agent, so well-described attributes produce better results. You can also [define a custom telemetry schema for your team](/configure/teams/customize-telemetry-schema/) that overlays the standard OpenTelemetry and Honeycomb attribute definitions with your own. This gives agents richer, team-specific context when exploring your telemetry. ### Capture findings with Boards Investigation results are only useful if your team can find them later. Rather than letting findings disappear when a chat session ends, use Boards to capture and share what your agent discovers. The MCP server can create new Boards with `create_board` and edit existing Boards with `update_board`. Agents can also add, remove, update, and reorder query, SLO, and text panels on existing Boards, so you can capture investigation results on a Board you already use. To learn more about managing Boards, visit [Manage Boards](/investigate/observe/boards/manage). ## Next steps Continue your MCP journey with these focused resources: * [Connecting AI Agents to Honeycomb MCP](/integrations/mcp/configuration-guide/): Follow step-by-step instructions to connect common agents to Honeycomb MCP. * [Example Use Cases](/integrations/mcp/use-cases/): Explore real-world use cases and tips for working with Honeycomb via MCP. * [Troubleshooting](/integrations/mcp/troubleshooting/): Find solutions to common configuration issues and learn how to verify that your agent is connected and working correctly. # Connecting to Honeycomb MCP Source: https://docs.honeycomb.io/integrations/mcp/configuration-guide Connect your AI agent to the Honeycomb MCP Server. Connect Honeycomb to any AI agent that supports the Model Context Protocol (MCP) so it can query your telemetry, investigate issues, and answer questions using your live Honeycomb data. This guide covers the fastest way to connect, manual configuration for specific clients, and authentication with an API key. ## Before you begin Make sure that: * Your Honeycomb team has [enabled Honeycomb Intelligence](/configure/teams/manage-behavior#enable-honeycomb-intelligence). * Your AI agent supports remote MCP servers or plugins. ## Put your agent to work Two prompts are all it takes: one connects your agent to Honeycomb, the other starts onboarding using your live data. 1. Select your region and run the associated prompt in your AI agent: Add the Honeycomb MCP server at [https://mcp.honeycomb.io/mcp](https://mcp.honeycomb.io/mcp) and authenticate with OAuth. Add the Honeycomb MCP server at [https://mcp.eu1.honeycomb.io/mcp](https://mcp.eu1.honeycomb.io/mcp) and authenticate with OAuth. 2. Once your agent authenticates, run this prompt to start onboarding: /honeycomb-onboarding Your agent introduces itself, asks a few quick questions about your role and which services you work on, and looks at what is actually sending data to your Honeycomb account. From there, you choose what to focus on: debugging a live issue, exploring your data, or checking reliability. Your agent tailors everything that follows to the service and path you pick. ## Connect manually For step-by-step configuration instructions, select your client:
Connect Amazon Q Developer to Honeycomb MCP using the qchat CLI: 1. Select your region and run the associated command in your terminal: ```bash wrap theme={} qchat mcp add --name honeycomb --command npx --args mcp-remote,https://mcp.honeycomb.io/mcp ``` ```bash wrap theme={} qchat mcp add --name honeycomb --command npx --args mcp-remote,https://mcp.eu1.honeycomb.io/mcp ``` 2. Run this prompt in Amazon Q and authenticate with Honeycomb when asked: /honeycomb-setup 3. Once your agent authenticates, run this prompt to start onboarding: /honeycomb-onboarding Connect Augment (Auggie CLI) to Honeycomb MCP by installing the Honeycomb plugin: 1. Add the [honeycomb/agent-skill](https://github.com/honeycombio/agent-skill) repo as a plugin source: ```bash theme={} auggie plugin marketplace add honeycombio/agent-skill ``` 2. Install the Honeycomb plugin. ```bash theme={} auggie plugin install honeycomb ``` 3. Run this prompt in Auggie and authenticate with Honeycomb when asked: /honeycomb-setup 4. Once your agent authenticates, run this prompt to start onboarding: /honeycomb-onboarding Connect ChatGPT to Honeycomb MCP by installing the Honeycomb app from ChatGPT's app directory: 1. Go to the [Honeycomb plugin](https://chatgpt.com/plugins/plugin_asdk_app_6a51b29fa2d48191b215ff28f9a64fb4) page. 2. Select **Install plugin**. 3. When prompted, sign in to Honeycomb to finish authentication. 4. Once your agent authenticates, run this prompt to start onboarding: /honeycomb-onboarding Connect Claude Code to Honeycomb MCP by installing the Honeycomb plugin: 1. Install Honeycomb as a Claude Code plugin: ```bash theme={} claude plugin marketplace add honeycombio/agent-skill claude plugin install honeycomb ``` 2. Run this prompt in Claude Code and authenticate with Honeycomb when asked: /honeycomb-setup 3. Once your agent authenticates, run this prompt to start onboarding: /honeycomb-onboarding 1) Select your region and run the associated command in your terminal: ```bash wrap theme={} claude mcp add honeycomb --transport http https://mcp.honeycomb.io/mcp ``` ```bash wrap theme={} claude mcp add honeycomb --transport http https://mcp.eu1.honeycomb.io/mcp ``` 2) Run this prompt in Claude Code and authenticate with Honeycomb when asked: /honeycomb-setup 3) Once your agent authenticates, run this prompt to start onboarding: /honeycomb-onboarding Connect Claude Desktop to Honeycomb MCP using the Honeycomb connector: 1. Go to the [Honeycomb connector](https://claude.ai/directory/connectors/honeycomb) page. 2. Select **Connect** to add the Honeycomb connector to your Claude Desktop. 3. When prompted, sign in to Honeycomb to finish authentication. 4. Once your agent authenticates, run this prompt to start onboarding: /honeycomb-onboarding Connect OpenAI Codex to Honeycomb MCP by installing the Honeycomb app: 1. Go to the [Honeycomb plugin](https://chatgpt.com/plugins/plugin_asdk_app_6a51b29fa2d48191b215ff28f9a64fb4) page. 2. Select **Install plugin**. 3. When prompted, sign in to Honeycomb to finish authentication. 4. Once your agent authenticates, run this prompt to start onboarding: /honeycomb-onboarding 1) Select your region and run the associated command in your terminal: ```bash wrap theme={} codex mcp add honeycomb --url https://mcp.honeycomb.io/mcp ``` ```bash wrap theme={} codex mcp add honeycomb --url https://mcp.eu1.honeycomb.io/mcp ``` 2) Run this prompt in Codex and authenticate with Honeycomb when asked: /honeycomb-setup 3) Once your agent authenticates, run this prompt to start onboarding: /honeycomb-onboarding Connect GitHub Copilot to Honeycomb MCP by installing the Honeycomb plugin: 1. Install Honeycomb as a Copilot plugin: ```bash theme={} copilot plugin install honeycombio/agent-skill:honeycomb ``` 2. Run this prompt in Copilot and authenticate with Honeycomb when asked: /honeycomb-setup 3. Once your agent authenticates, run this prompt to start onboarding: /honeycomb-onboarding Connect Cursor to Honeycomb MCP using a one-click install link: [Add Honeycomb to Cursor](cursor://anysphere.cursor-deeplink/mcp/install?name=honeycomb\&config=eyJ1cmwiOiJodHRwczovL21jcC5ob25leWNvbWIuaW8vbWNwIn0=) 1. Open Cursor and navigate to **Customize**. 2. Select **MCP** then select **+New**. 3. Select your region and update `mcp.json` with the associated configuration: ```json theme={} { "mcpServers": { "honeycomb": { "url": "https://mcp.honeycomb.io/mcp" } } } ``` ```json theme={} { "mcpServers": { "honeycomb": { "url": "https://mcp.eu1.honeycomb.io/mcp" } } } ``` 4. Save the configuration file and restart Cursor. 5. Run this prompt in Cursor and authenticate with Honeycomb when asked: /honeycomb-setup 6. Once your agent authenticates, run this prompt to start onboarding: /honeycomb-onboarding Connect VS Code to Honeycomb MCP using a one-click install link: [Add Honeycomb to VS Code](vscode:mcp/install?%7B%22name%22%3A%22honeycomb%22%2C%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fmcp.honeycomb.io%2Fmcp%22%7D)
## Authenticate with an API key If you are building autonomous or unattended agents and cannot use OAuth, then you can authenticate with an API key. Only team owners can generate an API key. Prefer OAuth in most use cases. Use an API key only when your agent cannot support interactive login. 1. Log in to your Honeycomb account. 2. Navigate to **Account** > **Team Settings** > **API Keys**. 3. Select **Create Management API Key**. 4. Name your key (for example, "MCP Integration"). 5. Choose the **Model Context Protocol** and **Environments** scopes, then grant permissions: * **Read**: Required for all Honeycomb MCP operations. **Be sure to grant read for both MCP and Environments**. * **Write**: Required for tools that create or update Honeycomb resources, including Boards, Triggers, SLOs, notification/alert recipients, and Canvas investigations. To explore the complete list of write tools, visit the [MCP Tools Reference](/integrations/mcp/tools/#required-scopes-for-write-tools). 6. Copy the **Key ID** and **Key Secret**, and store them somewhere safe. You will need them later, and you won't be able to see them again. The exact configuration process varies by agent, but here is an example configuration `mcp.json` snippet used by agents like Claude Code or Cursor: Be sure to use the appropriate endpoint for your region, and replace `KEY_ID` and `SECRET_KEY` with your actual key values. ```json theme={} { "mcpServers": { "honeycomb": { "command": "npx", "args": [ "-y", "mcp-remote", "https://mcp.honeycomb.io/mcp", "--header", "Authorization: Bearer $HONEYCOMB_API_KEY" ], "env": { "HONEYCOMB_API_KEY": ":" } } } } ``` Pay attention to formatting, including spacing and colon (`:`) characters. If your tool cannot parse the `Authorization` header correctly, try putting the `Bearer` prefix directly in the environment variable: `"HONEYCOMB_API_KEY": "Bearer KEY_ID:SECRET_KEY"`. As a security best practice, make sure that keys being used for MCP integrations do not carry any other scopes, and that you do not commit them to source control. Once connected, test by asking your agent to list available tools or fetch available teams and environments. You should get results if your key and permissions are set up correctly. ## Next steps Continue your MCP journey: * [Example Use Cases](/integrations/mcp/use-cases): Explore real-world use cases and tips for working with Honeycomb via MCP. * [Tools Reference](/integrations/mcp/tools): Learn about the tools Honeycomb MCP exposes to AI agents. * [Troubleshooting](/integrations/mcp/troubleshooting): Fix common MCP configuration and connection issues. # Honeycomb MCP Tools Reference Source: https://docs.honeycomb.io/integrations/mcp/tools Reference for the tools Honeycomb MCP exposes to AI agents, including discovery, query, trace, Board, Trigger, SLO, and Canvas investigation tools. Understand what each Honeycomb MCP tool does, when an agent will reach for it, and any requirements that apply. ## How tools are used AI agents discover MCP tools automatically when they connect. Each tool corresponds to a specific Honeycomb capability, like running a query, fetching a trace, or creating a Board. Agents pick which tool to call based on the tool's name, description, and your prompt, so you do not normally have to name a tool yourself. This page documents every tool the Honeycomb MCP server exposes. Use it to understand what your agent can do, to write more directed prompts, or to troubleshoot why an agent did or did not use a particular capability. Some tools require specific access scopes or are limited to certain plan tiers. To explore the full matrix, visit [Rate Limits and Scopes](#rate-limits-and-scopes). ## Tool surface at a glance Use this table to get a quick overview of what your agent can read and write before diving into the full reference. | Category | Read tools | Write tools | | ----------------------------------------------------------------- | -------------------------------------------------------------------------------- | ---------------------------------- | | [Workspace discovery](#workspace-discovery) | `get_workspace_context`, `get_environment`, `get_dataset`, `get_dataset_columns` | | | [Query and analysis](#query-and-analysis) | `run_query`, `get_query_results`, `find_queries`, `find_columns`, `run_bubbleup` | | | [Traces and spans](#traces-and-spans) | `get_trace`, `list_spans`, `get_span_details` | | | [Service map and anomalies](#service-map-and-anomalies) | `get_service_map`, `get_anomaly_service_profiles` | | | [Semantic conventions](#semantic-conventions) | `search_semconv`, `get_semconv_attribute`, `list_semconv_namespaces` | | | [Boards](#boards) | `list_boards` | `create_board`, `update_board` | | [Triggers](#triggers) | `get_triggers` | `create_trigger`, `update_trigger` | | [Service Level Objectives (SLOs)](#service-level-objectives-slos) | `get_slos` | `create_slo`, `update_slo` | | [Notification recipients](#notification-recipients) | `list_recipients` | `create_recipient` | | [Canvas investigations](#canvas-investigations) | `canvas_agent_poll_response` | `canvas_agent_invoke` | | [AI conversation analysis](#ai-conversation-analysis) | `list_aiconversations`, `get_aiconversation` | | | [Other](#other-tools) | `refinery_docs` | `feedback` | ## Workspace discovery Before your agent can do useful work, it needs to know where it is. These tools help it orient itself within your Honeycomb team and locate the right environments, datasets, and columns. Returns the team name, current time, and a list of environments with their slugs and dataset counts. Takes no parameters. Agents call this tool first to orient themselves before doing anything else. Most prompt-driven workflows start here so the agent knows which environments exist before running queries or fetching data. Returns details for a single environment, including its datasets and calculated fields, sorted by most recent activity. Returns up to 100 datasets per call. Returns metadata and the full column schema for a single dataset, including columns and calculated fields in a unified list sorted by last write time. Returns up to 100 columns per call by default. Returns the full column schema for a single dataset, with optional sample values for specific columns. For metrics datasets, returns metric names by default. Pass a `metric_name` to discover the attributes available for filtering or grouping a specific metric. ## Query and analysis These tools give your agent the ability to ask questions about your data—running aggregation queries, fetching prior query results, finding existing queries, locating relevant columns, and analyzing query subsets with BubbleUp. Runs a time-series aggregation query against a Honeycomb dataset and returns computed results. Supports compound queries ([query math](/investigate/query/math)), per-calculation filters, formulas, breakdowns, [calculated fields](/investigate/query/build/calculated-fields), and [relational trace prefixes](/investigate/query/build#relational-fields) (`root.`, `parent.`, `child.`, `any.`). Agents use this tool to compute custom aggregations that go beyond what simpler discovery tools can answer. When data is sampled, results include sampling metadata. Agents can use the `usage_mode` flag to disable sample-rate correction. Retrieves results and metadata from a previously executed query run. Accepts a Honeycomb query URL, a query run primary key, or a query ID (which returns the most recent run). Agents use this tool to fetch the output of a saved or earlier query without re-running it. Searches query history and saved queries by intent and returns matching queries with their run primary keys. Pair the result with [`get_query_results`](#param-get-query-results) to fetch the actual data. Useful when you want the agent to learn from prior investigations or reuse a saved query. Searches for columns and calculated fields by intent across one or all datasets in an environment. Agents use this tool to find relevant fields based on natural-language keywords rather than exact column names. Honeycomb's [Weaver registry](/configure/teams/customize-attributes/) feeds richer descriptions into this tool, so well-described attributes produce better matches. Runs a [BubbleUp](/investigate/analyze/identify-outliers) analysis on an existing query result to identify what makes a selected subset of data different from the baseline. BubbleUp compares value distributions across columns and surfaces the statistically significant differences. ## Traces and spans These tools let your agent move from aggregate query results into raw trace data, exploring span names and attributes across trace-aware datasets, so it can follow a request through your system and identify where things went wrong. Retrieves all spans for a specific trace ID and renders them as a waterfall. Agents can use the parameters for this tool to zoom in to specific subtrees of a trace and identify errors. Lists span names in trace data, ranked by count, with how often each is a trace root and which dataset the count came from. Returns a summary of attributes and their common values observed on spans with a specific name, including which attributes are populated, how many distinct values each has, and the top observed values. ## Service map and anomalies These tools give your agent a higher-level view of your system, so it can understand service dependencies and surface active anomaly detection profiles. Enterprise Returns a snapshot of service-to-service call dependencies for a specified time range. Powers the same graph as the [Service Map](/investigate/observe/service-map/) view in Honeycomb. Returns anomaly detection service profiles for the current team. Requires that anomaly detection be enabled for the team. ## Semantic conventions These tools let your agent search and inspect OpenTelemetry semantic convention attributes, including any team-specific extensions defined in the Weaver registry, so it can write better instrumentation and more accurate queries. Searches the semantic convention registry for attributes matching a query. Returns full definitions of one or more semantic convention attributes by their exact names. Lists the top-level semantic convention namespaces available in the team's registry, including any [team-specific attribute customizations](/configure/teams/customize-attributes/). ## Boards These tools let your agent create and manage Boards, so investigation results can be captured and shared with your team in a format everyone can revisit. Lists Boards in an environment, or returns the full contents of a single Board by ID. Use this before `update_board` to inspect existing panels and IDs. Creates a Board with query panels, Service Level Objective (SLO) panels, and text (Markdown) panels. Panels appear in the order you specify them and can include explicit width and height. Supports preset filters that become filter dropdowns on the Board. To learn more about Boards, visit [Customize Boards](/observe/boards/customize/). Updates an existing Board. Supports renaming, adding, removing, updating, and reordering panels, plus replacing preset filters and tags. ## Triggers These tools let your agent inspect, create, and update Honeycomb [Triggers](/notify/triggers/), so you can automate alerting based on query thresholds without leaving your workflow. Lists Triggers for the team, or returns detailed configuration for a single Trigger, including recipients with their type, name or target, and ID. Creates a Trigger that fires alerts when query results cross a threshold. To learn more about Triggers, visit [Create a Trigger](/notify/triggers/create/). Updates an existing Trigger. ## Service Level Objectives (SLOs) These tools let your agent inspect, create, and update Honeycomb Service Level Objectives ([SLOs](/notify/slos/)), so you can establish and maintain reliability targets for your services. Lists SLOs for the team, or returns detailed status and graphs for a single SLO. Creates an SLO with an auto-created Service Level Indicator (SLI) derived column. Provide the SLI expression and an alias, and the tool creates the derived column if needed, validates the expression, and then creates the SLO. To learn more about SLOs, visit [Create an SLO](/notify/slos/create/). Updates an existing SLO. Partial-update semantics apply; omitted fields keep their current values. Dataset associations are fixed at creation time; create a new SLO to use different datasets. ## Notification recipients These tools let your agent manage the notification destinations that Triggers and Service Level Objective (SLO) burn alerts route to, so alerts reach the right people and systems. Lists all pre-registered notification recipients for the team, including email, Slack, PagerDuty, and webhooks, with their IDs. Creates a notification recipient that can be attached to Triggers and SLO burn alerts. Returns the recipient ID for use with `create_trigger` and `update_trigger`. To learn more about recipients, visit [Recipients for Notifications](/notify/recipients/). ## Canvas investigations These tools let your agent interact with Honeycomb [Canvas](/investigate/canvas) and contribute to collaborative investigations alongside your team, running queries, laying out evidence, and summarizing findings on your team's behalf. Sends a message to the Canvas agent. If an investigation ID is provided, the message is routed to the user's agent in that investigation. Otherwise, a new investigation is created. Polls for the result of a previously-issued `canvas_agent_invoke` call. To learn more about Canvas investigations, visit [Canvas](/investigate/canvas/). ## AI conversation analysis These tools let your agent analyze telemetry from other AI agents in your stack that emit OpenTelemetry `gen_ai.*` attributes, answering questions like "which conversations had errors" and "how many tokens did this agent use" without requiring you to compose `run_query` calls. Lists recent AI agent conversations (`gen_ai.conversation.id` values) in an environment, ordered by total event count. Includes a per-conversation breakdown of agents, services, event counts, error counts, and token usage. Returns the full event timeline for a single AI conversation by its `gen_ai.conversation.id` value, including every LLM call, tool call, and related agent event with span name, operation, agent name, model, tool name, duration, and error detail. Also includes an aggregate summary with LLM call count, tool call count, failure count, total tokens, and total duration. ## Other tools These tools cover capabilities that do not fit neatly into the categories above but are still useful for getting the most out of Honeycomb MCP. Reads from Honeycomb [Refinery](/manage-data-volume/sample/honeycomb-refinery/) documentation, so your agent can answer Refinery configuration questions without leaving the conversation. Submits feedback about the Honeycomb MCP server experience to the Honeycomb team that maintains it. Ask your agent to "submit feedback to Honeycomb" with your message. ## Rate limits and scopes Understanding rate limits and required scopes helps you configure your agent correctly and avoid unexpected errors during operation. ### Rate limits Honeycomb MCP enforces per-tool rate limits to protect platform stability. Most tools share a default limit of 50 calls per minute, but discovery and metadata tools allow higher limits, and expensive or mutating tools have lower ones. | Tool | Limit per minute | | ---------------------------------------------------------------------------------------------------------------------------- | ---------------- | | `get_workspace_context`, `get_dataset`, `get_environment`, `list_boards`, `list_recipients`, `find_columns`, `refinery_docs` | 200 | | `search_semconv`, `get_semconv_attribute`, `list_semconv_namespaces` | 300 | | `canvas_agent_poll_response` | 300 | | `get_triggers`, `get_anomaly_service_profiles`, `find_queries`, `get_query_results` | 150 | | `run_query`, `get_trace`, `get_dataset_columns`, `get_slos`, `feedback` | 100 | | `update_trigger`, `update_slo` | 30 | | `create_trigger`, `create_slo`, `create_recipient`, `canvas_agent_invoke` | 20 | | `get_service_map` | 10 | | All other tools | 50 (default) | Rate-limit responses include the time at which you can retry. Rate limits are subject to change. ### Required scopes for write tools Write tools require the `mcp:write` scope to protect your data from unintended changes. When connecting with an API key, your key must grant the **Write** scope under **Model Context Protocol**, and the API key's environment access must include any environment the agent will write to. | Write tool | Required scope | | ---------------------------------- | -------------- | | `create_board`, `update_board` | `mcp:write` | | `create_trigger`, `update_trigger` | `mcp:write` | | `create_slo`, `update_slo` | `mcp:write` | | `create_recipient` | `mcp:write` | | `canvas_agent_invoke` | `mcp:write` | | `feedback` | `mcp:write` | OAuth users get write scopes automatically when they grant write access during the consent flow. To explore full configuration details, visit [Setting Up an API Key](/integrations/mcp/configuration-guide/#setting-up-an-api-key). ## Next steps * [Core Concepts](/integrations/mcp/concepts/): Understand how Honeycomb MCP works. * [Example Use Cases](/integrations/mcp/use-cases/): Review real-world examples of prompts and workflows. * [Troubleshooting](/integrations/mcp/troubleshooting/): Diagnose common issues with tool availability or behavior. # Troubleshooting Honeycomb MCP Source: https://docs.honeycomb.io/integrations/mcp/troubleshooting Resolve common configuration errors with the Honeycomb MCP Server and verify that your AI agent is connected and receiving observability data correctly. If you run into issues while integrating with the MCP server, this guide can help. It covers the most common problems you may encounter and offers steps to help you resolve them quickly. ## Authentication and setup issues These problems usually occur early, during initial setup or while trying to connect using OAuth or API keys. ### OAuth errors or failures **What this means:** Some OAuth clients behave inconsistently across environments or platforms, which can interfere with MCP authentication. **What to do:** If you experience unpredictable behavior with OAuth-based setup, [open a support ticket](https://support.honeycomb.io/) or report the issue in the [Pollinators Slack Community](/troubleshoot/community/). We are actively working to improve compatibility and appreciate your input. ### Server connection problems **What this means:** The MCP server is not responding, or you are unable to establish a connection. **What to do:** * Confirm that you are using the correct endpoint: * US: `https://mcp.honeycomb.io/mcp` * EU: `https://mcp.eu1.honeycomb.io/mcp` * Make sure that your network allows outbound HTTPS traffic. * Check whether any proxies or middleware are interfering with HTTPS requests. ### API key authentication failures **What this means:** Your client is attempting to use an API key, but the request is being rejected. This may be due to formatting issues, platform-specific behavior, or missing permissions. **What to do:** * **Check the format**: Make sure your key is in the form `:`. The colon (`:`) is required. * **Try alternative approaches**: API key handling may vary across environments or clients. * If you are using `mcp-remote`, try concatenating the key ID, key secret, and the word `Bearer`, and passing this via environment variable with string expansion. * Try using native HTTP support (in this example, that would mean passing the `:` string directly as the `Authorization` header). * **Check permissions**: Make sure that your API key includes the necessary permissions. * **Confirm the key is active**: Expired or disabled keys will be rejected. ## Connection issues These issues typically occur when your client fails to authenticate, connect, or access MCP tools successfully. ### "Unauthorized" errors **What this means**: Your client attempted to connect to the MCP server but was rejected due to an authentication error. This can happen when: * Your API key is invalid or malformed * Your authentication headers are incorrect * Your OAuth token is expired or missing **What to do:** If you are using OAuth: 1. Check your active sessions on the **Integrations** tab of your Honeycomb account ([US](https://ui.honeycomb.io/account#integrations), [EU](https://ui.eu1.honeycomb.io/account#integrations)), and confirm that your session exists and includes the `mcp:read` scope. 2. Try re-authenticating through your MCP client to refresh the session. If you are using API keys: 1. Verify both your key ID and key secret. 2. Ensure that your client sets the authentication header correctly. Some clients require the format `Bearer id:secret`, while others expect a concatenated `id:secret` string. ### No tools found or access denied **What this means:** You are authenticated, but none of the tools appear, or all tool calls fail due to authorization errors. This often indicates that Honeycomb Intelligence is not enabled for your Team. **What to do:** Ask your Team Owner to [enable Honeycomb Intelligence](/teams/manage-behavior#enable-honeycomb-intelligence) in your team settings. ### Session timeouts **What this means:** An agent that previously worked is now failing, often after a period of inactivity. MCP agent sessions may time out after 24 hours. If your agent suddenly stops responding or tools begin failing, the session may have expired. **What to do:** Start a new chat with your agent to re-establish the connection. ## Rate limits If your agent returns errors about rate limits, it means you have exceeded the allowed number of requests. ### "Rate Limit Exceeded" error **What this means:** The MCP server is temporarily rejecting requests due to too many recent calls. Per-tool limits vary: most tools share a default of 50 calls per minute, discovery and metadata tools allow higher limits, and expensive or mutating tools (like `get_service_map`, `create_trigger`, and `canvas_agent_invoke`) have lower limits. Rate limits are tied to your authentication method. API key limits apply to all requests made with that key. OAuth limits are per-user, shared across all sessions for that user. To explore the full per-tool matrix, visit [Rate Limits and Scopes](/integrations/mcp/tools/#rate-limits). You might receive an error message like: `Rate limit exceeded, please try again after
releases page for version of honeymarker, which contains binary packages for a variety of platforms. The packages install `honeymarker` to `/usr/bin`. The binary is called `honeymarker`, available if you need it in an unpackaged form or for ad-hoc use. View [`honeymarker`'s source](https://github.com/honeycombio/honeymarker). ### Usage Use the following command format for honeymarker: ```shell theme={} honeymarker -k -d COMMAND [command-specific flags] ``` where: * `` is found on ``. * `` is the name of the dataset for which you want to create the marker. * `COMMAND` is one of [available commands](#available-commands) listed below. For Environment markers, use `__all__` for dataset name. ### Available Commands `honeymarker` has the following commands: | Command | Description | | ---------------------------------- | ---------------- | | [`add`](#add-markers-add) | add a new marker | | [`list`](#list-markers-list) | list all markers | | [`rm`](#delete-markers-rm) | delete a marker | | [`update`](#update-markers-update) | update a marker | ## OpenTelemetry Marker Exporter The OpenTelemetry Collector's [Marker Exporter](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/exporter/honeycombmarkerexporter) allows you to send a [Honeycomb Marker](/configure/environments/manage-markers/) based on the shape of incoming telemetry. In your OpenTelemetry Collector exporter configuration, you can specify a set of rules that will be evaluated against incoming telemetry. When a condition is met, a marker is sent and appears in Honeycomb. For example, whenever a Kubernetes Event contains a `reason` of `Backoff`, the configuration below sends a marker: ```yaml theme={} exporters: honeycombmarker: api_key: YOUR-API-KEY-HERE markers: # Creates a new marker each time the exporter sees a Kubernetes event with a reason of Backoff - type: k8s-backoff-events rules: - log_conditions: - IsMap(body) and IsMap(body["object"]) and body["object"]["reason"] == "Backoff" ``` # Examples: Query for Metrics Source: https://docs.honeycomb.io/investigate/query/examples-metrics Copy and adapt example metrics queries to analyze the performance and behavior of your application using Honeycomb's Query Builder. This page describes Honeycomb event-based metrics. To learn more about time series metrics in Honeycomb, visit [Metrics in Honeycomb](/get-started/honeycomb/metrics-in-honeycomb). Querying metrics requires [sending metrics data to Honeycomb first](/send-data/metrics/). ## Write Queries for Metrics Data Metrics are stored in Honeycomb as fields on events. They can be queried just like any other data in a dataset. However, the kinds of queries typically written for metrics differs from traces. ### Common SELECT Operations Use any of the following common operations in the SELECT clause of [Query Builder](/investigate/query/build/) when visualizing metrics data: * `HEATMAP()` * `AVG()` * `SUM()` * `MAX()` * `MIN()` * `PXX()` We recommend that you combine `HEATMAP` with other Select Operations to get a better sense of trends over time. Refer to the [Select Operations](/investigate/query/build/#select-operations) documentation for more information on these operators. For metrics data, avoid using the `COUNT` SELECT operation. `COUNT` measures the total number of **metrics events** rather than the actual value of a metric. For example, if tracking memory utilization of a host, the `COUNT` operator will **not** show the counter associated with memory utilization over time. Instead, use `HEATMAP(host.memory_bytes)` and `AVG(host.memory_bytes)` to visualize, assuming the instrument that measures memory utilization is called `host.memory_bytes`. ### Track the Rate of Change Tracking the rate at which a measurement changes over time is a common operation when working with metrics data. To do that, use [`RATE_MAX`, `RATE_AVG`, and `RATE_SUM` aggregate operators](/investigate/query/build/visualize-rate/). A common way to query metrics is to have two stacked selection operations, such as: | SELECT | | ------------------------------------------------------------- | | `AVG(host.memory_bytes)`
`RATE_AVG(host.memory_bytes)` | When you select both operations, the results show the average memory utilization over time, and also interesting spikes in the rate of change. ## How Metrics are Stored in Honeycomb ### Values and Fields The values for any given metric event are the measurements collected at the timestamp associated with the event. Multiple metrics appear together as separate fields on the same event if they were received as part of the same OTLP request, have equivalent timestamps when truncated to the second (we truncate metric timestamps to the second for improved compaction), and share the same set of unique resources and attributes. [Find out how Honeycomb converts incoming metrics data into events](/manage-data-volume/adjust-granularity/metrics-event-mapping/). ### Numeric Metrics Counters, gauges, sums, and summary metrics result in single-valued numeric data, and these values show up as individual fields within a metric event, with the field name being the same as the metric name. For example, an application might send metrics for `host.cpu_usage` and `app.memory_bytes`. These names will show up as individual fields in a metrics event. ### Histograms OpenTelemetry (OTel) Histograms contain aggregated data -- a collection of buckets, each of which stores the number of values that were added to that bucket during the reporting period. When ingesting histograms, Honeycomb aggregates them in a different way. It creates a collection of fields with all of which contained in a single event. For a histogram named `latency`, these fields will include these aggregations: | Field | Meaning | | --------------- | ------------------------------------------------ | | `latency.count` | The total number of points | | `latency.sum` | The sum of all the values | | `latency.avg` | The mean (average) of all the values (sum/count) | In addition, Honeycomb records histogram data with fields containing `p` values, which are values that are greater than a given percentage of the data. For example, in a running race involving 10 competitors, `p50` would be the finishing time of the 5th competitor, and `p90` would correspond to the finishing time of the runner who finished 9th. The value for 'p50' is also known as the median in statistics. Here is the full list of `p` values recorded for a histogram named `latency` over OTLP: | p Value | Percentage | | -------------- | ---------- | | `latency.p001` | 0.1% | | `latency.p01` | 1% | | `latency.p05` | 5% | | `latency.p10` | 10% | | `latency.p20` | 20% | | `latency.p25` | 25% | | `latency.p50` | 50% | | `latency.p75` | 75% | | `latency.p80` | 80% | | `latency.p90` | 90% | | `latency.p95` | 95% | | `latency.p99` | 99% | | `latency.p999` | 99.9% | We recommend querying histograms by using `MAX(pValue)`. For example, `MAX(latency.p99)` will show you the worst-case latency measurement for 99% of spans. ## Metrics Correlations It may be useful to view infrastructure metrics for your systems alongside query results from non-metrics datasets. For instance, a system running out of memory, CPU, or network resources might be the reason for an [out-of-compliance SLO](/notify/slos/) or an [alerting trigger](/notify/triggers/), and seeing the graph of the problem alongside graphs of relevant system resources could confirm or deny this kind of hypothesis. Define a [Board](/observe/boards/) of the relevant metric queries you want to see in relation to other data, and then use [**Correlations**](/investigate/analyze/correlate/) when using [Query Builder](/investigate/query/build/) to view and compare your query results with up to six saved queries on a Board. # Examples: Query for Traces Source: https://docs.honeycomb.io/investigate/query/examples-traces Copy and adapt example trace queries to analyze the performance and behavior of your application using Honeycomb's Query Builder. Use the query examples below to explore the performance and behavior of your application. The specific attributes below may or may not exist in your data and environment. Enter each example query using the [Query Builder](/investigate/query/build/). These example queries use two to three of the `SELECT`, `WHERE`, and `GROUP BY` clauses, located at the top of the Query Builder. * `SELECT` - Performs a calculation and displays a corresponding graph over time. Most `SELECT` queries return a line graph while the `HEATMAP` visualization shows the distribution of data over time * `WHERE` - Filters based on attribute parameter(s) * `GROUP BY` - Groups fields by attribute parameter(s) Screenshot of Select, Where, and Group by clauses in Query Builder ## Number of Total Root Spans This query calculates the total number of root spans received by your application by looking for all spans without a parent span ID. | SELECT | WHERE | | ------ | -------- | | COUNT | is\_root | `is_root` is an alias for `trace.parent_id does not exist`, and when used with a **WHERE** clause, both filter to show only root spans. If `trace.parent_id does not exist` is used, Honeycomb automatically updates it to `is_root` in Query Builder. ## Performance Metrics ### What are the Slowest Traces in the Application This query identifies the slowest trace in your application, in terms of duration (`duration_ms`), and provides information about the specific events and spans that make up that trace. | SELECT | WHERE | GROUP BY | | ----------------- | -------- | -------- | | MAX(duration\_ms) | is\_root | name | Use to: * to find potential performance issues * understand the root cause of slow response times ### What is the P90 Duration of Database Calls This query calculates the `P90` duration of your database calls, which is the duration at which 90% of your database calls complete. | SELECT | WHERE | GROUP BY | | ----------------- | ------------------- | ------------ | | P90(duration\_ms) | db.statement exists | db.statement | Use to: * understand the performance of your database * identify potential issues or bottlenecks ### What are the Total Bytes Sent on Requests This query calculates the total bytes sent on requests, which is the total amount of data that is transmitted by your service in response to requests. `HEATMAP` creates a histogram data visualization. Use [BubbleUp](/investigate/analyze/identify-outliers/) to further investigate and compare values. | SELECT | WHERE | GROUP BY | | -------------------------------------------------------------------------------- | ------------------------------------ | -------- | | SUM(http.request\_content\_length)
HEATMAP(http.request\_content\_length) | http.request\_content\_length exists | name | Use to: * understand the performance and efficiency of your service * analyze your data further with BubbleUp ### How Much Time Database Calls Take in a Trace This query provides insight into the performance of your application. If a significant amount of time is spent on database calls, opportunity to improve speed and performance in the way that your application interacts with the database. | SELECT | WHERE | GROUP BY | | ----------------- | --------------------------------------------------- | ------------ | | SUM(duration\_ms) | db.statement exists
trace.trace\_id = abc123 | db.statement | ### What is the Rate at Which the Average Duration for the Service Increases or Decreases This query calculates the rate of change in the average amount of time that it takes for your service to complete a request. | SELECT | WHERE | GROUP BY | | ----------------------- | -------- | -------- | | RATE\_AVG(duration\_ms) | is\_root | name | Use to: * understand the performance of your service * identify potential trends or patterns in the duration of your service's requests ### Identify Errors Based on API Entry Point This query uses [relational fields](/investigate/query/build/#relational-fields) to identify errors in the system filtered by top-level API entry point. | SELECT | WHERE | GROUP BY | | ------ | ------------------------------------------------------------------------------------------------------------------- | -------- | | COUNT | error exists AND
meta.annotation\_type = span\_event AND
root.api\_entry\_point = `` | name | ### Find Properties in a Child Span and Group By the Root Span This query uses [relational fields](/investigate/query/build/#relational-fields) to identify the P95 of database SELECT \* statements and find the http.route from which they are being called. | SELECT | WHERE | GROUP BY | | ----------------- | ---------------------------------- | --------------- | | P95(duration\_ms) | db.statement starts with select \* | root.http.route | ### Identify Slow Database Calls for a Service This query uses [relational fields](/investigate/query/build/#relational-fields) to identify slow database calls for a service. | SELECT | WHERE | | ----------------- | ------------------------------------------------------------- | | AVG(duration\_ms) | duration\_ms > 10000 AND
root.service = /cart/checkout | ## Error Analysis ### Which Exception Happens the Most in the Service This query provides insight into potential problems in your system. For example, when running a web service that processes online transactions and the most frequent exception being thrown is "TimeoutException", then your service may have issues connecting to the database to retrieve information about the transactions. | SELECT | WHERE | GROUP BY | | ------ | ------------------------ | ----------------- | | COUNT | exception.message exists | exception.message | ### Which Spans Contain Which Exceptions Some OpenTelemetry instrumentation or SDKs will record exception messages on Span Events rather than on the Span itself. This query identifies which Span Events events contain exceptions, and then groups by the name of the Span that corresponds to that Span Event, the name of the service, and then the name of the exception. | SELECT | WHERE | GROUP BY | | ------ | --------------------------------------------------- | --------------------------------------------------------- | | COUNT | parent\_name exists
exception.message exists | parent\_name
service.name
exception.message | ### Show Only Errored Traces and Their Latency This query helps to investigate the reasons for errors and latencies. For example, if you know that a errored trace called "XYZ" experiences high latencies, you can take further steps like debugging the code for that trace, adding more resources to handle the workload, or implementing error handling and retry mechanisms. | SELECT | WHERE | GROUP BY | | ---------------------------------- | ---------------------------- | -------- | | COUNT
HEATMAP(duration\_ms) | error = true
is\_root | name | ### Which Tenants Experience Errors on Certain Endpoints This query identifies which tenants, or specific groups of users or data within a software system, experience endpoint errors. With this knowledge, you can provide specialized support and troubleshooting to help resolve the issue. For example, when running a storage service with multiple tenants, you notice that a particular tenant experiences a high number of errors when accessing their data on your endpoint. This may indicate that a problem exists with their configuration or usage of your service. | SELECT | WHERE | GROUP BY | | ------ | ----------------------------------------------------- | ---------------------- | | COUNT | error = true
is\_root
app.tenant exists | app.tenant
name | ### Identify Errors Based on API Entry Point This query uses [relational fields](/investigate/query/build/#relational-fields) to identify errors in the system filtered by top-level API entry point. | SELECT | WHERE | | ------ | ---------------------------------------------------------------- | | COUNT | error exists AND
root.api\_entry\_point = api-entry-point | ### Identify User Log in Error This query uses [relational fields](/investigate/query/build/#relational-fields) to identify a user who reported that they cannot log in. The `user_id` is only on the root span, but the error in the auth service exists on a child span within the trace. | SELECT | WHERE | | ------ | ------------------------------------------------------------------------------------------ | | COUNT | root.user\_id = `` AND
error exists AND
service.name = LoginService | ### Get a Count of Root Spans with a Child Span that Contains an Error This query uses [relational fields](/investigate/query/build/#relational-fields) to identify root spans that have a child span that has an error. | SELECT | WHERE | GROUP BY | | ------ | ------------------------------------ | -------- | | COUNT | is\_root AND
any.error exists | name | ### Show How Requests to a Service Behave When Another Service in the Trace Experiences a Specific Error This query uses [relational fields](/investigate/query/build/#relational-fields) to show how requests to a service behave when another service in the trace experiences a specific error. | SELECT | WHERE | | ------ | ------------------------------------------------------------------------------------------------------------------ | | COUNT | service.name = `` AND
any.service.name = `` AND
any.error = `` | ### Identify Errors from Database Spans for Traces that Reach a Certain Duration This query uses [relational fields](/investigate/query/build/#relational-fields) to return the error from database spans for traces longer than a specified duration. | SELECT | WHERE | | ------ | --------------------------------------------------------------------------------------- | | COUNT | root.duration\_ms > `` AND
name = db.statement AND
error exists | ### Find Spans that Contain Timeout Errors Where Immediate Parent Span Initiated a Database Call This query uses [relational fields](/investigate/query/build/#relational-fields) to identify spans that contain a timeout error and their immediate parent span initiated a database call. | SELECT | WHERE | | ------ | --------------------------------------------------------------------- | | COUNT | error\_code = TimeoutError AND
parent.operation = DatabaseCall | ## Instrumentation Gap Detection To detect where an instrumentation gap exists. ### Identify Missing Field That Should Exist This query uses [relational fields](/investigate/query/build/#relational-fields) to identify a field that should exist, but currently does not or has no value. | SELECT | WHERE | | ------ | ------------------------------------------------------------ | | COUNT | `` does-not-exist AND parent.`` does-not-exist | Use to: * figure out why a specific field (or set of fields) is missing on several spans. ## User Behavior ### What is the Number of Requests per Time Period This query calculates the total number of requests received by your application, and provides a breakdown of those requests by different dimensions, such as the type of request, the endpoint, or the tenant. | SELECT | WHERE | GROUP BY | | ------ | -------- | -------- | | COUNT | is\_root | name | Use to: * monitor the overall traffic and usage of your application ### What is the Number of Concurrent Calls for a Specific Span This query calculates the number of concurrent calls for the individual, specific span named `my-span`, which is the number of calls to that span that are executing simultaneously. | SELECT | WHERE | | ----------- | -------------- | | CONCURRENCY | name = my-span | Use to: * understand the workload and performance of your span * identify potential issues or bottlenecks that may be affecting the concurrency of your calls ### What is the Number of Distinct Users in the Application This query displays the level of demand on your system and the resources it uses. If the number of distinct users increases over time, it may indicate that your system is approaching its capacity and that action may be needed to improve its performance. | SELECT | WHERE | | ----------------------------- | ------------------- | | COUNT\_DISTINCT(app.user\_id) | app.user\_id exists | ## Endpoint Usage ### What is the Load Across Each Server This query calculates the number of executed, independent traces on each server. | SELECT | WHERE | GROUP BY | | ------ | -------- | --------- | | COUNT | is\_root | host.name | Use to: * understand the workload and performance of your servers * identify potential issues or bottlenecks ### Which Tenant hits Each Endpoint the Most and Their Highest Experienced Latency The query identifies tenants, or specific groups of users or data within a software system, the endpoints they use, and their maximum experienced latency. For example, if you know that a certain tenant hits endpoint `/api/users` the most and experiences high latencies on that endpoint, you can investigate the reasons for those latencies and take steps to improve the performance of that endpoint for that tenant. | SELECT | WHERE | GROUP BY | | ------------------------------ | --------------------------------- | ---------------------- | | COUNT
MAX(duration\_ms) | is\_root
app.tenant exists | app.tenant
name | ### High CPU Usage with User Login Request This query uses [relational fields](/investigate/query/build/#relational-fields) to identify spans with high CPU usage where the root span has an operation of "UserLoginRequest". | SELECT | WHERE | | --------------- | ------------------------------------------------------------- | | AVG(cpu\_usage) | root.operation = UserLoginRequest AND
cpu\_usage > 0.8 | ## Advanced Visualization ### Distribution Density of Status Codes Over Time This query presents the frequency and density of different status codes that are returned by your application during a specified time period. `HEATMAP` creates a histogram data visualization. Use [BubbleUp](/investigate/analyze/identify-outliers/) to further investigate and compare values. | SELECT | WHERE | GROUP BY | | -------------------------- | ------------------------ | -------- | | HEATMAP(http.status\_code) | http.status\_code exists | name | Use to: * understand the performance and behavior of your application * analyze your data further with BubbleUp ## Relational Fields These queries use [relational fields](/investigate/query/build/#relational-fields) for advanced filtering. To learn about more best practices, visit [Best Practices for Querying using Relational Fields](/get-started/best-practices/relational-fields/). ### `root` prefix #### Identify Errors Based on API Entry Point This query uses [relational fields](/investigate/query/build/#relational-fields) to identify errors in the system filtered by top-level API entry point. | SELECT | WHERE | GROUP BY | | ------ | ------------------------------------------------------------------------------------------------------------------- | -------- | | COUNT | error exists AND
meta.annotation\_type = span\_event AND
root.api\_entry\_point = `` | name | #### Identify Errors from Database Spans for Traces that Reach a Certain Duration This query uses [relational fields](/investigate/query/build/#relational-fields) to return the error from database spans for traces longer than a specified duration. | SELECT | WHERE | | ------ | --------------------------------------------------------------------------------------- | | COUNT | root.duration\_ms > `` AND
name = db.statement AND
error exists | #### Find Properties in a Child Span and Group By the Root Span This query uses [relational fields](/investigate/query/build/#relational-fields) to identify the P95 of database SELECT \* statements and find the http.route from which they are being called. | SELECT | WHERE | GROUP BY | | ----------------- | ---------------------------------- | --------------- | | P95(duration\_ms) | db.statement starts with select \* | root.http.route | #### Identify Slow Database Calls for a Service This query uses [relational fields](/investigate/query/build/#relational-fields) to identify slow database calls for a service. | SELECT | WHERE | | ----------------- | ------------------------------------------------------------- | | AVG(duration\_ms) | duration\_ms > 10000 AND
root.service = /cart/checkout | #### Identify Errors Based on API Entry Point This query uses [relational fields](/investigate/query/build/#relational-fields) to identify errors in the system filtered by top-level API entry point. | SELECT | WHERE | | ------ | ---------------------------------------------------------------- | | COUNT | error exists AND
root.api\_entry\_point = api-entry-point | #### Identify User Log in Error This query uses [relational fields](/investigate/query/build/#relational-fields) to identify a user who reported that they cannot log in. The `user_id` is only on the root span, but the error in the auth service exists on a child span within the trace. | SELECT | WHERE | | ------ | ------------------------------------------------------------------------------------------ | | COUNT | root.user\_id = `` AND
error exists AND
service.name = LoginService | #### Identify Errors from Database Spans for Traces that Reach a Certain Duration This query uses [relational fields](/investigate/query/build/#relational-fields) to return the error from database spans for traces longer than a specified duration. | SELECT | WHERE | | ------ | --------------------------------------------------------------------------------------- | | COUNT | root.duration\_ms > `` AND
name = db.statement AND
error exists | #### High CPU Usage with User Login Request This query uses [relational fields](/investigate/query/build/#relational-fields) to identify spans with high CPU usage where the root span has an operation of "UserLoginRequest". | SELECT | WHERE | | --------------- | ------------------------------------------------------------- | | AVG(cpu\_usage) | root.operation = UserLoginRequest AND
cpu\_usage > 0.8 | ### `parent` prefix #### Identify Missing Field That Should Exist This query uses [relational fields](/investigate/query/build/#relational-fields) to identify a field that should exist, but currently does not or has no value. | SELECT | WHERE | | ------ | ------------------------------------------------------------ | | COUNT | `` does-not-exist AND parent.`` does-not-exist | Use to: * figure out why a specific field (or set of fields) is missing on several spans. #### Find Spans that Contain Timeout Errors Where Immediate Parent Span Initiated a Database Call This query uses [relational fields](/investigate/query/build/#relational-fields) to identify spans that contain a timeout error and their immediate parent span initiated a database call. | SELECT | WHERE | | ------ | --------------------------------------------------------------------- | | COUNT | error\_code = TimeoutError AND
parent.operation = DatabaseCall | ### `child` prefix #### Select P99 Duration for a Span Only When it has Called into Another Specific Span You have a span named `spanA` that sometimes has a child named `spanB`. You want to select the P99 of `spanA` when it has called into `spanB`. | SELECT | WHERE | GROUP BY | ORDER BY | LIMIT | | ----------------- | ------------------------------------- | -------- | ---------------------- | ----- | | P99(duration\_ms) | name = spanA
child.name exists | None | P99(duration\_ms) desc | 100 | #### Select Sampling of Children for a Given Span You have a span named `spanA` that may call a number of different operations. You want to see a list/sampling of the functions into which it calls directly. | SELECT | WHERE | GROUP BY | ORDER BY | LIMIT | | ------ | ------------ | ---------- | ---------- | ----- | | COUNT | name = spanA | child.name | COUNT desc | 100 | ### `none` prefix #### Find All Traces with a Missing Root Span You want to find all traces that are missing a root span. This can help you identify where your instrumentation may need some troubleshooting. | SELECT | WHERE | GROUP BY | ORDER BY | LIMIT | | ------ | ------------------------------------ | --------------- | ---------- | ----- | | COUNT | none.trace.parent\_id does-not-exist | trace.trace\_id | COUNT desc | 1000 | #### Find Instances of a Process Where No Retry Succeeded You have a process named `ProcessA` that may retry multiple times if it fails, before giving up (and for example, executing a rollback). This means that you might have a few instances of the same pattern repeat in your trace. If the process succeeds, one of them will also contain a success span named `Commit`. You want to find instances where none of the retries succeeded, and examine the root spans that kicked off those instances to explore patterns that might emerge. | SELECT | WHERE | GROUP BY | | ------ | ----------------------------------------- | -------------------------------- | | COUNT | name = ProcessA
none.name = Commit | trace.trace\_id
root.name | ### `anyX` prefix #### Show How Requests to a Service Behave When Another Service in the Trace Experiences a Specific Error This query uses [relational fields](/investigate/query/build/#relational-fields) to show how requests to a service behave when another service in the trace experiences a specific error. | SELECT | WHERE | | ------ | ------------------------------------------------------------------------------------------------------------------ | | COUNT | service.name = `` AND
any.service.name = `` AND
any.error = `` | #### Get a Count of Root Spans with a Child Span that Contains an Error This query uses [relational fields](/investigate/query/build/#relational-fields) to identify root spans that have a child span that has an error. | SELECT | WHERE | GROUP BY | | ------ | ------------------------------------ | -------- | | COUNT | is\_root AND
any.error exists | name | #### Find Traces that Contain a Specific 3-way Combination You do not know your exact trace structure, but you have a hypothesis that a certain function call (`functionA`) and a certain database transaction (`db.rollback`) might both be related to some `500` errors that you are seeing. You want to find traces where: * `status_code` is returned as `500` * `functionA` is called at some point in the trace * `db.rollback` is called at some point in the trace | SELECT | WHERE | GROUP BY | | ------ | ------------------------------------------------------------------------------------------- | --------------- | | COUNT | any.response.status\_code = 500
any2.name = functionA
any3.name = db.rollback | trace.trace\_id | #### Identify the location of a data/field within a trace You do not know your exact trace structure, but you want to see customer team names and their device platform alongside some data you are looking at from a service named `ServiceA`. Team name and device platform are not available on the spans you are currently targeting, but they may be available on other spans (`team.name` is available on one specific span, `platform` is available on another specific span). | SELECT | WHERE | GROUP BY | | ------ | ------------------------------------------------------------------------------- | ---------------------------------- | | COUNT | service.name = ServiceA
any.team.name exists
any2.platform exists | any.team.name
any2.platform | # Query Math Source: https://docs.honeycomb.io/investigate/query/math Build queries from multiple statements, perform math between them, and visualize the final result. ## Introduction Query Math adds support for multi-step queries in Honeycomb. You can now define multiple query steps, perform math between them, and visualize the final result—all inline in the Query Builder. This feature helps you express richer queries without creating temporary calculated fields. Instead of building complex calculated field expressions, you can break down your analysis into logical steps and combine them using simple mathematical formulas. Use Query Math to: * Calculate ratios and percentages directly in your query * Combine multiple aggregates (for example, error counts and request totals) * Perform time-series math with functions like `RATE()` and `INCREASE()` * Simplify complex calculated fields into inline formulas * Compare conditional aggregations side by side ## How it works Query Math lets you create multiple query steps, such as Step A and Step B—each with its own **SELECT**, **WHERE**, and **GROUP BY** clauses. You can then define a formula that references these steps using variables like `$A`, `$B`, and so on. When you run the query, Honeycomb: 1. Executes each step independently. 2. Evaluates your formula using the results from each step. 3. Visualizes the final result. Only the final formula result appears in your visualization. To see individual step results, remove the formula from your query. ## Using Query Math To build a query with Query Math: 1. Select **Query** () from the navigation menu. 2. Define your first step (Step A): 1. Select fields in the **SELECT** clause. 2. Add filters in the **WHERE** clause. 3. Optionally, add groupings in the **GROUP BY** clause. 3. Select **Add Query** to create additional steps (for example, Step B). 4. Select **Add Formula** to define the mathematical relationship between your query steps. 5. In the formula editor, reference your steps using `$A`, `$B`, and so on, and combine them using mathematical operators. 6. Select **Run Query** to see the result. All query steps must use the same **GROUP BY** dimensions. For example, if Step A groups by `k8s.pod.name`, then Step B must also group by `k8s.pod.name`. Screenshot of Query Builder, showing two query steps (A) and (B), and a query math formula (C) ## Supported operators in query formulas Query formulas support standard mathematical operators in infix notation: | Operator | Description | Example | | -------- | ------------------------ | ---------------- | | `+` | Addition | `$A + $B` | | `-` | Subtraction | `$A - $B` | | `*` | Multiplication | `$A * $B` | | `/` | Division | `$A / $B` | | `()` | Parentheses for grouping | `($A + $B) / $C` | You can combine these operators to create complex formulas: ```js theme={} (($A / $B) * 100) ``` Include spaces around arithmetic operators to ensure that the formula parses correctly. ## Query math examples These examples demonstrate common use cases for Query Math. Each shows how to structure your query stages and combine them with formulas. ### Error rate Compute the percentage of all requests that resulted in `500` errors. **Step A**: * `SELECT COUNT` * `WHERE status = 500` **Step B**: * `SELECT COUNT` **Formula C**: ```js theme={} ($A / $B) * 100 ``` ### Success rate Calculate the percentage of successful requests (non-error status codes). **Step A**: * `SELECT COUNT` * `WHERE status < 400` **Step B**: * `SELECT COUNT` **Formula C**: ```js theme={} ($A / $B) * 100 ``` ### Memory utilization percentage Calculate the percentage of available memory that is currently in use, which makes it easier to identify which pods are approaching capacity. **Step A**: * `SELECT MAX(k8s.pod.memory.usage)` **Step B**: * `SELECT MAX(k8s.pod.memory.available)` **Formula C**: ```js theme={} ($A / ($A / $B)) * 100 ``` ### Request rate difference Compare the request rate between two services, which can help you identify load imbalances. **Step A**: * `SELECT AVG(request_rate)` (create query-scoped calculated field `request_rate` with definition `RATE($http.server.requests)`) * `WHERE service.name = "api"` **Step B**: * `SELECT AVG(request_rate)` * `WHERE service.name = "frontend"` Query-scoped calculated fields defined in any step are automatically available in all other steps within the same query. **Formula C**: ```js theme={} $A - $B ``` ### CPU utilization Combine different temporal aggregation functions to analyze metric behavior. This query compares the current CPU utilization snapshot against the rate of change, helping you understand CPU usage patterns. **Step A**: * `SELECT AVG(last_cpu)` (create query-scoped calculated field `last_cpu` with definition `LAST($k8s.pod.cpu.utilization)`) **Step B**: * `SELECT AVG(rate_cpu)` (create query-scoped calculated field `rate_cpu` with definition `RATE($k8s.pod.cpu.time)`) **Formula C**: ```js theme={} $A / $B ``` ## Working with Groupings When using **GROUP BY** in Query Math, all query statements must group by the same dimensions. If your query statements have different **GROUP BY** clauses, the query will fail. For example, if you want to calculate error rates per route: **Step A**: * `SELECT COUNT` * `WHERE status >= 400` * `GROUP BY http.route` **Step B**: * `SELECT COUNT` * `GROUP BY http.route` **Formula C**: ```js theme={} ($A / $B) * 100 ``` Honeycomb evaluates the formula for each unique value of `http.route`, producing a separate result for each route. ## Combining with Temporal Aggregation Query Math works seamlessly with [temporal aggregation functions](/investigate/query/temporal-aggregation/). You can use `RATE()`, `INCREASE()`, `SUMMARIZE()`, and `LAST()` in your query steps, then perform math across the results. For example, to calculate your error rate as a percentage of total throughput: **Step A**: * `SELECT SUM(error_rate)` (create query-scoped calculated field `error_rate` with definition `RATE($http.server.errors)` ) **Step B**: * `SELECT SUM(request_rate)` (create query-scoped calculated field `request_rate` with definition `RATE($http.server.requests)`) **Formula C**: ```js theme={} ($A / $B) * 100 ``` This query shows what percentage of your requests per second are errors, using temporal aggregation to normalize both metrics to per-second rates before calculating the ratio. ## Visualizing results When you add a formula to your query, only the formula result appears in the visualization. This keeps your charts focused on the final calculated value. If you want to see the individual step results: 1. Remove the formula temporarily. 2. Run the query to see each step's results independently. 3. Add the formula back when ready. This workflow is useful for debugging or validating intermediate results before combining them. ## Tips for building multi-statement queries Use these strategies to build effective Query Math queries: * **Start simple**: Build and test each query statement individually before adding a formula. * **Use descriptive calculated field names**: Names like `error_rate` or `memory_util` make steps easier to understand. * **Validate groupings**: Ensure all statements use identical **GROUP BY** clauses to avoid query errors. * **Test incrementally**: Add one formula operation at a time to isolate any issues. * **Use parentheses**: Explicitly group operations to control evaluation order, especially in complex formulas. # Temporal Aggregation Concepts Source: https://docs.honeycomb.io/investigate/query/temporal-aggregation Find out how Honeycomb uses temporal aggregation to align raw metric data into consistent time steps for accurate analysis and visualization. Explore how temporal aggregation shapes metrics data for visualization and analysis. ## Introduction When working with metrics, time alignment is key. Metrics data arrives as timeseries—streams of values for a single metric, segmented by attributes like `http.route` or `k8s.node.name`. Raw metric values often arrive at irregular intervals, making direct comparison or visualization challenging. Additionally, some metrics are reported as monotonic sums, where the meaningful insight comes from the difference between consecutive values over a time period, while correctly handling counter resets when values jump back to zero. Raw values may also represent measurements over varying time ranges—the interval between the current and previous capture—which may not align neatly with the fixed time steps used in your queries. Honeycomb solves this by using temporal aggregation: a process that reshapes raw timeseries values into regularly spaced, query-aligned values. ## What is Temporal Aggregation? Temporal aggregation groups raw metric values into fixed-duration time steps and applies a summarizing function to each group. A step represents one slice of time in your query, like a single minute in a one-minute granularity query. Honeycomb collects all the raw metric values that fall within that step and applies a temporal aggregation function, such as `LAST()`, `INCREASE()`, `RATE()`, or `SUMMARIZE()`, to compute a single value per timeseries for that time slice. The result is a time-aligned series of points that you can cleanly visualize or group by attribute like route or node. Without temporal aggregation, your charts would be incomplete, misaligned, or misleading, especially when comparing multiple timeseries. ## How It Works When you run a metrics query, Honeycomb automatically: 1. Takes into account the relevant timeseries based on the filters and time-range of your query. Each unique combination of metric and attributes (for example, `http.server.request.count` by `http.route` and `k8s.node.name`) is stored as its own timeseries when your instrumentation reaches Honeycomb. 2. Divides the query's time range into evenly-spaced steps using the desired granularity (for example, 60-second intervals). 3. Applies a temporal aggregation function to each timeseries within each step to produce a single value per step. This step-aligned output forms the foundation for your charts, groupings, and further analysis. ### Example Suppose you are tracking memory usage across multiple hosts with the gauge `process.memory.usage`, collected every 10 seconds. If you query it over a two-hour range with one-minute granularity, Honeycomb will: * Divide the time range into 120 one-minute steps, * Pull the six data points per minute from each host, * Apply the `LAST()` function to each group of six values, * Return one value per minute, per host. ## Why It Matters: Preparing for Spatial Aggregation Once temporal aggregation aligns your timeseries in time, Honeycomb can group and summarize across dimensions like route, node, or service. This step is known as spatial aggregation; it aggregates across multiple timeseries at the same time step to produce a single summarized value per group. In Honeycomb, spatial aggregation corresponds to the operations you define in the **SELECT** clause. For example, if you group your query by `http.route`, Honeycomb first aligns all timeseries that share the same value for `http.route` to the same time steps, then computes a percentile or average across those aligned series. Spatial aggregation depends on clean, aligned time steps, so temporal aggregation always comes first. ## Understanding Monotonicity and Temporality All metric types include extra metadata that hints at how they should be aggregated over time. These properties guide how aggregations should be applied: * **Monotonicity** describes whether a sum metric only increases or can go both up and down. * **Monotonic**: The value always increases or resets to zero (for example, total requests served). * **Non-monotonic**: The value may increase or decrease (for example, queue length). * **Temporality** describes what each data point represents in time. * **Cumulative**: Each value represents the total since the start of the measurement. * **Delta**: Each value represents the change since the previous measurement. Honeycomb supports both cumulative and delta metrics natively, unlike some legacy metrics systems that forced users to choose one. This flexibility lets you use your existing data as is, and use aggregation functions to generate different views, which reduces complexity at ingest time. ## Supported Temporal Aggregation Functions Honeycomb supports four core temporal aggregation functions. Each one reshapes raw metrics into time-aligned results that suit different types of analysis. To learn how Honeycomb applies these functions and how you can override them when needed, visit [Applying Temporal Aggregation Functions](/investigate/query/apply-temporal-aggregation/). ### `LAST(metric)` `LAST(metric)` returns the most recent data point in each step. Use this function for metrics that represent a current state or sample, such as memory usage or thread count. It can also be used for non-monotonic sums, where values may fluctuate up and down. Example: Show the last reported memory usage per node every minute. ### `SUMMARIZE(metric)` `SUMMARIZE(metric)` adds up all values within each time step. If a value spans multiple steps, Honeycomb interpolates to distribute the value proportionally. This function is best for delta-style metrics that track a count or total within a given window, like requests received, log entries written, or bytes transferred. For histograms, `SUMMARIZE()` adds the values in each bucket independently, preserving the bucket structure across time steps. Example: Count the total number of HTTP requests per minute across all Kubernetes pods. ### `INCREASE(metric[, range_interval_seconds])` `INCREASE(metric[, range_interval_seconds])` measures the change in a metric's value across a range. It [handles counter resets](#handling-counter-resets) automatically and interpolates to match the range's boundaries. Use this function for monotonic, cumulative metrics where the total always increases, like total bytes sent or number of connections handled. For histograms, `INCREASE()` calculates the difference for each bucket independently, as well as for the total value. If data points are missing at interval boundaries, Honeycomb will extrapolate, but only up to half the duration of a captured interval. This avoids overestimating changes when samples are dropped. Example: Calculate the total number of errors over time, even if the service restarts. ### `RATE(metric[, range_interval_seconds])` `RATE(metric[, range_interval_seconds])` calculates the per-second rate of change over the time range. It works just like `INCREASE()`, but divides the result by the time range to get a rate. This function is useful for smoothing spikes or understanding trends as normalized rates. Example: Track request throughput as requests per second, even if raw request counts vary dramatically. ## Understanding the `range_interval_seconds` Argument Some temporal aggregation functions accept an optional `range_interval_seconds` argument. This argument controls the size of the window Honeycomb uses to calculate changes over time. Use `range_interval_seconds` to make temporal aggregation more resilient to sparse data or uneven reporting intervals. By default, Honeycomb uses the query’s granularity, or time step, as the range interval, but sometimes, you may want to override this default to get more accurate results. By setting `INCREASE(metric, 300)`, you allow Honeycomb to look back over a five-minute window when calculating the increase for each step. Use `range_interval_seconds` when: * You want to smooth results by averaging or increasing over a longer time window. * You want consistent results even if you zoom in or zoom out of your graph. * You are troubleshooting gaps or unexpected zero values in your charts. ## Handling Counter Resets The `INCREASE()` function is designed for monotonic cumulative metrics, which are metrics that count up over time, like total requests served or bytes sent. But sometimes counters reset, such as during service restarts or container redeployments. When this happens, a raw difference calculation would produce a misleading negative value. Honeycomb automatically detects and corrects for these resets: * If a later value is lower than an earlier one within the same step, Honeycomb treats it as a reset and starts counting from the new value. * If the data point includes a start time (as with OpenTelemetry) and that start time changes, Honeycomb treats this as a reset, even if the new value is higher than the previous one. * Instead of returning a negative delta, Honeycomb calculates the increase from zero after the reset. This logic ensures that your results reflect real activity, not artifacts from service restarts or instrumentation quirks. A counter reports these values during a one-minute step: ```text theme={} 10:01:05 — 8,450 10:01:30 — 8,700 10:01:45 — 250 ← service restarted ``` Without reset handling, the calculation would incorrectly show a drop of 8,450. With `INCREASE()`, Honeycomb computes: * +250 from 8,450 to 8,700 * Reset detected * +250 from the restart point (250, assumed 0) This leads to a total increase of 500. # Metrics-to-Event Mapping Source: https://docs.honeycomb.io/manage-data-volume/adjust-granularity/metrics-event-mapping Find out how Honeycomb converts incoming metrics data points into events, including how data points are combined and stored in the columnar data store. This page describes Honeycomb event-based metrics. To learn more about time series metrics in Honeycomb, visit [Metrics in Honeycomb](/get-started/honeycomb/metrics-in-honeycomb). Honeycomb stores these data points, and all associated metadata (the resources and attributes) in events within our columnar data store. Honeycomb will combine data points into the same event if: * they were received as part of the same OTLP request * their timestamps are equivalent when truncated to the second (we truncate metric timestamps to the second for improved compaction) * they have the same set of resource attribute keys and values * they have the same set of data point attribute keys and values (sometimes these are also called "tags" or "labels") ## Combining Across Metric Streams Given a single metrics request that contains the following data: ```yaml theme={} Resource: - service.name: greyhound - host.name: greyhound-9ab3f2 - cloud.availability_zone: us-east-1c Metric: system.cpu.utilization.user - Timestamp: 1623110537 # 1970-01-01 00:00:01.623110537 +0000 UTC Value: 34 Metric: system.cpu.utilization.system - Timestamp: 1823110538 # 1970-01-01 00:00:01.823110538 +0000 UTC Value: 8 Metric: runtime.go.goroutines - Timestamp: 1623110537 Value: 635 Metric: runtime.go.gc.count - Timestamp: 1823110538 Value: 321 ``` Honeycomb will store a single event that contains the following data: ```yaml theme={} - Timestamp: 1000000000 # 1970-01-01 00:00:01 +0000 UTC service.name: greyhound host.name: greyhound-9ab3f2 cloud.availability_zone: us-east-1c system.cpu.utilization.user: 34 system.cpu.utilization.system: 8 runtime.go.goroutines: 635 runtime.go.gc.count: 321 ``` Both of the timestamps on the above metrics (1623110537 and 1823110538) take place within the first second of the unix epoch. When processed by Honeycomb, the timestamps will be truncated to the second, meaning they will both become 1000000000 (1970-01-01 00:00:01 +0000 UTC). Since the metrics share the same labels and truncated timestamp, we are able to combine them into a single Honeycomb event. ## Splitting by Metric Attributes Given a single metrics request that contains the following data: ```yaml theme={} Resource: - service.name: greyhound - host.name: greyhound-9ab3f2 - cloud.availability_zone: us-east-1c Metric: system.cpu.utilization - Timestamp: 1623110537 # 1970-01-01 00:00:01.623110537 +0000 UTC Attributes: - cpu: cpu1 - state: user Value: 34 - Timestamp: 1623110537 Attributes: - cpu: cpu1 - state: system Value: 8 Metric: runtime.go.goroutines - Timestamp: 1623110537 Value: 635 Metric: runtime.go.gc.count - Timestamp: 1623110537 Value: 321 ``` Honeycomb will store three events that contain the following data: ```yaml theme={} - Timestamp: 1000000000 # 1970-01-01 00:00:01 +0000 UTC system.cpu.utilization: 34 service.name: greyhound host.name: greyhound-9ab3f2 cloud.availability_zone: us-east-1c cpu: cpu1 state: user - Timestamp: 1000000000 system.cpu.utilization: 8 service.name: greyhound host.name: greyhound-9ab3f2 cloud.availability_zone: us-east-1c cpu: cpu1 state: system - Timestamp: 1000000000 service.name: greyhound host.name: greyhound-9ab3f2 cloud.availability_zone: us-east-1c runtime.go.goroutines: 635 runtime.go.gc.count: 321 ``` # Manage Metrics Events Source: https://docs.honeycomb.io/manage-data-volume/adjust-granularity/metrics-events Control how many events your metrics data generates in Honeycomb by adjusting capture intervals, label counts, and which metrics you send. This page describes Honeycomb's legacy event-based metrics implementation. To learn more about time series metrics in Honeycomb, visit [Metrics in Honeycomb](/get-started/honeycomb/metrics-in-honeycomb). Several factors affect the number of events created by your metric data: * number of metrics captured * capture interval * number of labels you apply to metrics Since metrics are captured regularly, the event volume used for metrics can be predicted and controlled over time. To control event volume you can change: * How many events are [generated by each metric capture](#events-generated-by-each-metric-capture) * How often those metrics are sent, or the [capture interval](#modifying-capture-interval) Honeycomb automatically compacts some event volume based on [data point attributes](#data-point-attribute-compaction), including [`system.cpu.time` and `system.cpu.utilization`](#compaction-of-systemcputime-and-systemcpuutilization). ## Events Generated by Each Metric Capture Every metric data point is associated with a [resource](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/overview.md#resources), representing the system that it describes, and any number of [attributes](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/common/README.md), providing additional context about the meaning of that data point. Honeycomb stores these data points, and all associated metadata (the resources and attributes) in events within our columnar data store. Honeycomb will combine data points into the same event if: * they were received as part of the same OTLP request * their timestamps are equivalent when truncated to the second (we truncate metric timestamps to the second for improved compaction) * they have the same set of resource attribute keys and values * they have the same set of data point attribute keys and values (sometimes these are also called "tags" or "labels") [See some examples of metric-to-event mapping](/manage-data-volume/adjust-granularity/metrics-event-mapping/). ### Grouping OTLP Metrics Requests Any system that produces OpenTelemetry metrics will send repeated OTLP metrics requests. The more metrics contained in any OTLP request to Honeycomb, the greater the opportunity Honeycomb has to combine those requests into the same set of events. Requests can be grouped by time or size using [OpenTelemetry Collector's Batch Processor](https://github.com/open-telemetry/opentelemetry-collector/tree/main/processor/batchprocessor), which can be added to any [preexisting OpenTelemetry Collector pipeline](/send-data/opentelemetry/collector/). Requests can also be grouped across hosts by sending them through a single OpenTelemetry Collector processor before forwarding them to Honeycomb. (OpenTelemetry Collector can receive OTLP requests from other servers using the [OTLP Receiver](https://github.com/open-telemetry/opentelemetry-collector/tree/main/receiver/otlpreceiver).) ### Adjusting the Distinct Attributes in Any Individual Metrics Request For any metrics request, data points from distinct metrics can be combined into the same event if they share the same complete set of attributes (both keys and values) across all resources and data points. For this reason, it is generally good practice to share sets of attribute values across as many metrics as possible. For instance, if two distinct metrics are broken out by `process.pid`, their data points can share the same events. But if one metric has a `process.pid` attribute and the other does not, each data point will end up in a distinct event. Resource attributes can be set or changed using the OpenTelemetry SDK, or by using the [OpenTelemetry Collector Resource Processor](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/processor/resourceprocessor). Labels can be set or changed using the OpenTelemetry SDK, or by using the [OpenTelemetry Collector Metrics Transform Processor](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/processor/metricstransformprocessor). Note that this processor lives in the "contrib" build of OpenTelemetry Collector. ### Adjusting the Number of Captured Timeseries Metrics instrumentation can separate any individual metric (for example, `http.server.active_requests`) into any number of distinct timeseries that can be distinguished from one another by resource attributes (for example, `host.name`) or data point attributes (for example, `http.method`). The larger the cardinality of any of these attributes, the more distinct timeseries the system will be capturing. (Cardinality is the number of distinct values that exist for any individual attribute. For example, if `http.method` is sometimes `GET` and sometimes `POST`, the cardinality of this attribute would be `2`.) Timeseries can sometimes accumulate exponentially. For example, if a system had 100 distinct `host.name` fields, 2 distinct `http.method` fields, and 4 distinct `http.host` fields, it could consist of up to 100 × 2 × 4 = 800 distinct timeseries just for the `http.server.active_requests` metric. (And given that all of these would have distinct sets of attributes, this means Honeycomb would create 800 events at every capture interval for this metric.) Here is an example of what this kind of combinatoric cardinality explosion can look like: ```text theme={} host.name measurements (for http.server.active_requests, measured every 60s for 10 minutes) --------- --------------------------------------------------------------------------------- host1 46, 20, 36, 11, 38, 25, 5, 32, 57, 14 host2 16, 48, 1, 46, 29, 15, 53, 49, 33, 40 cardinality of host.name = 2 2 timeseries, generated 20 events over 10 minutes at minute 1, your dataset would contain the following 2 events: - host.name: host1, http.server.active_requests: 46 - host.name: host2, http.server.active_requests: 16 ``` ```text theme={} host.name http.method measurements (for http.server.active_requests, measured every 60s for 10 minutes) --------- ----------- --------------------------------------------------------------------------------- host1 GET 9, 4, 15, 6, 26, 11, 5, 4, 19, 9 host1 POST 37, 16, 21, 5, 12, 14, 0, 28, 38, 5 host2 GET 15, 33, 1, 45, 17, 6, 19, 12, 14, 19 host2 POST 1, 15, 0, 1, 12, 9, 34, 37, 19, 21 cardinality of host.name = 2 cardinality of http.method = 2 2*2=4 timeseries, generated 40 events over 10 minutes at minute 1, your dataset would contain the following 4 events: - host.name: host1, http.method: GET, http.server.active_requests: 9 - host.name: host1, http.method: POST, http.server.active_requests: 37 - host.name: host2, http.method: GET, http.server.active_requests: 15 - host.name: host2, http.method: POST, http.server.active_requests: 1 ``` ```text theme={} host.name http.method http.host measurements (for http.server.active_requests, measured every 60s for 10 minutes) --------- ----------- --------- --------------------------------------------------------------------------------- host1 GET public 8, 2, 14, 5, 25, 9, 3, 3, 18, 8 host1 GET internal 1, 2, 1, 1, 1, 2, 2, 1, 1, 1 host1 POST public 37, 16, 20, 5, 11, 13, 0, 27, 37, 4 host1 POST internal 0, 0, 1, 0, 1, 1, 0, 1, 1, 1 host2 GET public 14, 31, 0, 44, 14, 5, 18, 11, 13, 18 host2 GET internal 1, 2, 1, 1, 3, 1, 1, 1, 1, 1 host2 POST public 1, 14, 0, 1, 11, 8, 33, 37, 19, 20 host2 POST internal 0, 1, 0, 0, 1, 1, 1, 0, 0, 1 cardinality of host.name = 2 cardinality of http.method = 2 cardinality of http.host = 2 2*2*2=8 timeseries, generated 80 events over 10 minutes at minute 1, your dataset would contain the following 8 events: - host.name: host1, http.method: GET, http.host: public, http.server.active_requests: 8 - host.name: host1, http.method: GET, http.host: internal, http.server.active_requests: 1 - host.name: host1, http.method: POST, http.host: public, http.server.active_requests: 37 - host.name: host1, http.method: POST, http.host: internal, http.server.active_requests: 0 - host.name: host2, http.method: GET, http.host: public, http.server.active_requests: 14 - host.name: host2, http.method: GET, http.host: internal, http.server.active_requests: 1 - host.name: host2, http.method: POST, http.host: public, http.server.active_requests: 1 - host.name: host2, http.method: POST, http.host: internal, http.server.active_requests: 0 ``` Timeseries can be set or changed using the OpenTelemetry SDK, or by using [OpenTelemetry Collector's Filter Processor](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/processor/filterprocessor) or [Metrics Transform Processor](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/processor/metricstransformprocessor). Note that the Metrics Transform Processor lives in the "contrib" build of OpenTelemetry Collector. ## Modifying Capture Interval Every metrics stream is configured with a **capture interval**, which determines the frequency that individual data points are captured. More frequent capture intervals allow for a smaller granularity of any timeseries graph. Less frequent capture intervals generate proportionally fewer events. Capture interval can be modified directly at the point of capture. Generally this variable will be in the OpenTelemetry SDK or in an OpenTelemetry Collector receiver. ## Data Point Attribute Compaction As noted above, metrics normally include all data point attributes as key-value pairs on the metric event. However, Honeycomb has found that certain standard attributes relating to OpenTelemetry Semantic Conventions can be combined, or compacted, even when they're not identical because there are only a small number of individual values for these attributes. This compaction occurs automatically. For example, the metric `system.disk.io` has an attribute called `direction`. The only two values of direction are `transmit` and `receive`, so Honeycomb distributes these two values into a single event with two fields: `system.disk.io.transmit` and `system.disk.io.receive`. The full set of metric names and data point attributes that are distributed in this way is: | Metric Name | Data Point Attribute Name | | -------------------------------- | ------------------------- | | `system.disk.io` | `direction` | | `system.filesystem.usage` | `state` | | `system.processes.count` | `status` | | `system.network.connections` | `protocol` | | `system.network.dropped` | `direction` | | `system.network.dropped_packets` | `direction` | | `system.network.errors` | `direction` | | `system.network.io` | `direction` | | `k8s.node.network.errors` | `direction` | | `k8s.node.network.io` | `direction` | | `k8s.pod.network.errors` | `direction` | | `k8s.pod.network.io` | `direction` | ## Compaction of `system.cpu.time` and `system.cpu.utilization` There are other metrics that are treated specially: `system.cpu.time`, and `system.cpu.utilization`. These metrics have two key data point attributes that are compacted automatically: `state` and `logical_number`. The `state` attribute is distributed as above, generating values like `system.cpu.time.idle`. In addition, the `logical_number` attribute, an indication of which CPU core is used on a multi-core CPU, is dropped, and its different values are summed into the appropriate `state`. Thus, `system.cpu.time.idle` is the sum of the `idle` value of the `state` attribute over all values of `logical_number`. The result of this manipulation is that up to 128 individual metrics are compacted into a single Honeycomb event. # Filter Processor for OpenTelemetry Collector Source: https://docs.honeycomb.io/manage-data-volume/filter/filter-processor Filter spans, metrics, and logs based on conditions before they reach Honeycomb using the OpenTelemetry Collector filter processor. Filter spans, metrics, and logs using the filter processor for the OpenTelemetry Collector. The [filter processor](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/processor/filterprocessor/README.md/) for the OpenTelemetry (OTel) Collector filters telemetry based on conditions you provide. If you have instrumentations creating a lot of unneeded signals, the filter processor is a great way to reduce this noisy, noncritical data. The filter processor is included in the [Core, Contrib, and Kubernetes distributions](https://github.com/open-telemetry/opentelemetry-collector-releases/) of the Collector. ## Filter Conditions You can use the [OpenTelemetry Transformation Language (OTTL)](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/pkg/ottl/README.md/) to create filtering conditions for different types of telemetry. If any condition is met, the telemetry is dropped. If there are multiple conditions, each condition is ORed together. | Configuration Option | OTTL Context | | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | | `traces.span` | [Span](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/pkg/ottl/contexts/ottlspan/README.md/) | | `traces.spanevent` | [SpanEvent](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/pkg/ottl/contexts/ottlspanevent/README.md/) | | `metrics.metric` | [Metric](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/pkg/ottl/contexts/ottlmetric/README.md/) | | `metrics.datapoint` | [DataPoint](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/pkg/ottl/contexts/ottldatapoint/README.md/) | | `logs.log_record` | [Log](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/pkg/ottl/contexts/ottllog/README.md/) | Honeycomb currently translates all fields with the `instrumentation_scope.name` field into `library.name`. To filter based on the value of an instrumentation scope, use `instrumentation_scope.name` instead of `library.name`. ## Get Started To use the filter processor, add the `filter` component as a processor in your OTel Collector configuration file: ```yaml theme={} processors: # add the filter processor filter/simple: error_mode: ignore # tell it to operate on span data traces: span: - 'attributes["container.name"] == "app_container_1"' ``` Then add the filter processor to a compatible pipeline: ```yaml theme={} service: pipelines: traces: processors: [filter/simple, batch] ``` An example Collector configuration: ```yaml theme={} receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 processors: batch: filter/simple: error_mode: ignore traces: span: - 'attributes["container.name"] == "app_container_1"' exporters: otlp_http: endpoint: "https://api.honeycomb.io:443" # US instance #endpoint: "https://api.eu1.honeycomb.io:443" # EU instance headers: "x-honeycomb-team": "YOUR_API_KEY" service: pipelines: traces: receivers: [otlp] processors: [filter/simple, batch] exporters: [otlp_http] ``` ## Examples Here are some example configurations for filtering spans, metrics, and logs. You can find more examples in the [filter processor repository](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/processor/filterprocessor/testdata/). An example with filters for each type: ```yaml theme={} processors: filter: error_mode: ignore traces: span: - 'attributes["container.name"] == "app_container_1"' - 'resource.attributes["host.name"] == "localhost"' - 'name == "app_3"' spanevent: - 'attributes["grpc"] == true' - 'IsMatch(name, ".*grpc.*")' metrics: metric: - 'name == "my.metric" and resource.attributes["my_label"] == "abc123"' - 'type == METRIC_DATA_TYPE_HISTOGRAM' datapoint: - 'metric.type == METRIC_DATA_TYPE_SUMMARY' - 'resource.attributes["service.name"] == "my_service_name"' logs: log_record: - 'IsMatch(body, ".*password.*")' - 'severity_number < SEVERITY_NUMBER_WARN' ``` ### Filter Spans Drop spans based on a resource attribute: ```yaml theme={} processors: filter: error_mode: ignore traces: span: - IsMatch(resource.attributes["k8s.pod.name"], "my-pod-name.*") ``` ### Filter Span Events Drop span events based on attribute and span event name: ```yaml theme={} processors: filter: traces: # Filter out only span events with both the 'grpc' attribute and # that have a span event name with 'grpc' in it. spanevent: - 'attributes["grpc"] == true and IsMatch(name, ".*grpc.*") == true' ``` ### Filter Metrics Drop metrics with an invalid type: ```yaml theme={} processors: filter: error_mode: ignore metrics: metric: - type == METRIC_DATA_TYPE_NONE ``` Drop metrics based on name and value: ```yaml theme={} processors: filter: error_mode: ignore metrics: datapoint: - metric.name == "k8s.pod.phase" and value_int == 4 ``` Drop metrics based on attribute key with the filter processor's [HasAttrKeyOnDatapoint()](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/processor/filterprocessor/README.md#hasattrkeyondatapoint/) function: ```yaml theme={} filter: error_mode: ignore metrics: metric: - 'HasAttrKeyOnDatapoint("some.metric")' ``` Drop metrics with a given attribute and given value using the filter processor's [HasAttrOnDataPoint()](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/processor/filterprocessor/README.md#hasattrondatapoint/) function: ```yaml theme={} filter: error_mode: ignore metrics: metric: - 'HasAttrOnDatapoint("some.metric", "true")' ``` ### Filter Logs Drop logs based on log body or log severity: ```yaml theme={} filter: error_mode: ignore logs: log_record: - 'IsMatch(body, ".*password.*")' - 'severity_number < SEVERITY_NUMBER_WARN' ``` # Sampling Source: https://docs.honeycomb.io/manage-data-volume/sample Choose the right sampling strategy for your telemetry data. Compare head sampling and tail sampling and find out which approach fits your system and cost goals. Sampling is when you select a few representative elements from a larger collection and extrapolate from the selected elements to learn about the larger collection. [Head sampling](#head-sampling) and [tail sampling](#tail-sampling) are two different approaches to sampling your telemetry data. Data chosen by a sampler as representative of a data set is **sampled** data. Sampled data is processed and exported to Honeycomb. **Unsampled** data is not processed or exported. **How Honeycomb handles sampled data** [Honeycomb adjusts for sample rate](/manage-data-volume/sample/sampled-data-in-honeycomb/) when working with and querying sampled data. ## Observability and Sampling Sampling is crucial to observability at scale. You might sample your telemetry data to reduce your total data volume or filter out noise from services with predictable traffic. Consider these different kinds of traces: * Traces that finish successfully with no errors * Traces with specific attributes on them * Traces with high latency * Traces with errors on them Most of your traces are probably the first kind: traces that finish successfully with no errors. These traces represent healthy behavior of your services and are required for comparisons with other kinds of traces. But you don't need all of them, a sample of these traces is enough to understand the health of your system. The other kinds of traces are much more interesting. You might take larger samples, or even 100%, of these traces. ## Head Sampling Head sampling is when you sample traces without looking at the entire trace. The decision to sample or not sample a span in a trace is made as early as possible. In OpenTelemetry, a head sampling decision is made during span creation: unsampled spans are not created. The most common form of head sampling is deterministic probability sampling. Given a constant sampling rate that represents a fixed percentage of traces to sample, the sampler will make a decision to sample or not sample spans based on using the trace ID as a random number. Using the trace ID allows disparate samplers to make consistent decisions for all of the spans in a trace. See our guidelines on [when you should consider head sampling](/manage-data-volume/sample/guidelines/#when-to-use-head-sampling). ### OpenTelemetry SDK Support The OpenTelemetry SDKs support deterministic probability sampling: * [Java](/send-data/java/opentelemetry-agent/#sampling) * [Node.js](/send-data/javascript-nodejs/opentelemetry-sdk/#sampling) * [Go](/send-data/go/opentelemetry-sdk/#sampling) * [.NET](/send-data/dotnet/#sampling) * [Python](/send-data/python/opentelemetry-sdk/#sampling) * [Ruby](/send-data/ruby/opentelemetry-sdk/#sampling) ## Tail Sampling Tail sampling is where the sampling decision considers all or most of the spans within the trace. Because tail sampling is done by inspecting whole traces, you can apply many different sampling techniques such as: * **Dynamic sampling**: By configuring a set of fields on a trace that make up a key, the sampler automatically increases or decreases the sampling rate based on how frequently each unique value of that key occurs. For example, a key made up of `http.status_code` will sample much less traffic for requests that return `200` than for requests that return `404`. * **Rules-based sampling**: Define sampling rates for well-known conditions. For example, you can sample 100% of traces with an error and fall back to dynamic sampling for other traffic. * **Throughput-based sampling**: Sample traces based on a fixed upper bound on the number of spans per second. * **Deterministic probability sampling** - Although deterministic probability sampling is also used in head sampling, it is still possible to use it in tail sampling. Honeycomb offers [Refinery](/manage-data-volume/sample/honeycomb-refinery/) as a tail sampling solution to install in your environment. Tail sampling with Refinery lets you combine all of the above techniques to create a sampling strategy tailored to your needs. See our guidelines on [when you should consider tail sampling](/manage-data-volume/sample/guidelines/#when-to-use-tail-sampling). # When to Sample Source: https://docs.honeycomb.io/manage-data-volume/sample/guidelines Get Honeycomb's recommendations for when sampling makes sense, why it reduces costs without sacrificing insight, and which sampling approach fits your use case. Guidelines for why and when to sample your telemetry data. The [OpenTelemetry Sampling](https://opentelemetry.io/docs/concepts/sampling/) documentation has further guidance on when and why you should sample. ## Why Sampling Some of the main reasons to sample data include: * Reduce total data volume. A representative sample of your data will be much smaller than the entire volume of data produced. * Ensure you sample interesting traces. The question of representativeness can be nuanced if you have a wide variety of traffic, especially if it is irregular. * Filter out noise. A small sample can capture the behavior of services with predictable traffic patterns. ## When to Sample You should consider sampling if: * Your services generate 1000 or more traces per second * A lot of your trace data represents healthy traffic and is fairly uniform * You have conditions you can use to identify data that is relevant to you If you have a lot of data, but it is fairly uniform or it is not critical you capture everything, then you can use a simple sampling strategy. If you have a lot of conditions that matter to you, or irregular traffic patterns across your services, then you will need a more sophisticated sampling strategy. ## When to Use Head Sampling Head sampling is a blunt instrument. It is simple to configure and requires no additional infrastructure or operational overhead. But what head sampling offers in simplicity, it loses in flexibility: * You cannot sample traces based on errors they contain or their overall latency * You cannot sample traces based on attributes on different spans in a trace * You cannot dynamically adjust your sampling rate based on traffic to a service To accomplish the above, you need to use tail sampling instead. ## When to Use Tail Sampling Tail sampling with [Refinery](/manage-data-volume/sample/honeycomb-refinery/) lets you sample traces in just about any way you can imagine. How you configure tail sampling depends on your needs and the complexity of your system. Most people tend to follow some common patterns: * Configure several rules to use a high or low sampling rate for well-known conditions, like keeping all errors in traces and dropping most health checks * Configure a dynamic sampler based on a low-cardinality key like `http.status_code` to sample traces proportionally across all values of that key The rules and key configuration will often have to take into account attributes that are unique to your system. The flexibility and sophistication of tail sampling comes at a price: it is more effort to configure and requires additional infrastructure and operational overhead to run. For extremely high-volume systems, you may also need to combine head sampling and tail sampling to protect your infrastructure from huge spikes of data. # Honeycomb Refinery Source: https://docs.honeycomb.io/manage-data-volume/sample/honeycomb-refinery Deploy and operate Refinery, Honeycomb's trace-aware, tail-based sampling proxy. Set up your cluster, define sampling rules, and monitor performance. This documentation reflects Honeycomb Refinery 3.0, the latest major release. If you're using a previous version of Refinery, we recommend that you [migrate to Refinery 3.0 or later](/troubleshoot/product-lifecycle/recommended-migrations/upgrade-refinery/) to take advantage of new and improved features. Refinery is a tail-based sampling proxy and operates at the level of an entire [trace](/get-started/basics/observability/concepts/distributed-tracing/). Refinery examines whole traces and intelligently applies sampling decisions to each trace. These decisions determine whether to include or discard the trace data in the sampled data sent to Honeycomb. A tail-based sampling model lets you inspect an entire trace at one time and make a decision to sample based on its contents. For example, your data may have a root span with the HTTP status code to serve for a request, and another span with information on whether the data was served from a cache. Using Refinery, you can choose to keep only traces that had a `500` status code and were also served from a cache. For more structured learning, check out the [Introduction to Refinery](https://academy.honeycomb.io/app/courses/96b6353d-28da-4b73-9a45-e72db585cb7a) course from Honeycomb Academy. ## Refinery's tail-based sampling capabilities Refinery support several kinds of tail sampling: * **Dynamic sampling** - This sampling type configures a key based on a trace's set of fields and automatically increases or decreases the sampling rate based on how frequently each unique value of that key occurs. For example, using a key based on `http.status_code`, you can include in your sampled data: * one out of every 1,000 traces for requests that return `2xx` * one out of every 10 traces for requests that return `4xx` * every request that returns `5xx` * **Rules-based sampling** - This sampling type enables you to define sampling rates for well-known conditions. For example, in your sampled data, you can keep 100% of traces with an error and then apply dynamic sampling to all other traffic. * **Throughput-based sampling** - This sampling type enables you to sample traces based on a fixed upper-bound for the number of spans per second. The sampler will dynamically sample traces with a goal of keeping the throughput below the specified limit. * **Deterministic probability sampling** - This sampling type consistently applies sampling decisions without considering the contents of the trace other than its trace ID. For example, you can include 1 out of every 12 traces in the sampled data sent to Honeycomb. This kind of sampling can also be done using [head sampling](/manage-data-volume/sample/#head-sampling), and if you use both, Refinery takes that into account. * **Supports OpenTelemetry traces and logs signals** - Handles both OpenTelemetry trace and log data signals. Log records associated with traces are sampled as part of the trace. Unassociated log events are forwarded directly to Honeycomb. Refinery lets you combine all of the above techniques to achieve your desired sampling behavior. ## Next Steps Explore our [Refinery setup instructions](/manage-data-volume/sample/honeycomb-refinery/set-up/). The default configuration at installation contains the minimum configuration needed to run Refinery. Customize your configuration with [general configuration](/manage-data-volume/sample/honeycomb-refinery/configure/) and [sampling method configuration](/manage-data-volume/sample/honeycomb-refinery/sampling-methods/). While configuring, you may need to [scale](/manage-data-volume/sample/honeycomb-refinery/scale-size/) and [troubleshoot](/troubleshoot/common-issues/refinery/) your Refinery instance. # Configure Honeycomb Refinery Source: https://docs.honeycomb.io/manage-data-volume/sample/honeycomb-refinery/configure Customize your Refinery configuration with general settings, peer management, and storage options beyond the default installation values. Update the fields in `config.yaml` to customize your Refinery configuration. The [default configuration at installation](#default-configuration) contains the minimum configuration needed to run Refinery. Complete your Refinery setup after configuring `config.yaml` by customizing your [Sampling Methods configuration](/manage-data-volume/sample/honeycomb-refinery/sampling-methods/) in `rules.yaml`. This content applies to Refinery version 3.0 and later. For Refinery version 1.x, visit our GitHub repo for documentation on [`config`](https://github.com/honeycombio/refinery/blob/v1.21.0/config_complete.toml) and [`rules`](https://github.com/honeycombio/refinery/blob/v1.21.0/rules_complete.toml). We recommend [upgrading to Refinery 3.0](/troubleshoot/product-lifecycle/recommended-migrations/upgrade-refinery/) to benefit from new features and improvements. ## Default Configuration The default Refinery configuration uses a hardcoded peer list for file-based peer management. It uses the `DeterministicSampler` Sampling Method and a `SampleRate` of 1, meaning that no traffic will be dropped. In the Refinery GitHub repository, [a minimal default configuration file](https://github.com/honeycombio/refinery/blob/main/config.yaml) exists. To see the full set of available options, refer below to the [Refinery Config File](#refinery-config-file). In the Refinery GitHub repository, a [fully-commented configuration file](https://github.com/honeycombio/refinery/blob/main/config_complete.yaml) version exists that can be used as a template. ## Recommended Settings These recommended settings are not required when using Refinery, but highlighted for their useful purposes. To control access, use [Network](#network-configuration) and [Access Key](#access-key-configuration) configuration settings. For peer management, refer to [Peer Management](#peer-management) configuration, or if using Redis, [Redis Peer Management](#redis-peer-management). If needed, [Debugging](#debugging) contains configuration values used when setting up and debugging Refinery. When configured, the [Stress Relief](#stress-relief) mechanism can prevent Refinery from being overwhelmed by a large number of traces. It sheds load when Refinery is under duress and prevents crash loops. ## Environment Variables Refinery supports using environment variables. Environment variables take precedence over `config.yaml` file configuration. | Environment Variable | Configuration Field | | ------------------------------------------------------------------------ | ------------------------------ | | `REFINERY_GRPC_LISTEN_ADDRESS` | `GRPCListenAddr` | | `REFINERY_REDIS_HOST` | `PeerManagement.RedisHost` | | `REFINERY_REDIS_USERNAME` | `PeerManagement.RedisUsername` | | `REFINERY_REDIS_PASSWORD` | `PeerManagement.RedisPassword` | | `REFINERY_HONEYCOMB_API_KEY` | `HoneycombLogger.LoggerAPIKey` | | `REFINERY_HONEYCOMB_METRICS_API_KEY`
`REFINERY_HONEYCOMB_API_KEY` | `LegacyMetrics.APIKey` | | `REFINERY_QUERY_AUTH_TOKEN` | `QueryAuthToken` | `REFINERY_HONEYCOMB_METRICS_API_KEY` takes precedence over `REFINERY_HONEYCOMB_API_KEY` for the `LegacyMetrics.APIKey` configuration. ## Refinery Config File The Refinery `config` file is a YAML file. The file is split into sections; each section is a group of related configuration options. Each section has a name, and the name is used to refer to the section in other parts of the config file. ## Example This is an example `config` file: ```yaml theme={} General: ConfigurationVersion: 2 Network: ListenAddr: "0.0.0.0:8080" PeerListenAddr: "0.0.0.0:8081" OTelMetrics: Enabled: true APIKey: SetThisToAHoneycombKey ``` The remainder of this page describes the sections within the file and the fields in each. ## General Configuration `General` contains general configuration options that apply to the entire Refinery process. ### `ConfigurationVersion` `ConfigurationVersion` is the file format of this particular configuration file. This file is version 2. This field is required. It exists to allow the configuration system to adapt to future changes in the configuration file format. * Not eligible for live reload. * Type: `int` * Default: `2` ### `MinRefineryVersion` `MinRefineryVersion` is the minimum version of Refinery that can load this configuration file. This setting specifies the lowest Refinery version capable of loading all of the features used in this file. If this value is present, then Refinery will refuse to start if its version is less than this setting. * Not eligible for live reload. * Type: `string` * Default: `v2.0` ### `DatasetPrefix` `DatasetPrefix` is a prefix that can be used to distinguish a dataset from an environment in the rules. If telemetry is being sent to both a classic dataset and a new environment called the same thing, such as `production`, then this parameter can be used to distinguish these cases. When Refinery receives telemetry using an API key associated with a Honeycomb Classic dataset, it will then use the prefix in the form `{prefix}. {dataset}` when trying to resolve the rules definition. * Not eligible for live reload. * Type: `string` ### `ConfigReloadInterval` `ConfigReloadInterval` is the average interval between attempts at reloading the configuration file. Refinery will attempt to read its configuration and check for changes at approximately this interval. This time is varied by a random amount up to 10% to avoid all instances refreshing together. In installations where configuration changes are handled by restarting Refinery, which is often the case when using Kubernetes, disable this feature with a value of `0s`. As of Refinery v2.7, news of a configuration change is immediately propagated to all peers, and they will attempt to reload their configurations. Note that external factors (for example, Kubernetes ConfigMaps) may cause delays in propagating configuration changes. * Not eligible for live reload. * Type: `duration` * Default: `15s` ## Network Configuration `Network` contains network configuration options. ### `ListenAddr` `ListenAddr` is the address where Refinery listens for incoming requests. This setting is the IP and port on which Refinery listens for incoming HTTP requests. These requests include traffic formatted as Honeycomb events, proxied requests to the Honeycomb API, and OpenTelemetry data using the `http` protocol. Incoming traffic is expected to be HTTP, so if SSL is a requirement, put something like `nginx` in front to do the decryption. * Not eligible for live reload. * Type: `hostport` * Default: `0.0.0.0:8080` * Environment variable: `REFINERY_HTTP_LISTEN_ADDRESS` * Command line switch: `--http-listen-address` ### `PeerListenAddr` `PeerListenAddr` is the IP and port on which to listen for traffic being rerouted from a peer. Incoming traffic is expected to be HTTP, so if using SSL use something like nginx or a load balancer to do the decryption. * Not eligible for live reload. * Type: `hostport` * Default: `0.0.0.0:8081` * Environment variable: `REFINERY_PEER_LISTEN_ADDRESS` * Command line switch: `--peer-listen-address` ### `HTTPIdleTimeout` `HTTPIdleTimeout` is the duration the http server waits for activity on the connection. This is the amount of time after which if the http server does not see any activity, then it pings the client to see if the transport is still alive. "0s" means no timeout. * Not eligible for live reload. * Type: `duration` * Default: `0s` ### `HoneycombAPI` `HoneycombAPI` is the URL of the upstream Honeycomb API where the data will be sent. This setting is the destination to which Refinery sends all events that it decides to keep. * Eligible for live reload. * Type: `url` * Default: `https://api.honeycomb.io` * Environment variable: `REFINERY_HONEYCOMB_API` * Command line switch: `--honeycomb-api` ### `AdditionalHeaders` `AdditionalHeaders` is a map of additional HTTP headers to add to all upstream Honeycomb API requests. These headers will be added to all HTTP requests made to the upstream Honeycomb API endpoint, including trace data, OTel metrics, OTel traces, and logs. This is useful for scenarios where requests need to pass through an mTLS proxy that requires additional headers like `FORWARD_TO_URL`. Both keys and values must be strings. Reserved Honeycomb header prefixes ("x-honeycomb-" and "x-hny-") cannot be set. * Not eligible for live reload. * Type: `map` * Example: `FORWARD_TO_URL:https://api.honeycomb.io` ## Access Key Configuration `AccessKeys` contains access keys -- API keys that the proxy will treat specially, and other flags that control how the proxy handles API keys. ### `ReceiveKeys` `ReceiveKeys` is a set of Honeycomb API keys that the proxy will treat specially. This list only applies to span traffic - other Honeycomb API actions will be proxied through to the upstream API directly without modifying keys. * Eligible for live reload. * Type: `stringarray` * Example: `your-key-goes-here` ### `ReceiveKeyIDs` `ReceiveKeyIDs` is a set of Honeycomb Ingest Key IDs that the proxy will treat specially. When `AcceptOnlyListedKeys` is `true`, traffic using an API key whose Honeycomb ingest key ID matches an entry in this list will be accepted. The key ID is the `id` field returned by the Honeycomb `/1/auth` endpoint; it is distinct from the full API key value. This allows authorization based on key IDs rather than full key values, which avoids storing secret key material in the configuration file. Both `ReceiveKeys` and `ReceiveKeyIDs` may be used simultaneously. Note: This feature does not support legacy API keys. Only Honeycomb Ingest Keys (which have a key ID) are compatible with this setting. * Eligible for live reload. * Type: `stringarray` * Example: `your-key-id-goes-here` ### `AcceptOnlyListedKeys` `AcceptOnlyListedKeys` is a boolean flag that causes events arriving with API keys not in the `ReceiveKeys` list to be rejected. If `true`, then only traffic using the keys listed in `ReceiveKeys` or whose key ID is listed in `ReceiveKeyIDs` is accepted. Events arriving with API keys not in either list will be rejected with an HTTP `401` error. If `false`, then all traffic is accepted and `ReceiveKeys` is ignored. This setting is applied **before** the `SendKey` and `SendKeyMode` settings. * Eligible for live reload. * Type: `bool` ### `SendKey` `SendKey` is an optional Honeycomb API key that Refinery can use to send data to Honeycomb, depending on configuration. Setting this value via a command line flag may expose credentials - it is recommended to use the environment variable or a configuration file. If `SendKey` is set to a valid Honeycomb key, then Refinery can use the listed key to send data. The exact behavior depends on the value of `SendKeyMode`. * Eligible for live reload. * Type: `string` * Example: `SetThisToAHoneycombKey` * Environment variable: `REFINERY_SEND_KEY` ### `SendKeyMode` `SendKeyMode` controls how SendKey is used to replace or augment API keys used in incoming telemetry. Controls how SendKey is used to replace or supply API keys used in incoming telemetry. If `AcceptOnlyListedKeys` is `true`, then `SendKeys` will only be used for events with keys listed in `ReceiveKeys`. `none` uses the incoming key for all telemetry (default). `all` overwrites all keys, even missing ones, with `SendKey`. `nonblank` overwrites all supplied keys but will not inject `SendKey` if the incoming key is blank. `listedonly` overwrites only the keys listed in `ReceiveKeys`. `unlisted` uses the `SendKey` for all events *except* those with keys listed in `ReceiveKeys`, which use their original keys. `missingonly` uses the SendKey only to inject keys into events with blank keys. All other events use their original keys. * Eligible for live reload. * Type: `string` * Default: `none` * Options: `none`, `all`, `nonblank`, `listedonly`, `unlisted`, `missingonly` ## Refinery Telemetry `RefineryTelemetry` contains configuration information for the telemetry that Refinery uses to record its own operation. ### `AddRuleReasonToTrace` `AddRuleReasonToTrace` controls whether to decorate traces with Refinery rule evaluation results. When enabled, this setting causes traces that are sent to Honeycomb to include the field `meta.refinery.reason`. This field contains text indicating which rule was evaluated that caused the trace to be included. This setting also includes the field `meta.refinery.send_reason`, which contains the reason that the trace was sent. Possible values of this field are `trace_send_got_root`, which means that the root span arrived; `trace_send_expired`, which means that `TraceTimeout` was reached; `trace_send_ejected_full`, which means that the trace cache was full; and `trace_send_ejected_memsize`, which means that Refinery was out of memory. These names are also the names of metrics that Refinery tracks. We recommend enabling this setting whenever a rules-based sampler is in use, as it is useful for debugging and understanding the behavior of your Refinery installation. * Eligible for live reload. * Type: `bool` * Example: `true` ### `AddSpanCountToRoot` `AddSpanCountToRoot` controls whether to add a metadata field to root spans that indicates the number of child elements in a trace. The added metadata field, `meta.span_count`, indicates the number of child elements on the trace at the time the sampling decision was made. If `true` and `AddCountsToRoot` is set to false, then Refinery will add `meta.span_count` to the root span. * Eligible for live reload. * Type: `defaulttrue` * Default: `true` ### `AddCountsToRoot` `AddCountsToRoot` controls whether to add metadata fields to root spans that indicates the number of child spans, span events, span links, and honeycomb events. If `true`, then Refinery will ignore the `AddSpanCountToRoot` setting and add the following fields to the root span based on the values at the time the sampling decision was made: * `meta.span_count`: the number of child spans on the trace * `meta.span_event_count`: the number of span events on the trace * `meta.span_link_count`: the number of span links on the trace * `meta.event_count`: the number of honeycomb events on the trace * Eligible for live reload. * Type: `bool` ### `AddHostMetadataToTrace` `AddHostMetadataToTrace` specifies whether to add host metadata to traces. If `true`, then Refinery will add the following tag to all traces: - `meta.refinery.local_hostname`: the hostname of the Refinery node * Eligible for live reload. * Type: `defaulttrue` * Default: `true` ## Traces `Traces` contains configuration for how traces are managed. ### `SendDelay` `SendDelay` is the duration to wait after the root span arrives before sending a trace. This setting is a short timer that is triggered when a trace is marked complete by the arrival of the root span. Refinery waits for this duration before sending the trace. This setting exists to allow for asynchronous spans and small network delays to elapse before sending the trace. `SendDelay` is not applied if the `TraceTimeout` expires or the `SpanLimit` is reached. * Eligible for live reload. * Type: `duration` * Default: `2s` ### `BatchTimeout` `BatchTimeout` is how frequently Refinery sends unfulfilled batches. By default, this setting uses the `DefaultBatchTimeout` in `libhoney` as its value, which is `100ms`. * Eligible for live reload. * Type: `duration` * Example: `500ms` ### `TraceTimeout` `TraceTimeout` is the duration to wait before making the trace decision on an incomplete trace. A long timer; it represents the outside boundary of how long to wait before making the trace decision about an incomplete trace. Normally trace decisions (send or drop) are made when the root span arrives. Sometimes the root span never arrives (for example, due to crashes). Once this timer fires, Refinery will make a trace decision based on the spans that have arrived so far. This ensures sending a trace even when the root span never arrives. After the trace decision has been made, Refinery retains a record of that decision for a period of time. When additional spans (including the root span) arrive, they will be kept or dropped based on the original decision. If particularly long-lived traces are present in your data, then you should increase this timer. Note that this increase will also increase the memory requirements for Refinery. * Eligible for live reload. * Type: `duration` * Default: `60s` ### `SpanLimit` `SpanLimit` is the number of spans after which a trace becomes eligible for a trace decision. This setting helps to keep memory usage under control. If a trace has more than this set number of spans, then it becomes eligible for a trace decision. It's most helpful in a situation where a sudden burst of many spans in a large trace hits Refinery all at once, causing memory usage to spike and possibly crashing Refinery. * Eligible for live reload. * Type: `int` * Default: `32000` ### `MaxBatchSize` `MaxBatchSize` is the maximum number of events to be included in each batch for sending. This value is used to set the `BatchSize` field in the `libhoney` library used to send data to Honeycomb. If you have particularly large traces, then you should increase this value. Note that this will also increase the memory requirements for Refinery. * Eligible for live reload. * Type: `int` * Default: `500` ### `SendTicker` `SendTicker` is the interval between checks for traces to send. A short timer that determines the duration between trace cache review runs to send. Increasing this will spend more time processing incoming events to reduce `incoming_` or `peer_router_dropped` spikes. Decreasing this will check the trace cache for timeouts more frequently. * Eligible for live reload. * Type: `duration` * Default: `100ms` ### `MaxExpiredTraces` `MaxExpiredTraces` is the maximum number of expired traces to process. This setting controls how many traces are processed when it is time to make a sampling decision. Up to this many traces will be processed every `SendTicker` duration. If this number is too small it will mean Refinery is spending less time calculating sampling decisions, resulting in data arriving at Honeycomb slower. Additionally, MaxExpiredTraces indirectly affects the system’s health check behavior. The HealthCheckTimeout will be automatically adjusted based on this value to ensure health checks remain accurate relative to the configured processing load. If your `collector_collect_loop_duration_ms` is above 3 seconds it is recommended to reduce this value and the `SendTicker` duration. This will mean Refinery makes fewer sampling decision calculations each `SendTicker` tick, but gets the chance to make decisions more often. * Eligible for live reload. * Type: `int` * Default: `3000` ## Debugging `Debugging` contains configuration values used when setting up and debugging Refinery. ### `DebugServiceAddr` `DebugServiceAddr` is the IP and port where the debug service runs. The debug service is generally only used when debugging Refinery itself, and will only run if the command line option `-d` is specified. If this value is not specified, then the debug service runs on the first open port between `localhost:6060` and `localhost:6069`. * Not eligible for live reload. * Type: `hostport` * Example: `localhost:6060` ### `QueryAuthToken` `QueryAuthToken` is the token that must be specified to access the `/query` endpoint. Setting this value via a command line flag may expose credentials - it is recommended to use the environment variable or a configuration file. This token must be specified with the header "X-Honeycomb-Refinery-Query" in order for a `/query` request to succeed. These `/query` requests are intended for debugging Refinery during setup and are not typically needed in normal operation. If not specified, then the `/query` endpoints are inaccessible. * Not eligible for live reload. * Type: `string` * Example: `some-private-value` * Environment variable: `REFINERY_QUERY_AUTH_TOKEN` ### `AdditionalErrorFields` `AdditionalErrorFields` is a list of span fields to include when logging errors happen during the ingestion of events. For example, the span too large error. This is primarily useful in trying to track down misbehaving senders in a large installation. The fields `dataset`, `apihost`, and `environment` are always included. If a field is not present in the span, then it will not be present in the error log. * Eligible for live reload. * Type: `stringarray` * Example: `trace.span_id` ### `DryRun` `DryRun` controls whether sampling is applied to incoming traces. If enabled, then Refinery marks the traces that would be dropped given the current sampling rules, and sends all traces regardless of the sampling decision. This is useful for evaluating sampling rules. When DryRun is enabled, traces is decorated with `meta.refinery. dryrun.kept` that is set to `true` or `false`, based on whether the trace would be kept or dropped. In addition, `SampleRate` will be set to the incoming rate for all traces, and the field `meta.refinery.dryrun.sample_rate` will be set to the sample rate that would have been used. NOTE: This setting is not compatible with `TraceCache=distributed`, because drop trace decisions shared among peers do not contain all the relevant information needed to send traces to Honeycomb. * Eligible for live reload. * Type: `bool` * Example: `true` ## Refinery Logger `Logger` contains configuration for logging. ### `Type` `Type` is the type of logger to use. The setting specifies where (and if) Refinery sends logs. `none` means that logs are discarded. `honeycomb` means that logs will be forwarded to Honeycomb as events according to the set Logging settings. `stdout` means that logs will be written to `stdout`. * Not eligible for live reload. * Type: `string` * Default: `stdout` * Options: `stdout`, `honeycomb`, `none` ### `Level` `Level` is the logging level above which Refinery should send a log to the logger. `warn` is the recommended level for production. `debug` is very verbose, and should not be used in production environments. * Not eligible for live reload. * Type: `string` * Default: `warn` * Options: `debug`, `info`, `warn`, `error`, `panic` ## Honeycomb Logger `HoneycombLogger` contains configuration for logging to Honeycomb. Only used if `Logger.Type` is "honeycomb". ### `APIHost` `APIHost` is the URL of the Honeycomb API where Refinery sends its logs. Refinery's internal logs will be sent to this host using the standard Honeycomb Events API. * Not eligible for live reload. * Type: `url` * Default: `https://api.honeycomb.io` ### `APIKey` `APIKey` is the API key used to send Refinery's logs to Honeycomb. Setting this value via a command line flag may expose credentials - it is recommended to use the environment variable or a configuration file. It is recommended that you create a separate team and key for Refinery logs. * Not eligible for live reload. * Type: `string` * Example: `SetThisToAHoneycombKey` * Environment variable: `REFINERY_HONEYCOMB_LOGGER_API_KEY, REFINERY_HONEYCOMB_API_KEY` ### `Dataset` `Dataset` is the dataset to which logs will be sent. Only used if `APIKey` is specified. * Not eligible for live reload. * Type: `string` * Default: `Refinery Logs` ### `SamplerEnabled` `SamplerEnabled` controls whether logs are sampled before sending to Honeycomb. The sample rate is controlled by the `SamplerThroughput` setting. The sampler used throttles the rate of logs sent to Honeycomb from any given source within Refinery -- it should effectively limit the rate of redundant messages. * Not eligible for live reload. * Type: `defaulttrue` * Default: `true` ### `SamplerThroughput` `SamplerThroughput` is the sampling throughput for logs in events per second. The sampling algorithm attempts to make sure that the average throughput approximates this value, while also ensuring that all unique logs arrive at Honeycomb at least once per sampling period. * Not eligible for live reload. * Type: `float` * Default: `10` * Example: `10` ### `AdditionalAttributes` `AdditionalAttributes` adds the provided attributes to all logs written by the Honeycomb logger. When supplying via a environment variable, the value should be a string of comma-separated key-value pairs. When supplying via the command line, the value should be a key value pair. If multiple key-value pairs are needed, each should be supplied via its own command line flag. The key-value pairs must use ':' as the separator. * Not eligible for live reload. * Type: `map` * Example: `pipeline.id:'12345',rollout.id:'67890'` * Environment variable: `REFINERY_HONEYCOMB_LOGGER_ADDITIONAL_ATTRIBUTES` ## Stdout Logger `StdoutLogger` contains configuration for logging to `stdout`. Only used if `Logger.Type` is "stdout". ### `Structured` `Structured` controls whether to use structured logging. `true` generates structured logs (JSON). `false` generates plain text logs. * Not eligible for live reload. * Type: `bool` ### `SamplerEnabled` `SamplerEnabled` controls whether logs are sampled before sending to `stdout`. The sample rate is controlled by the `SamplerThroughput` setting. * Not eligible for live reload. * Type: `bool` ### `SamplerThroughput` `SamplerThroughput` is the sampling throughput for logs in events per second. The sampling algorithm attempts to make sure that the average throughput approximates this value, while also ensuring that all unique logs arrive at `stdout` at least once per sampling period. * Not eligible for live reload. * Type: `float` * Default: `10` * Example: `10` ## Prometheus Metrics `PrometheusMetrics` contains configuration for Refinery's internally-generated metrics as made available through Prometheus. ### `Enabled` `Enabled` controls whether to expose Refinery metrics over the `PrometheusListenAddr` port. Each of the metrics providers can be enabled or disabled independently. Metrics can be sent to multiple destinations. * Not eligible for live reload. * Type: `bool` ### `ListenAddr` `ListenAddr` is the IP and port the Prometheus Metrics server will run on. Determines the interface and port on which Prometheus will listen for requests for `/metrics`. Must be different from the main Refinery listener. Only used if `Enabled` is `true` in `PrometheusMetrics`. * Not eligible for live reload. * Type: `hostport` * Default: `localhost:2112` ## OpenTelemetry Metrics `OTelMetrics` contains configuration for Refinery's OpenTelemetry (OTel) metrics. This is the preferred way to send metrics to Honeycomb. New installations should prefer `OTelMetrics`. ### `Enabled` `Enabled` controls whether to send metrics via OpenTelemetry. Each of the metrics providers can be enabled or disabled independently. Metrics can be sent to multiple destinations. * Not eligible for live reload. * Type: `bool` ### `APIHost` `APIHost` is the URL of the OpenTelemetry API to which metrics will be sent. Refinery's internal metrics will be sent to the `/v1/metrics` endpoint on this host. * Not eligible for live reload. * Type: `url` * Default: `https://api.honeycomb.io` ### `APIKey` `APIKey` is the API key used to send Honeycomb metrics via OpenTelemetry. Setting this value via a command line flag may expose credentials - it is recommended to use the environment variable or a configuration file. It is recommended that you create a separate team and key for Refinery metrics. If this is blank, then Refinery will not set the Honeycomb-specific headers for OpenTelemetry, and your `APIHost` must be set to a valid OpenTelemetry endpoint. * Not eligible for live reload. * Type: `string` * Example: `SetThisToAHoneycombKey` * Environment variable: `REFINERY_OTEL_METRICS_API_KEY, REFINERY_HONEYCOMB_API_KEY` ### `Dataset` `Dataset` is the Honeycomb dataset that Refinery sends its OpenTelemetry metrics. Only used if `APIKey` is specified. * Not eligible for live reload. * Type: `string` * Default: `Refinery Metrics` ### `ReportingInterval` `ReportingInterval` is the interval between sending OpenTelemetry metrics to Honeycomb. Between `1` and `60` seconds is typical. * Not eligible for live reload. * Type: `duration` * Default: `30s` ### `Compression` `Compression` is the compression algorithm to use when sending OpenTelemetry metrics to Honeycomb. `gzip` is the default and recommended value. In rare circumstances, compression costs may outweigh the benefits, in which case `none` may be used. * Not eligible for live reload. * Type: `string` * Default: `gzip` * Options: `none`, `gzip` ### `AdditionalAttributes` `AdditionalAttributes` adds the provided attributes as resource attributes on all OpenTelemetry metrics emitted by Refinery. This is useful for injecting deployment-specific metadata (such as a cluster ID or environment name) into metrics so they can be filtered or grouped in the metrics backend. Both keys and values must be strings. When supplying via a environment variable, the value should be a string of comma-separated key-value pairs. When supplying via the command line, the value should be a key value pair. If multiple key-value pairs are needed, each should be supplied via its own command line flag. The key-value pairs must use ':' as the separator. * Not eligible for live reload. * Type: `map` * Example: `pipeline.id:'12345',rollout.id:'67890'` * Environment variable: `REFINERY_OTEL_METRICS_ADDITIONAL_ATTRIBUTES` ## OpenTelemetry Tracing `OTelTracing` contains configuration for Refinery's own tracing. ### `Enabled` `Enabled` controls whether to send Refinery's own OpenTelemetry traces. The setting specifies if Refinery sends traces. * Not eligible for live reload. * Type: `bool` ### `APIHost` `APIHost` is the URL of the OpenTelemetry API to which traces will be sent. Refinery's internal traces will be sent to the `/v1/traces` endpoint on this host. * Not eligible for live reload. * Type: `url` * Default: `https://api.honeycomb.io` ### `APIKey` `APIKey` is the API key used to send Refinery's traces to Honeycomb. Setting this value via a command line flag may expose credentials - it is recommended to use the environment variable or a configuration file. It is recommended that you create a separate team and key for Refinery telemetry. If this value is blank, then Refinery will not set the Honeycomb-specific headers for OpenTelemetry, and your `APIHost` must be set to a valid OpenTelemetry endpoint. * Not eligible for live reload. * Type: `string` * Example: `SetThisToAHoneycombKey` * Environment variable: `REFINERY_HONEYCOMB_TRACES_API_KEY, REFINERY_HONEYCOMB_API_KEY` ### `Dataset` `Dataset` is the Honeycomb dataset to which Refinery sends its OpenTelemetry metrics. Only used if `APIKey` is specified. * Not eligible for live reload. * Type: `string` * Default: `Refinery Traces` ### `SampleRate` `SampleRate` is the rate at which Refinery samples its own traces. This is the Honeycomb sample rate used to sample traces sent by Refinery. Since each incoming span generates multiple outgoing spans, a minimum sample rate of `100` is strongly advised. * Eligible for live reload. * Type: `int` * Default: `100` ### `Insecure` `Insecure` controls whether to send Refinery's own OpenTelemetry traces via http instead of https. When true Refinery will export its internal traces over http instead of https. Useful if you plan on sending your traces to a different refinery instance for tail sampling. * Not eligible for live reload. * Type: `bool` ## Peer Management `PeerManagement` controls how the Refinery cluster communicates between peers. ### `Type` `Type` is the type of peer management to use. Peer management is the mechanism by which Refinery locates its peers. `file` means that Refinery gets its peer list from the Peers list in this config file. It also prevents Refinery from using a publish/subscribe mechanism to propagate peer lists, stress levels, and configuration changes. `redis` means that Refinery uses a Publish/Subscribe mechanism, implemented on Redis, to propagate peer lists, stress levels, and notification of configuration changes much more quickly than the legacy mechanism. The recommended setting is `redis`, especially for new installations. If `redis` is specified, fields in `RedisPeerManagement` must also be set. * Not eligible for live reload. * Type: `string` * Default: `file` * Options: `redis`, `file` ### `Identifier` `Identifier` specifies the identifier to use when registering itself with peers. By default, when using a peer registry, Refinery will use the local hostname to identify itself to other peers. If your environment requires something else, (for example, if peers cannot resolve each other by name), then you can specify the exact identifier, such as an IP address, to use here. Overrides `IdentifierInterfaceName`, if both are set. * Not eligible for live reload. * Type: `string` * Example: `192.168.1.1` ### `IdentifierInterfaceName` `IdentifierInterfaceName` specifies a network interface to use when finding a local hostname. By default, when using a peer registry, Refinery will use the local hostname to identify itself to other peers. If your environment requires that you use IPs as identifiers (for example, if peers cannot resolve each other by name), then you can specify the network interface that Refinery is listening on here. Refinery will use the first unicast address that it finds on the specified network interface as its identifier. * Not eligible for live reload. * Type: `string` * Example: `eth0` ### `UseIPV6Identifier` `UseIPV6Identifier` specifies that Refinery should use an IPV6 address as its identifier. If using `IdentifierInterfaceName`, Refinery will default to the first IPv4 unicast address it finds for the specified interface. If this value is specified, then Refinery will use the first IPV6 unicast address found. * Not eligible for live reload. * Type: `bool` ### `Peers` `Peers` is the list of peers to use when Type is "file", excluding self. This list is ignored when Type is "redis". The format is a list of strings of the form "scheme://host:port". * Eligible for live reload. * Type: `stringarray` * Example: `http://192.168.1.11:8081,http://192.168.1.12:8081` ## Redis Peer Management `RedisPeerManagement` controls how the Refinery cluster communicates between peers when using Redis. Does not apply when `PeerManagement.Type` is "file". ### `Host` `Host` is the host and port of the Redis instance to use for peer cluster membership management. Must be in the form `host:port`. * Not eligible for live reload. * Type: `hostport` * Example: `localhost:6379` * Environment variable: `REFINERY_REDIS_HOST` ### `ClusterHosts` `ClusterHosts` is a list of host and port pairs for the instances in a Redis Cluster, and used for managing peer cluster membership. This configuration enables Refinery to connect to a Redis deployment setup in Cluster Mode. Each entry in the list should follow the format `host:port`. If `ClusterHosts` is specified, the `Host` setting will be ignored. * Not eligible for live reload. * Type: `stringarray` * Example: `- localhost:6379` ### `Username` `Username` is the username used to connect to Redis for peer cluster membership management. Setting this value via a command line flag may expose credentials - it is recommended to use the environment variable or a configuration file. Many Redis installations do not use this field. * Not eligible for live reload. * Type: `string` * Environment variable: `REFINERY_REDIS_USERNAME` ### `Password` `Password` is the password used to connect to Redis for peer cluster membership management. Setting this value via a command line flag may expose credentials - it is recommended to use the environment variable or a configuration file. Many Redis installations do not use this field. * Not eligible for live reload. * Type: `string` * Environment variable: `REFINERY_REDIS_PASSWORD` ### `AuthCode` `AuthCode` is the string used to connect to Redis for peer cluster membership management using an explicit AUTH command. Setting this value via a command line flag may expose credentials - it is recommended to use the environment variable or a configuration file. Many Redis installations do not use this field. * Not eligible for live reload. * Type: `string` * Environment variable: `REFINERY_REDIS_AUTH_CODE` ### `ClusterName` `ClusterName` is a cluster identifier used as a prefix for Redis pubsub channel names. ClusterName is used to namespace Redis pubsub channels when multiple Refinery clusters share the same Redis instance. If set, all pubsub channel names will be prefixed with this value (e.g., "production:peers"). This allows multiple clusters to coexist without interfering with each other. Must be alphanumeric if specified. * Not eligible for live reload. * Type: `string` * Example: `production` ### `UseTLS` `UseTLS` enables TLS when connecting to Redis for peer cluster membership management. When enabled, this setting sets the `MinVersion` in the TLS configuration to `1.2`. * Not eligible for live reload. * Type: `bool` ### `UseTLSInsecure` `UseTLSInsecure` disables certificate checks when connecting to Redis for peer cluster membership management. This setting is intended for use with self-signed certificates and sets the `InsecureSkipVerify` flag within Redis. * Not eligible for live reload. * Type: `bool` ### `Timeout` `Timeout` is the timeout to use when communicating with Redis. It is rarely necessary to adjust this value. * Not eligible for live reload. * Type: `duration` * Default: `5s` ## Collection Settings `Collection` contains the settings that are relevant to collecting spans together to make traces. If none of the memory settings are used, then Refinery will not attempt to limit its memory usage. This is not recommended for production use since a burst of traffic could cause Refinery to run out of memory and crash. ### `PeerQueueSize` `PeerQueueSize` is the maximum number of in-flight spans redirected from other peers stored in the peer span queue. The peer span queue serves as a buffer for spans redirected from other peers before they are processed. In the event that this queue reaches its capacity, any subsequent spans will be discarded. The size of this queue is contingent upon the number of peers within the cluster. Specifically, with N peers, the queue's span capacity is determined by (N-1)/N of the total number of spans. Its minimum value should be at least three times the `CacheCapacity`. * Not eligible for live reload. * Type: `int` * Default: `30000` ### `IncomingQueueSize` `IncomingQueueSize` is the number of in-flight spans to keep in the incoming span queue. The incoming span queue is used to buffer spans before they are processed. If this queue fills up, then subsequent spans will be dropped. Its minimum value should be at least three times the `CacheCapacity`. * Not eligible for live reload. * Type: `int` * Default: `30000` ### `AvailableMemory` `AvailableMemory` is the amount of system memory available to the Refinery process. This value will typically be set through an environment variable controlled by the container or deploy script. If this value is zero or not set, then `MaxMemoryPercentage` cannot be used to calculate the maximum allocation and `MaxAlloc` will be used instead. If set, then this must be a memory size. Sizes with standard unit suffixes (such as `MB` and `GiB`) and Kubernetes units (such as `M` and `Gi`) are supported. Fractional values with a suffix are supported. If `AvailableMemory` is set, `Collections.MaxAlloc` must not be defined. A useful value for this setting will leave 1-2GB of pod memory for overages. For typical configurations this may be about 85%-90% of the pod's total memory. * Eligible for live reload. * Type: `memorysize` * Example: `4.5Gb` * Environment variable: `REFINERY_AVAILABLE_MEMORY` * Command line switch: `--available-memory` ### `MaxMemoryPercentage` `MaxMemoryPercentage` is the maximum percentage of memory that should be allocated by the span collector. If nonzero, then it must be an integer value between 1 and 100, representing the target maximum percentage of memory that should be allocated by the span collector. If set to a non-zero value, then once per tick (see `SendTicker`) the collector will compare total allocated bytes to this calculated value. If allocation is too high, then traces will be ejected from the cache early to reduce memory. Useful values for this setting are generally in the range of 70-90. * Eligible for live reload. * Type: `percentage` * Default: `75` * Example: `75` ### `MaxAlloc` `MaxAlloc` is the maximum number of bytes that should be allocated by the Collector. If set, then this must be a memory size. Sizes with standard unit suffixes (such as `MB` and `GiB`) and Kubernetes units (such as `M` and `Gi`) are supported. Fractional values with a suffix are supported. See `MaxMemoryPercentage` for more details. If set, `Collections.AvailableMemory` must not be defined. * Eligible for live reload. * Type: `memorysize` ### `ShutdownDelay` `ShutdownDelay` controls the maximum time Refinery can use while draining traces at shutdown. This setting controls the duration that Refinery expects to have to drain in-process traces before shutting down an instance. When asked to shut down gracefully, Refinery stops accepting new spans immediately and drains the remaining traces by sending them to remaining peers. This value should be set to a bit less than the normal timeout period for shutting down without forcibly terminating the process. * Eligible for live reload. * Type: `duration` * Default: `15s` ### `HealthCheckTimeout` `HealthCheckTimeout` controls the maximum duration allowed for collection health checks to complete. The `HealthCheckTimeout` setting specifies the maximum duration allowed for the health checks of the collection subsystems to complete. If a subsystem does not respond within this timeout period, it will be marked as unhealthy. This timeout value should be set carefully to ensure that transient delays do not lead to unnecessary failure detection while still allowing for timely identification of actual health issues. This timeout should be configured to balance responsiveness and stability — allowing for timely detection of real health issues without being overly sensitive to brief or harmless delays. Refinery will adjust the timeout based on the configured `MaxExpiredTraces`, so that health checks remain effective under varying system conditions. * Not eligible for live reload. * Type: `duration` * Default: `15s` ### `WorkerCount` `WorkerCount` is the number of parallel collection workers to run for trace processing. Controls the number of parallel collection workers used for processing traces. Each worker processes a subset of traces independently using consistent hashing. Values greater than 1 enable parallel processing which can improve throughput on multi-core systems. The default of 0 means Refinery will automatically set this value to the number of logical CPUs available at startup. * Not eligible for live reload. * Type: `int` ## Specialized Configuration `Specialized` contains special-purpose configuration options that are not typically needed. ### `EnvironmentCacheTTL` `EnvironmentCacheTTL` is the duration for which environment information is cached. This is the amount of time for which Refinery caches environment information, which it looks up from Honeycomb for each different `APIKey`. This information is used when making sampling decisions. If you have a very large number of environments, then you may want to increase this value. * Eligible for live reload. * Type: `duration` * Default: `1h` ### `CompressPeerCommunication` `CompressPeerCommunication` determines whether Refinery will compress span data it forwards to peers. If it costs money to transmit data between Refinery instances (for example, when spread across AWS availability zones), then you almost certainly want compression enabled to reduce your bill. The option to disable it is provided as an escape hatch for deployments that value lower CPU utilization over data transfer costs. * Not eligible for live reload. * Type: `defaulttrue` * Default: `true` ### `AdditionalAttributes` `AdditionalAttributes` is a map that can be used for injecting user-defined attributes into every span. For example, it could be used for naming a Refinery cluster. Both keys and values must be strings. * Eligible for live reload. * Type: `map` * Example: `ClusterName:MyCluster,environment:production` ## ID Fields `IDFields` controls the field names to use for the event ID fields. These fields are used to identify events that are part of the same trace. ### `TraceNames` `TraceNames` is the list of field names to use for the trace ID. The first field in the list that is present in an incoming span will be used as the trace ID. If none of the fields are present, then Refinery treats the span as not being part of a trace and forwards it immediately to Honeycomb. * Eligible for live reload. * Type: `stringarray` * Example: `trace.trace_id,traceId` ### `ParentNames` `ParentNames` is the list of field names to use for the parent ID. The first field in the list that is present in an event will be used as the parent ID. A trace without a `parent_id` is assumed to be a root span. * Eligible for live reload. * Type: `stringarray` * Example: `trace.parent_id,parentId` ## gRPC Server Parameters `GRPCServerParameters` controls the parameters of the gRPC server used to receive OpenTelemetry data in gRPC format. ### `Enabled` `Enabled` specifies whether the gRPC server is enabled. If `false`, then the gRPC server is not started and no gRPC traffic is accepted. * Not eligible for live reload. * Type: `defaulttrue` * Default: `true` ### `ListenAddr` `ListenAddr` is the address Refinery listens to for incoming GRPC OpenTelemetry events. Incoming traffic is expected to be unencrypted, so if using SSL, then put something like `nginx` in front to do the decryption. * Not eligible for live reload. * Type: `hostport` * Environment variable: `REFINERY_GRPC_LISTEN_ADDRESS` * Command line switch: `--grpc-listen-address` ### `MaxConnectionIdle` `MaxConnectionIdle` is the amount of time to permit an idle connection. A duration for the amount of time after which an idle connection will be closed by sending a GoAway. "Idle" means that there are no active RPCs. "0s" sets duration to infinity, but this is not recommended for Refinery deployments behind a load balancer, because it will prevent the load balancer from distributing load evenly among peers. * Not eligible for live reload. * Type: `duration` * Default: `1m` * Example: `1m` ### `MaxConnectionAge` `MaxConnectionAge` is the maximum amount of time a gRPC connection may exist. After this duration, the gRPC connection is closed by sending a `GoAway`. A random jitter of +/-10% will be added to `MaxConnectionAge` to spread out connection storms. `0s` sets duration to infinity; a value measured in low minutes will help load balancers to distribute load among peers more evenly. * Not eligible for live reload. * Type: `duration` * Default: `3m` ### `MaxConnectionAgeGrace` `MaxConnectionAgeGrace` is the duration beyond `MaxConnectionAge` after which the connection will be forcibly closed. This setting is in case the upstream node ignores the `GoAway` request. "0s" sets duration to infinity. * Not eligible for live reload. * Type: `duration` * Default: `1m` ### `KeepAlive` `KeepAlive` is the duration between keep-alive pings. After this amount of time, if the client does not see any activity, then it pings the server to see if the transport is still alive. "0s" sets duration to 2 hours. * Not eligible for live reload. * Type: `duration` * Default: `1m` ### `KeepAliveTimeout` `KeepAliveTimeout` is the duration the server waits for activity on the connection. This is the amount of time after which if the server does not see any activity, then it pings the client to see if the transport is still alive. "0s" sets duration to 20 seconds. * Not eligible for live reload. * Type: `duration` * Default: `20s` ### `MaxSendMsgSize` `MaxSendMsgSize` is the maximum message size the server can send. The server enforces a maximum message size to avoid exhausting the memory available to the process by a single request. The size is expressed in bytes. * Not eligible for live reload. * Type: `memorysize` * Default: `15MB` ### `MaxRecvMsgSize` `MaxRecvMsgSize` is the maximum message size the server can receive. The server enforces a maximum message size to avoid exhausting the memory available to the process by a single request. The size is expressed in bytes. * Not eligible for live reload. * Type: `memorysize` * Default: `15MB` ## Sample Cache `SampleCache` controls the sample cache used to retain information about trace status after the sampling decision has been made. ### `KeptSize` `KeptSize` is the number of traces preserved in the cuckoo kept traces cache. Refinery keeps a record of each trace that was kept and sent to Honeycomb, along with some statistical information. This is most useful in cases where the trace was sent before sending the root span, so that the root span can be decorated with accurate metadata. Default is `10_000` traces. Each trace in this cache consumes roughly 200 bytes. * Eligible for live reload. * Type: `int` * Default: `10000` ### `DroppedSize` `DroppedSize` is the size of the cuckoo dropped traces cache. This cache consumes 4-6 bytes per trace at a scale of millions of traces. Changing its size with live reload sets a future limit, but does not have an immediate effect. * Eligible for live reload. * Type: `int` * Default: `1000000` ### `SizeCheckInterval` `SizeCheckInterval` controls how often the cuckoo cache re-evaluates its remaining capacity. This cache is quite resilient so it does not need to happen very often, but the operation is also inexpensive. Default is 10 seconds. * Eligible for live reload. * Type: `duration` * Default: `10s` ## Stress Relief `StressRelief` controls the Stress Relief mechanism, which is used to prevent Refinery from being overwhelmed by a large number of traces. There is a metric called `stress_level` that is emitted as part of Refinery metrics. It is a measure of Refinery's throughput rate relative to its processing rate, combined with the amount of room in its internal queues, and ranges from `0` to `100`. `stress_level` is generally expected to be `0` except under heavy load. When stress levels reach `100`, there is an increased chance that Refinery will become unstable. To avoid this problem, the Stress Relief system can do deterministic sampling on new trace traffic based solely on `TraceID`, without having to store traces in the cache or take the time processing sampling rules. Existing traces in flight will be processed normally, but when Stress Relief is active, trace decisions are made deterministically on a per-span basis; all spans will be sampled according to the `SamplingRate` specified here. Once Stress Relief activates (by exceeding the `ActivationLevel`), it will not deactivate until `stress_level` falls below the `DeactivationLevel`. When it deactivates, normal trace decisions are made -- and any additional spans that arrive for traces that were active during Stress Relief will respect the decisions made during that time. The measurement of stress is a lagging indicator and is highly dependent on Refinery configuration and scaling. Other configuration values should be well tuned first, before adjusting the Stress Relief Activation parameters. Stress Relief is not a substitute for proper configuration and scaling, but it can be used as a safety valve to prevent Refinery from becoming unstable under heavy load. ### `Mode` `Mode` is a string indicating how to use Stress Relief. This setting sets the Stress Relief mode. "never" means that Stress Relief will never activate. "monitor" is the recommended setting, and means that Stress Relief will monitor the status of Refinery and activate according to the levels set by fields such as `ActivationLevel`. "always" means that Stress Relief is always on, which may be useful in an emergency situation. * Eligible for live reload. * Type: `string` * Default: `never` ### `ActivationLevel` `ActivationLevel` is the `stress_level` (from 0-100) at which Stress Relief is triggered. This value must be greater than `DeactivationLevel` and should be high enough that it is not reached in normal operation. * Eligible for live reload. * Type: `percentage` * Default: `90` ### `DeactivationLevel` `DeactivationLevel` is the `stress_level` (from 0-100) at which Stress Relief is turned off. This setting is subject to `MinimumActivationDuration`. The value must be less than `ActivationLevel`. * Eligible for live reload. * Type: `percentage` * Default: `75` ### `SamplingRate` `SamplingRate` is the sampling rate to use when Stress Relief is activated. All new traces will be deterministically sampled at this rate based only on the `traceID`. It should be chosen to be a rate that sends fewer samples than the average sampling rate Refinery is expected to generate. For example, if Refinery is configured to normally sample at a rate of 1 in 10, then Stress Relief should be configured to sample at a rate of at least 1 in 30. If this value is configured to send more data to Honeycomb during stress relief than the normal average sampling strategy, it may overwhelm the upstream send queue and have the opposite of the desired effect. * Eligible for live reload. * Type: `int` * Default: `100` ### `MinimumActivationDuration` `MinimumActivationDuration` is the minimum time that Stress Relief will stay enabled once activated. This setting helps to prevent oscillations. * Eligible for live reload. * Type: `duration` * Default: `10s` # Diagnose Refinery Performance Through Trace Patterns Source: https://docs.honeycomb.io/manage-data-volume/sample/honeycomb-refinery/diagnose Use Refinery's built-in metrics to identify and address performance bottlenecks caused by common trace patterns. Refinery's performance is shaped not just by traffic volume, but by the structure and characteristics of your trace data. Certain trace patterns, such as traces with thousands of spans, spans with large payloads, long-lived traces, and high-cardinality sampling keys, can cause memory pressure, throughput degradation, and [Stress Relief](/manage-data-volume/sample/honeycomb-refinery/configure/#stress-relief) activation. Use this page to diagnose an active performance problem, or to understand these patterns before they affect your cluster. * **Actively troubleshooting?** Start with [Diagnose by symptom](#diagnose-by-symptom) to map what you are observing to a likely cause. * **Planning proactively?** Start with [Common trace patterns](#common-trace-patterns) to understand the patterns and their effects. ## Common trace patterns These patterns are the most common structural causes of Refinery performance problems. Each one places stress on Refinery in a different way, and each requires a different response. | Pattern | Primary effect | | --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ | | [Traces with a high span count](#traces-with-a-high-span-count) | Increased per-trace memory usage; delayed sampling decisions | | [Fields with a high number of attributes or attribute values](#fields-with-a-high-number-of-attributes-or-attribute-values) | Increased per-span memory usage; slower processing | | [Long-lived traces](#long-lived-traces) | Trace cache growth; sustained memory pressure | | [High-cardinality sampling keys](#high-cardinality-sampling-keys) | Unstable sampling rates | ## Diagnose by symptom Use the symptom table to map what you are observing in Refinery's metrics to one or more likely causes. Follow the links to the pattern sections for identification steps and recommendations. | What you are observing | Likely cause | | ---------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `memory_inuse` rising with `trace_span_count` | [Traces with a high span count](#traces-with-a-high-span-count) | | `memory_inuse` rising without a change in `incoming_router_span` | [Fields with a high number of attributes or attribute values](#fields-with-a-high-number-of-attributes-or-attribute-values) and/or [Long-lived traces](#long-lived-traces) | | `collector_collect_loop_duration_ms` increasing | [Traces with a high span count](#traces-with-a-high-span-count) | | `collect_cache_entries_*` growing without bound | [Long-lived traces](#long-lived-traces) | | `trace_duration_ms_*` max values surpass `TraceTimeout` | [Long-lived traces](#long-lived-traces) | | `_keyspace_size` growing or fluctuating | [High-cardinality sampling keys](#high-cardinality-sampling-keys) | | Stress Relief activating frequently | Any of the above; check all patterns | ## Traces with a high span count A single trace that contains an unusually large number of spans, such as 10,000 or more, places an outsized memory burden on Refinery. This pattern is common in services that instrument batching processes or polling loops. ### How to identify Check these metrics in your Refinery monitoring to confirm this pattern is the cause of your performance issue: * `trace_span_count_*` shows spikes in spans per trace. * `collector_collect_loop_duration_ms` is elevated. * `memory_inuse` rises in correlation with `trace_span_count_*`. ### Why this affects Refinery Refinery buffers all spans belonging to a single trace in memory before making a sampling decision. A high span count increases per-trace memory usage and delays sampling decisions, which reduces overall throughput. ### Recommendations These changes address the pattern at both the Refinery configuration level and the instrumentation level: * Lower [`SpanLimit`](/manage-data-volume/sample/honeycomb-refinery/configure/#spanlimit) in Refinery to trigger a trace decision sooner. * Modify your application instrumentation to reduce spans per trace. Visit [Exotic Trace Shapes](https://www.honeycomb.io/blog/exotic-trace-shapes) on the Honeycomb Blog to learn more. ## Fields with a high number of attributes or attribute values Spans that carry a large number of attributes, or attributes with unusually large values such as request and response bodies or full stack traces, can degrade Refinery performance. This pattern often results from verbose or unstructured instrumentation. ### How to identify These metrics confirm that payload size, rather than span volume, is driving memory pressure: * `incoming_router_event_bytes_*` shows elevated per-event payload sizes even when span count is low or stable. This metric is available in Refinery v2.9.4 and later. * `memory_inuse` increases even when span count is low or stable. ### Why this affects Refinery Large span payloads increase per-span memory usage, which leads to slower processing, higher memory pressure, and more frequent activation of [Stress Relief](/manage-data-volume/sample/honeycomb-refinery/configure/#stress-relief). ### Recommendations Addressing this pattern requires reducing payload size at the source before data reaches Refinery: * Normalize and trim unnecessary fields. * Avoid storing large payloads, such as stack traces or full request bodies, as span attributes. ## Long-lived traces When spans for a single trace arrive over an extended period of time, Refinery must hold the incomplete trace in memory for longer than usual. This pattern is common in background jobs, retry logic, or workflows that span multiple asynchronous stages. ### How to identify These metrics indicate that traces are accumulating in the cache faster than they are being processed: * `trace_duration_ms_*` values approach the configured `TraceTimeout`. * `trace_send_expired` is rising. * `collect_cache_entries_*` increases gradually without a corresponding drop. * `memory_inuse` grows without a change in span rate. ### Why this affects Refinery Accumulating long-lived traces increases trace cache size and memory pressure over time. When enough long traces accumulate, throughput drops and [Stress Relief](/manage-data-volume/sample/honeycomb-refinery/configure/#stress-relief) may activate. If a Dynamic Sampler is in use, this pattern can also affect sampling accuracy: the sampler's keyspace may update faster than spans arrive for a trace, causing a sampling decision based on incomplete information. The effect compounds over time, which makes early detection important. ### Recommendations These adjustments give Refinery an earlier opportunity to resolve traces and free memory: * Adjust [`TraceTimeout`](/manage-data-volume/sample/honeycomb-refinery/configure/#tracetimeout) to set an upper bound on how long Refinery holds an incomplete trace. Increasing `TraceTimeout` also increases Refinery's memory requirements. * Where possible, break long workflows across trace boundaries at async or retry handoffs. ## High-cardinality sampling keys Dynamic sampling based on high-cardinality fields, such as `http.url` or `user.id`, can result in a large and unstable sampling keyspace. Refinery maintains a key-to-sample-rate map for each Dynamic Sampler; when that map grows too large or fluctuates frequently, sampling rates become unpredictable. ### How to identify These signals reveal whether your sampling keyspace is growing beyond a stable, manageable size: * `_keyspace_size` increases rapidly or fluctuates. * When querying your sampled trace data in Honeycomb, `COUNT_DISTINCT(meta.refinery.sample_key)` is large or increases across different time granularities. Before running this query, enable [`AddRuleReasonToTrace`](/manage-data-volume/sample/honeycomb-refinery/configure/#addrulereasontotrace) in your Refinery configuration to attach `meta.refinery.sample_key` to your sampled traces. ### Why this affects Refinery An unstable or excessively large keyspace causes erratic sampling rates and increases the likelihood of triggering [Stress Relief](/manage-data-volume/sample/honeycomb-refinery/configure/#stress-relief). The instability affects both the quality of sampling decisions and overall cluster health. ### Recommendations These changes stabilize the keyspace and restore predictable sampling behavior: * Use lower-cardinality fields as sampling keys. * Enable [`MaxKeys`](/manage-data-volume/sample/honeycomb-refinery/sampling-methods/#maxkeys) to cap the keyspace size. * Visit [Refinery EMA Sampling](/manage-data-volume/sample/honeycomb-refinery/sampling-methods/#ema-dynamic-sampler) for more on EMA Dynamic Samplers, or read [Refinery and EMA Sampling](https://www.honeycomb.io/blog/refinery-ema-sampling) on the Honeycomb blog. # Monitor Honeycomb Refinery Source: https://docs.honeycomb.io/manage-data-volume/sample/honeycomb-refinery/monitor Use Refinery's built-in metrics to monitor cluster health, identify performance bottlenecks, and decide when to adjust your configuration or sampling rules. When scaling Refinery, use [Refinery's metrics](#understanding-refinerys-metrics) to determine if adjustment is needed in your [general configuration](/manage-data-volume/sample/honeycomb-refinery/configure/) and [sampling rules](/manage-data-volume/sample/honeycomb-refinery/sampling-methods/). ## Understanding Refinery's Metrics Refinery emits a number of metrics to give indications about its health as well as its trace throughput and sampling statistics. These metrics can be exposed to [Prometheus](https://prometheus.io/) or sent to Honeycomb, which will need configuration within `config.yaml`. Below is a summary of the key recorded metrics by type. For a complete list of available metrics, please refer to the [Honeycomb Refinery Metrics Documentation](https://github.com/honeycombio/refinery/blob/main/metrics.md) Refinery exports a number of histogram metrics as seen below in [next section](#refinery-system-metrics). Querying histograms in Honeycomb is straight forward. However, histograms in Prometheus have a bit of a learning curve if you are not familiar with them. Please refer to the [Prometheus histogram documentation](https://prometheus.io/docs/practices/histograms/) if you need a refresher. ### Refinery System Metrics Refinery's system metrics include `memory_inuse`, `num_goroutines`, `hostname`, and `process_uptime_seconds`. We recommend monitoring `process_uptime_seconds` alongside `memory_inuse`. If you see unexpected restarts, this could indicate that the process is hitting memory constraints. Refinery's system metrics are only available when sending directly to Honeycomb. If metrics are being sent from Prometheus, Refinery's system metrics are not available. ### Refinery Health Check Metrics `is_ready` : This field indicates whether the system is ready to receive traffic. The value is either 0 or 1. 1 means the system is ready to receive and process traffic. 0 means the system is not ready to receive traffic. `is_alive` : This field indicates whether the system is operational and reporting its status. The value is either 0 or 1. 1 means the system is alive and actively reporting its health status. 0 means the system is not alive, potentially indicating a failure. ### Collector Metrics The collector refers to Refinery's mechanism that intercepts and collects traces in a buffer. Ideally, it holds onto each trace until the root span has arrived. At that point, Refinery sends the trace to the sampler to make a decision whether to keep or drop the trace. In some cases, Refinery may have to make a sampling decision on the trace before the root span arrives. `collect_cache_entries_*` : Records avg, max, min, p50, p95, and p99. Indicates how full the cache is over time. `collector_incoming_queue_*` : Records avg, max, min, p50, p95, and p99. Indicates how full the queue of spans is that were received from outside of Refinery and need to be processed by the collector. `collector_peer_queue_*` : Records avg, max, min, p50, p95, and p99. Indicates how full the queue of spans is that were received from other Refinery peers and need to be processed by the collector. `collector_collect_loop_duration_ms` : Records avg, max, min, p50, p95, and p99. Indicates the duration of each iteration for the primary event processing loop in Refinery. ### Sampler Metrics Sampler metrics will vary with the type of sampler you have configured. Generally, there will be metrics on the number of traces dropped, the number of traces kept, and the sample rate. The fields below are an example of the metrics when the dynamic sampler is configured: `dynsampler_num_dropped` : The number of traces dropped by the sampler. `dynsampler_num_kept` : The number of traces kept by the sampler. `dynsampler_sample_rate_*` : Records avg, max, min, p50, p95, and p99 of the sample rate reported by the configured sampler. ### Incoming and Peer Router Metrics A Refinery host may receive spans both from outside Refinery and from other hosts within the Refinery cluster. In the following fields, `incoming` refers to the process that is listening for incoming events from outside Refinery and `peer` refers to the process that is listening for events redirected from a peer. `upstream` refers to the Honeycomb API. `incoming_router_batch`, `peer_router_batch` : These values increment when Refinery's batch event processing endpoint is hit. `incoming_router_event`, `peer_router_event` : These values increment when Refinery's single event processing endpoint is hit. `incoming_router_dropped`, `peer_router_dropped` : These values increment when Refinery fails to add new spans to a receive buffer when processing new events. These values should be monitored closely as they indicate that spans are being dropped. `incoming_router_span`, `peer_router_span` : These values increment when Refinery accepts events that are part of a trace, also known as spans. `incoming_router_nonspan`, `peer_router_nonspan` : These values increment when Refinery accepts other non-span events that are not part of a trace. The following fields can be used to get a better idea of the traffic that is flowing from incoming sources vs. from peer sources, and to track any errors from the Honeycomb API: * `incoming_router_peer`, `peer_router_peer` * `incoming_router_proxied`, `peer_router_proxied` * `peer_enqueue_errors`, `upstream_enqueue_errors` * `peer_response_20x`, `upstream_response_20x` * `peer_response_errors`, `upstream_response_errors` ### Trace Metrics `trace_accepted` : This field indicates that a new trace has been added to the collector's cache. `trace_duration_ms_*` : Records avg, max, min, p50, p95, and p99. This value can help determine the appropriate configuration for `CacheCapacity`. For more information, see `collect_cache_buffer_overrun`. `trace_send_dropped` : Indicates the number of traces that were dropped by the sampler. When dry run mode is enabled, this metric will increment for each trace. In this case, you can still see the result of sampling decisions by filtering by the configured field for `DryRunFieldName`. `trace_send_kept` : Indicates the number of traces that were kept by the sampler. When dry run mode is enabled, this metric will remain 0, reflecting that we are sending all traces to Honeycomb. In this case, you can still see the result of sampling decisions by filtering by the configured field for `DryRunFieldName`. `trace_send_has_root` : Indicates that the trace was fully finished when it was sent. This is generally what you want to happen, since if the trace was not complete when it was sent, this could indicate an incorrect sampling decision based on your criteria. `trace_send_no_root` : Indicates that traces are being sent before they are completed. This field often correlates with `collect_cache_buffer_overrun`. Another reason why this could happen is if a node shuts down unexpectedly and sends the traces it currently has in its cache. `trace_sent_cache_hit` : Indicates that Refinery received a span belonging to a trace that had already been sent. In this case, Refinery checks the sampling decision for the trace and either sends the span along to Honeycomb immediately, or drops the span. `trace_span_count_*` : Records avg, max, min, p50, p95, and p99. Use this field as an indication of how large your traces are. Note that if you are seeing a high number of `trace_send_no_root`, the `trace_span_count_*` values may be undercounting, since this indicates that traces were not fully complete before they were sent. ## Stress Relief Metrics The Stress Relief system monitors these metrics to calculate the current stress level of the Refinery cluster: * `collector_peer_queue_length` * `collector_incoming_queue_length` * `libhoney_peer_queue_length` * `libhoney_upstream_queue_length` * `memory_heap_allocation` The stress level is calculated and represented as the following two metrics: `stress_level`: a gauge from 0 to 100, where 0 is no stress and 100 is maximum stress. By default, at `stress_level` 90 Stress Relief will activate, and then deactivate once it reaches 75. These values are configurable as `ActivationLevel` and `DeactivationLevel` in the Refinery configuration file. `stress_relief_activated`: a gauge at 0 or 1. # Specify Sampling Methods in Honeycomb Refinery Source: https://docs.honeycomb.io/manage-data-volume/sample/honeycomb-refinery/sampling-methods Define how Refinery samples your traces. Learn how to combine multiple sampling methods for more precise control over which data you keep. Update the fields in `rules.yaml` to specify sampling methods for your data. The [default configuration at installation](#default-configuration) contains the minimum configuration needed to run Refinery. After setting up or modifying sampling rules, we recommend [validating your configuration and doing a Dry Run](#testing-your-sampling-rules) before dropping your traffic. Complete your Refinery set-up after configuring `rules.yaml` by customizing your [Refinery configuration](/manage-data-volume/sample/honeycomb-refinery/configure/) in `config.yaml`. This content applies to Refinery version 3.0 and later. For Refinery version 1.x, visit our GitHub repo for documentation on [`config`](https://github.com/honeycombio/refinery/blob/v1.21.0/config_complete.toml) and [`rules`](https://github.com/honeycombio/refinery/blob/v1.21.0/rules_complete.toml). We recommend [upgrading to Refinery 3.0](/troubleshoot/product-lifecycle/recommended-migrations/upgrade-refinery/) to benefit from new features and improvements. ## Default Configuration The default Refinery configuration uses a hardcoded peer list for file-based peer management. It uses the `DeterministicSampler` Sampling Method and a `SampleRate` of 1, meaning that no traffic will be dropped. In the Refinery GitHub repository, [a minimal default rules file](https://github.com/honeycombio/refinery/blob/main/rules.yaml) exists. Check out our [Sampling Example](#sampling-example), or our Refinery GitHub repository for an [example rules file](https://github.com/honeycombio/refinery/blob/main/rules_complete.yaml). To see the full set of available options, refer below to the [Refinery Rules File](#refinery-rules-file). ## Quick Start Configure sampling methods and rules in `rules.yaml`: 1. Include the [required `__default__` section](#required-default-section) to handle scenarios not defined by your sampling rules 2. Define one or more sampling rules, each with a defined Honeycomb Environment and a [Sampler](#sampling-options) After setting up your sampling rules, we recommend [validating your configuration and doing a Dry Run](#testing-your-sampling-rules) before fully sampling your traffic with Refinery. ## Required Default Section `rules.yaml` **must** contain a `__default__` section under the `Samplers` heading. For installations that expect most events to be matched to one of the primary rules, choose a default rule containing a `DeterministicSampler` and a `SampleRate` of 1, meaning that no unusual traffic will be dropped. For installations expecting most traffic to be matched by the default rule, consider using an `EMADynamicSampler` or `EMAThroughputSampler` as the default, and then write rules to handle special cases. ## Sampling Options Available sampling methods through samplers include: * [`DeterministicSampler`](#deterministic-sampler) * [`DynamicSampler`](#dynamic-sampler) * [`EMADynamicSampler`](#ema-dynamic-sampler) * [`RulesBasedSampler`](#rules-based-sampler) * [`EMAThroughputSampler`](#ema-throughput-sampler) * [`WindowedThroughputSampler`](#windowed-throughput-sampler) * [`TotalThroughputSampler`](#total-throughput-sampler) [`EMADynamicSampler`](#ema-dynamic-sampler) or [`EMAThroughputSampler`](#ema-throughput-sampler) are recommended for most Refinery use cases. ### Concept: Dynamic Sampling Several of our Refinery sampling options use dynamic sampling as indicated by its name. Dynamic Sampling aims to achieve a target rate, weighting rare traffic and frequent traffic differently so as to end up with the correct average. Frequent traffic is sampled less often, while rarer events are kept or sampled more frequently. Use dynamic sampling to keep high-resolution data about unusual events while maintaining a representative sample of your application's overall behavior. To achieve this, configure Refinery to examine the trace for a specific set of fields. For example, if you specify `request.status_code` and `request.method`, then Refinery collects all the values found in those fields anywhere in the trace - for example, "200" and "GET" - together into a key that it hands to the `dynsampler`. The `dynsampler` code will look at the frequency that key appears during the previous time slice, and use that to hand back a desired sample rate. More frequent keys are kept less often, so that an even distribution of traffic across the keyspace is represented in Honeycomb. By selecting fields well, you can drop significant amounts of traffic while still retaining good visibility into the areas of traffic that interest you. For example, if you want to make sure you have a complete list of all URL handlers invoked, you would add the URL (or a normalized form), as one of the fields to include. Be careful in your selection, because if the combination of fields creates a unique key each time, you will not drop any traffic. Because of this, it is not effective to use fields that have unique values, like a UUID, as one of the sampling fields. Each field included should ideally have values that appear many times within any given 30 second window in order to generate a useful sample rate. To see how this differs from random sampling in practice, consider a simple web service with the following characteristics: 90% of traffic is served correctly and returns a `200` response code. The remaining 10% of traffic is divided into a mix of `40x` and `50x` responses. If we sample events randomly, we can see these characteristics. We can do analysis of aggregates such as: what is the average duration of an event, breaking down on fields like `status code`, `endpoint`, `customer_id`, and so on. At a high level, we can still learn a lot about our data from a completely random sample. But what about those `50x` errors? Typically, we would like to look at these errors in high resolution - they might all have different causes, or affect only a subset of customers. Discarding them at the same rate that we discard events describing healthy traffic is unfortunate - the errors are much more interesting! Here is where dynamic sampling can help. Dynamic sampling will adjust the sample rate of traces and events based on their frequency. To achieve the target sample rate, it will drop more of the common events, while lowering the sample rate for less common events, all the way down to `1` and keeping unique events. The details of all of the samplers and their configuration values are documented [in the Refinery Rules documentation](#refinery-rules-file) below. ## Testing Your Sampling Rules Two method exist for testing your sampling rules: using Refinery's [Dry Run Mode](#run-refinery-in-dry-run-mode) to verify your rules, and using [Usage Mode](#use-usage-mode-in-the-query-builder) to check expected versus actual sampling rate. ### Run Refinery in Dry Run Mode When getting started with Refinery or when updating sampling rules, it may be helpful to verify that the rules are working as expected before you start dropping traffic. By enabling Dry Run Mode, all spans in each trace will be marked with the sampling decision in a field called `refinery_kept`. All traces will be sent to Honeycomb regardless of the sampling decision. You can then run queries in Honeycomb on this field to check your results and verify that the rules are working as intended. Enable dry run mode by adding `DryRun = true` in your `config.yaml` configuration. Refer to [Dry Run documentation](/manage-data-volume/sample/honeycomb-refinery/configure/#dryrun) for more details. When Dry Run Mode is enabled: * Refinery will set the `meta.dryrun.sample_rate` attribute on spans. This attribute allows you to inspect what the sample rate will be without sampling your data. * the metric `trace_send_kept` increments for each trace, and the metric for `trace_send_dropped` remains at `0`, which reflects that all traces are being sent to Honeycomb. Also, Refinery can send telemetry that includes information that can help debug the sampling decisions that are made. To enable this, set [`AddRuleReasonToTrace`](/manage-data-volume/sample/honeycomb-refinery/configure/#addrulereasontotrace) to `true` in your `config.yaml` file. Traces sent to Honeycomb will then include the field `meta.refinery.reason`. This field contains text that indicates the rule that caused the trace to be included. ### Use Usage Mode in the Query Builder It may also be helpful to use the ["Usage Mode"](/get-started/manage-costs/how-honeycomb-calculates-usage/#usage-mode) version of the Query Builder to assess your sampling strategy. Since calculations in this mode do not correct for sample rates, you can check how many actual events match each category for a dynamic sampler. ## Sampling Example Here is an example of how we sample events from Honeycomb's ingest service. Since this is a high volume service, we use the EMA Dynamic Sampler (`EMADynamicSampler`) with a target rate of 1/50 traces. Here is what our `rules.yaml` file looks like: ```yaml theme={} RulesVersion: 2 Samplers: __default__: DeterministicSampler: SampleRate: 1 IngestService: EMADynamicSampler: GoalSampleRate: 50 AdjustmentInterval: 60s FieldList: - request.method - request.path - response.status_code ``` where: * The [required default](#required-default-section) section (`__default__`) * applies to all data not applicable to the IngestService conditions * uses a Deterministic Sampler (`DeterministicSampler`) * keeps all applicable traffic with a `SampleRate` of `1` * The IngestService section: * uses a EMA Dynamic Sampler (`EMADynamicSampler`) * has a goal sample rate (`GoalSampleRate`) of `50`, which keeps 1 out of every 50 traces seen. This rate is used by the EMA Dynamic Sampler, which assigns a sample rate for each trace based on the sampling key generated by the fields in `FieldList`. * has an `AdjustmentInterval` of `60`, so the EMA Dynamic Sampler recalculates its internal counters every 60 seconds. While `AdjustmentInterval`'s default value is `15` seconds, we increased this value to `60` seconds, as it is not necessary to evaluate changes more often. * has a `FieldList` selection of `response.status_code` in addition to the HTTP endpoint (represented here by `request.method` and `request.path`), because it allows us to clearly see when there is failing traffic to any endpoint. A useful `FieldList` selection has consistent values for high frequency boring traffic and unique values for outliers and interesting traffic. Read more about the configuration options for the [EMA Dynamic Sampler](#ema-dynamic-sampler). ## Refinery Rules file The Refinery `rules` file is a YAML file. ## Example Below is a simple example of a `rules` file. For a complete example, [visit the Refinery GitHub repository](https://github.com/honeycombio/refinery/blob/main/rules_complete.yaml). ```yaml theme={} RulesVersion: 2 Samplers: __default__: DeterministicSampler: SampleRate: 1 production: DynamicSampler: SampleRate: 2 ClearFrequency: 30s FieldList: - request.method - http.target - response.status_code ``` where: `RulesVersion` is a required parameter used to verify the version of the rules file. It must be set to `2`. `Samplers` maps targets to sampler configurations. Each target is a Honeycomb environment (or a dataset for Honeycomb Classic keys). The value is the sampler to use for that target. A `__default__` target is required. The target called `__default__` will be used for any target that is not explicitly listed. The targets are determined by examining the API key used to send the trace. If the API key is a Honeycomb Classic key with a 32-character hexadecimal value, then the specified dataset name is used as the target. If the API key is a key with 20-23 alphanumeric characters, then the key's environment name is used as the target. The remainder of this page describes the samplers that can be used within the `Samplers` section and the fields that control their behavior. ## Deterministic Sampler The Deterministic Sampler (`DeterministicSampler`) uses a fixed sample rate to sample traces based on their trace ID. This is the simplest sampling algorithm - it is a static sample rate, choosing traces randomly to either keep or send (at the appropriate rate). It is not influenced by the contents of the trace other than the trace ID. ### `SampleRate` The sample rate to use. It indicates a ratio, where one sample trace is kept for every N traces seen. For example, a `SampleRate` of `30` will keep 1 out of every 30 traces. The choice on whether to keep any specific trace is random, so the rate is approximate. The sample rate is calculated from the trace ID, so all spans with the same trace ID will be sampled or not sampled together. A `SampleRate` of `1` or less will keep all traces. Specifying this value is required. * Type: `int` ## Dynamic Sampler The Dynamic Sampler (`DynamicSampler`) is the basic Dynamic Sampler implementation. Most installations will find the EMA Dynamic Sampler to be a better choice. This sampler collects the values of a number of fields from a trace and uses them to form a key. This key is handed to the standard dynamic sampler algorithm, which generates a sample rate based on the frequency with which that key has appeared during the previous `ClearFrequency`. See [https://github.com/honeycombio/dynsampler-go](https://github.com/honeycombio/dynsampler-go) for more detail on the mechanics of the Dynamic Sampler. This sampler uses the `AvgSampleRate` algorithm from that package. ### `SampleRate` The sample rate to use. It indicates a ratio, where one sample trace is kept for every N traces seen. For example, a `SampleRate` of `30` will keep 1 out of every 30 traces. The choice on whether to keep any specific trace is random, so the rate is approximate. The sample rate is calculated from the trace ID, so all spans with the same trace ID will be sampled or not sampled together. A `SampleRate` of `1` or less will keep all traces. Specifying this value is required. * Type: `int` ### `ClearFrequency` The duration after which the Dynamic Sampler should reset its internal counters. It should be specified as a duration string. For example, "30s" or "1m". Defaults to "30s". * Type: `duration` ### `FieldList` A list of all the field names to use to form the key that will be handed to the Dynamic Sampler. The combination of values from all of these fields should reflect how interesting the trace is compared to another. When choosing field names for `FieldList`, a good field selection has consistent values for high-frequency, boring traffic, and unique values for outliers and interesting traffic. Including an error field, or something like `HTTP status code`, is an excellent choice. Using fields with very high cardinality, like `k8s.pod.id`, is a bad choice. If the combination of fields essentially makes each trace unique, then the Dynamic Sampler will sample everything. If the combination of fields is not unique enough, then you will not be guaranteed samples of the most interesting traces. If a trace does not contain any of the fields specified in the FieldList, it will still be evaluated by the sampler. However, since it lacks all key fields, it will be grouped under a single empty (blank) key. This means that all such traces will share the same sample rate, determined by that one shared key. As an example, consider as a good set of fields: the combination of `HTTP endpoint` (high-frequency and boring), `HTTP method`, and `status code` (normally boring but can become interesting when indicating an error) since it will allowing proper sampling of all endpoints under normal traffic and call out when there is failing traffic to any endpoint. As of Refinery 2.8.0, the `root.` prefix can be used to limit the field value to that of the root span. For example, `root.http.response.status_code` will only consider the `http.response.status_code` field from the root span rather than a combination of all the spans in the trace. This is useful when you want to sample based on the root span's properties rather than the entire trace, and helps to reduce the cardinality of the sampler key. In contrast, for example, consider as a bad set of fields: a combination of `HTTP endpoint`, `status code`, and `pod id`, since it would result in keys that are all unique, and therefore result in sampling 100% of traces. For example, rather than a set of fields, using only the `HTTP endpoint` field is a **bad** choice, as it is not unique enough, and therefore interesting traces, like traces that experienced a `500`, might not be sampled. Field names may come from any span in the trace; if they occur on multiple spans, then all unique values will be included in the key. * Type: `stringarray` ### `MaxKeys` Limits the number of distinct keys tracked by the sampler. Once `MaxKeys` is reached, new keys will not be included in the sample rate map, but existing keys will continue to be be counted. Use this field to keep the sample rate map size under control. Defaults to `500`; Dynamic Samplers will rarely achieve their sampling goals with more keys than this. * Type: `int` ### `UseTraceLength` Indicates whether to include the trace length (number of spans in the trace) as part of the key. The number of spans is exact, so if there are normally small variations in trace length, we recommend setting this field to `false` (the default). If your traces are consistent lengths and changes in trace length is a useful indicator to view in Honeycomb, then set this field to `true`. * Type: `bool` ## EMA Dynamic Sampler The Exponential Moving Average (EMA) Dynamic Sampler (`EMADynamicSampler`) attempts to average a given sample rate, weighting rare traffic and frequent traffic differently so as to end up with the correct average. `EMADynamicSampler` is an improvement upon the simple `DynamicSampler` and is recommended for many use cases. Based on the `DynamicSampler`, `EMADynamicSampler` differs in that rather than compute rate based on a periodic sample of traffic, it maintains an Exponential Moving Average of counts seen per key, and adjusts this average at regular intervals. The weight applied to more recent intervals is defined by `weight`, a number between (0, 1). Larger values weight the average more toward recent observations. In other words, a larger weight will cause sample rates more quickly adapt to traffic patterns, while a smaller weight will result in sample rates that are less sensitive to bursts or drops in traffic and thus more consistent over time. Keys that are not already present in the EMA will always have a sample rate of `1`. Keys that occur more frequently will be sampled on a logarithmic curve. Every key will be represented at least once in any given window and more frequent keys will have their sample rate increased proportionally to trend towards the goal sample rate. ### `GoalSampleRate` The sample rate to use. It indicates a ratio, where one sample trace is kept for every N traces seen. For example, a `SampleRate` of `30` will keep 1 out of every 30 traces. The choice on whether to keep any specific trace is random, so the rate is approximate. The sample rate is calculated from the trace ID, so all spans with the same trace ID will be sampled or not sampled together. A `SampleRate` of `1` or less will keep all traces. Specifying this value is required. * Type: `int` ### `AdjustmentInterval` The duration after which the EMA Dynamic Sampler should recalculate its internal counters. It should be specified as a duration string. For example, `30s` or `1m`. Defaults to `15s`. * Type: `duration` ### `Weight` The weight to use when calculating the EMA. It should be a number between `0` and `1`. Larger values weight the average more toward recent observations. In other words, a larger weight will cause sample rates more quickly adapt to traffic patterns, while a smaller weight will result in sample rates that are less sensitive to bursts or drops in traffic and thus more consistent over time. The default value is `0.5`. * Type: `float` ### `AgeOutValue` Indicates the threshold for removing keys from the EMA. The EMA of any key will approach `0` if it is not repeatedly observed, but will never truly reach it, so this field determines what constitutes "zero". Keys with averages below this threshold will be removed from the EMA. Default is the value of `Weight`, as this prevents a key with the smallest integer value (1) from being aged out immediately. This value should generally be less than (\<=) `Weight`, unless you have very specific reasons to set it higher. * Type: `float` ### `BurstMultiple` If set, then this value is multiplied by the sum of the running average of counts to dynamically define the burst detection threshold. If total counts observed for a given interval exceed this threshold, then EMA is updated immediately, rather than waiting on the `AdjustmentInterval`. Defaults to `2`; a negative value disables. With the default of `2`, if your traffic suddenly doubles, then burst detection will kick in. * Type: `float` ### `BurstDetectionDelay` Indicates the number of intervals to run before burst detection kicks in. Defaults to `3`. * Type: `int` ### `FieldList` A list of all the field names to use to form the key that will be handed to the Dynamic Sampler. The combination of values from all of these fields should reflect how interesting the trace is compared to another. When choosing field names for `FieldList`, a good field selection has consistent values for high-frequency, boring traffic, and unique values for outliers and interesting traffic. Including an error field, or something like `HTTP status code`, is an excellent choice. Using fields with very high cardinality, like `k8s.pod.id`, is a bad choice. If the combination of fields essentially makes each trace unique, then the Dynamic Sampler will sample everything. If the combination of fields is not unique enough, then you will not be guaranteed samples of the most interesting traces. If a trace does not contain any of the fields specified in the FieldList, it will still be evaluated by the sampler. However, since it lacks all key fields, it will be grouped under a single empty (blank) key. This means that all such traces will share the same sample rate, determined by that one shared key. As an example, consider as a good set of fields: the combination of `HTTP endpoint` (high-frequency and boring), `HTTP method`, and `status code` (normally boring but can become interesting when indicating an error) since it will allowing proper sampling of all endpoints under normal traffic and call out when there is failing traffic to any endpoint. As of Refinery 2.8.0, the `root.` prefix can be used to limit the field value to that of the root span. For example, `root.http.response.status_code` will only consider the `http.response.status_code` field from the root span rather than a combination of all the spans in the trace. This is useful when you want to sample based on the root span's properties rather than the entire trace, and helps to reduce the cardinality of the sampler key. In contrast, for example, consider as a bad set of fields: a combination of `HTTP endpoint`, `status code`, and `pod id`, since it would result in keys that are all unique, and therefore result in sampling 100% of traces. For example, rather than a set of fields, using only the `HTTP endpoint` field is a **bad** choice, as it is not unique enough, and therefore interesting traces, like traces that experienced a `500`, might not be sampled. Field names may come from any span in the trace; if they occur on multiple spans, then all unique values will be included in the key. * Type: `stringarray` ### `MaxKeys` Limits the number of distinct keys tracked by the sampler. Once `MaxKeys` is reached, new keys will not be included in the sample rate map, but existing keys will continue to be be counted. Use this field to keep the sample rate map size under control. Defaults to `500`; Dynamic Samplers will rarely achieve their sampling goals with more keys than this. * Type: `int` ### `UseTraceLength` Indicates whether to include the trace length (number of spans in the trace) as part of the key. The number of spans is exact, so if there are normally small variations in trace length, we recommend setting this field to `false` (the default). If your traces are consistent lengths and changes in trace length is a useful indicator to view in Honeycomb, then set this field to `true`. * Type: `bool` ## EMA Throughput Sampler The Exponential Moving Average (EMA) Throughput Sampler (`EMAThroughputSampler`) attempts to achieve a given throughput -- number of spans per second -- weighting rare traffic and frequent traffic differently so as to end up with the correct rate. The `EMAThroughputSampler` is an improvement upon the Total Throughput Sampler and is recommended for most throughput-based use cases. Because it like the `EMADynamicSampler`, `EMAThroughputSampler` maintains an Exponential Moving Average of counts seen per key, and adjusts this average at regular intervals. The weight applied to more recent intervals is defined by `weight`, a number between (0, 1) - larger values weight the average more toward recent observations. In other words, a larger weight will cause sample rates more quickly adapt to traffic patterns, while a smaller weight will result in sample rates that are less sensitive to bursts or drops in traffic and thus more consistent over time. New keys that are not already present in the EMA will always have a sample rate of `1`. Keys that occur more frequently will be sampled on a logarithmic curve. Every key will be represented at least once in any given window and more frequent keys will have their sample rate increased proportionally to trend towards the goal throughput. ### `GoalThroughputPerSec` The desired throughput **per second**. This is the number of events per second you want to send to Honeycomb. The sampler will adjust sample rates to try to achieve this desired throughput. This value is calculated for the individual instance, not for the cluster; if your cluster has multiple instances, then you will need to divide your total desired sample rate by the number of instances to get this value. * Type: `int` ### `UseClusterSize` Indicates whether to use the cluster size to calculate the goal throughput. If `true`, then the goal throughput will be divided by the number of instances in the cluster. If `false` (the default), then the goal throughput will be the value specified in `GoalThroughputPerSec`. * Type: `bool` ### `InitialSampleRate` `InitialSampleRate` is the sample rate to use during startup, before the sampler has accumulated enough data to calculate a reasonable throughput. This is mainly useful in situations where unsampled throughput is high enough to cause problems. Default value is `10`. * Type: `int` ### `AdjustmentInterval` The duration after which the EMA Dynamic Sampler should recalculate its internal counters. It should be specified as a duration string. For example, `30s` or `1m`. Defaults to `15s`. * Type: `duration` ### `Weight` The weight to use when calculating the EMA. It should be a number between `0` and `1`. Larger values weight the average more toward recent observations. In other words, a larger weight will cause sample rates more quickly adapt to traffic patterns, while a smaller weight will result in sample rates that are less sensitive to bursts or drops in traffic and thus more consistent over time. The default value is `0.5`. * Type: `float` ### `AgeOutValue` Indicates the threshold for removing keys from the EMA. The EMA of any key will approach `0` if it is not repeatedly observed, but will never truly reach it, so this field determines what constitutes "zero". Keys with averages below this threshold will be removed from the EMA. Default is the value of `Weight`, as this prevents a key with the smallest integer value (1) from being aged out immediately. This value should generally be less than (\<=) `Weight`, unless you have very specific reasons to set it higher. * Type: `float` ### `BurstMultiple` If set, then this value is multiplied by the sum of the running average of counts to dynamically define the burst detection threshold. If total counts observed for a given interval exceed this threshold, then EMA is updated immediately, rather than waiting on the `AdjustmentInterval`. Defaults to `2`; a negative value disables. With the default of `2`, if your traffic suddenly doubles, then burst detection will kick in. * Type: `float` ### `BurstDetectionDelay` Indicates the number of intervals to run before burst detection kicks in. Defaults to `3`. * Type: `int` ### `FieldList` A list of all the field names to use to form the key that will be handed to the Dynamic Sampler. The combination of values from all of these fields should reflect how interesting the trace is compared to another. When choosing field names for `FieldList`, a good field selection has consistent values for high-frequency, boring traffic, and unique values for outliers and interesting traffic. Including an error field, or something like `HTTP status code`, is an excellent choice. Using fields with very high cardinality, like `k8s.pod.id`, is a bad choice. If the combination of fields essentially makes each trace unique, then the Dynamic Sampler will sample everything. If the combination of fields is not unique enough, then you will not be guaranteed samples of the most interesting traces. If a trace does not contain any of the fields specified in the FieldList, it will still be evaluated by the sampler. However, since it lacks all key fields, it will be grouped under a single empty (blank) key. This means that all such traces will share the same sample rate, determined by that one shared key. As an example, consider as a good set of fields: the combination of `HTTP endpoint` (high-frequency and boring), `HTTP method`, and `status code` (normally boring but can become interesting when indicating an error) since it will allowing proper sampling of all endpoints under normal traffic and call out when there is failing traffic to any endpoint. As of Refinery 2.8.0, the `root.` prefix can be used to limit the field value to that of the root span. For example, `root.http.response.status_code` will only consider the `http.response.status_code` field from the root span rather than a combination of all the spans in the trace. This is useful when you want to sample based on the root span's properties rather than the entire trace, and helps to reduce the cardinality of the sampler key. In contrast, for example, consider as a bad set of fields: a combination of `HTTP endpoint`, `status code`, and `pod id`, since it would result in keys that are all unique, and therefore result in sampling 100% of traces. For example, rather than a set of fields, using only the `HTTP endpoint` field is a **bad** choice, as it is not unique enough, and therefore interesting traces, like traces that experienced a `500`, might not be sampled. Field names may come from any span in the trace; if they occur on multiple spans, then all unique values will be included in the key. * Type: `stringarray` ### `MaxKeys` Limits the number of distinct keys tracked by the sampler. Once `MaxKeys` is reached, new keys will not be included in the sample rate map, but existing keys will continue to be be counted. Use this field to keep the sample rate map size under control. Defaults to `500`; Dynamic Samplers will rarely achieve their sampling goals with more keys than this. * Type: `int` ### `UseTraceLength` Indicates whether to include the trace length (number of spans in the trace) as part of the key. The number of spans is exact, so if there are normally small variations in trace length, we recommend setting this field to `false` (the default). If your traces are consistent lengths and changes in trace length is a useful indicator to view in Honeycomb, then set this field to `true`. * Type: `bool` ## Windowed Throughput Sampler Windowed Throughput Sampler (`WindowedThroughputSampler`) is an enhanced version of total throughput sampling. Just like the `TotalThroughput` Sampler, `WindowedThroughputSampler` attempts to meet the goal of fixed number of events per second sent to Honeycomb. The original throughput sampler updates the sampling rate every "ClearFrequency" seconds. While this parameter is configurable, it suffers from the following tradeoff: * Decreasing it is more responsive to load spikes, but with the cost of making the sampling decision on less data. * Increasing it is less responsive to load spikes, but sample rates will be more stable because they are made with more data. The Windowed Throughput Sampler resolves this by introducing two different, tunable parameters: * `UpdateFrequency`: how often the sampling rate is recomputed * `LookbackFrequency`: how much total time is considered when recomputing sampling rate. A standard configuration would be to set `UpdateFrequency` to `1s` and `LookbackFrequency` to `30s`. In this configuration, for every second, we lookback at the last 30 seconds of data in order to compute the new sampling rate. The actual sampling rate computation is nearly identical to the original Throughput Sampler, but this variant has better support for floating point numbers and does a better job with less-common keys. ### `GoalThroughputPerSec` The desired throughput **per second**. This is the number of events per second you want to send to Honeycomb. The sampler will adjust sample rates to try to achieve this desired throughput. This value is calculated for the individual instance, not for the cluster; if your cluster has multiple instances, then you will need to divide your total desired sample rate by the number of instances to get this value. * Type: `int` ### `UseClusterSize` Indicates whether to use the cluster size to calculate the goal throughput. If `true`, then the goal throughput will be divided by the number of instances in the cluster. If `false` (the default), then the goal throughput will be the value specified in `GoalThroughputPerSec`. * Type: `bool` ### `UpdateFrequency` The duration between sampling rate computations. It should be specified as a duration string. For example, `30s` or `1m`. Defaults to `1s`. * Type: `duration` ### `LookbackFrequency` This controls how far back in time to lookback to dynamically adjust the sampling rate. Default is `30 * UpdateFrequencyDuration`. This field is forced to be an **integer multiple** of `UpdateFrequencyDuration`. * Type: `duration` ### `FieldList` A list of all the field names to use to form the key that will be handed to the Dynamic Sampler. The combination of values from all of these fields should reflect how interesting the trace is compared to another. When choosing field names for `FieldList`, a good field selection has consistent values for high-frequency, boring traffic, and unique values for outliers and interesting traffic. Including an error field, or something like `HTTP status code`, is an excellent choice. Using fields with very high cardinality, like `k8s.pod.id`, is a bad choice. If the combination of fields essentially makes each trace unique, then the Dynamic Sampler will sample everything. If the combination of fields is not unique enough, then you will not be guaranteed samples of the most interesting traces. If a trace does not contain any of the fields specified in the FieldList, it will still be evaluated by the sampler. However, since it lacks all key fields, it will be grouped under a single empty (blank) key. This means that all such traces will share the same sample rate, determined by that one shared key. As an example, consider as a good set of fields: the combination of `HTTP endpoint` (high-frequency and boring), `HTTP method`, and `status code` (normally boring but can become interesting when indicating an error) since it will allowing proper sampling of all endpoints under normal traffic and call out when there is failing traffic to any endpoint. As of Refinery 2.8.0, the `root.` prefix can be used to limit the field value to that of the root span. For example, `root.http.response.status_code` will only consider the `http.response.status_code` field from the root span rather than a combination of all the spans in the trace. This is useful when you want to sample based on the root span's properties rather than the entire trace, and helps to reduce the cardinality of the sampler key. In contrast, for example, consider as a bad set of fields: a combination of `HTTP endpoint`, `status code`, and `pod id`, since it would result in keys that are all unique, and therefore result in sampling 100% of traces. For example, rather than a set of fields, using only the `HTTP endpoint` field is a **bad** choice, as it is not unique enough, and therefore interesting traces, like traces that experienced a `500`, might not be sampled. Field names may come from any span in the trace; if they occur on multiple spans, then all unique values will be included in the key. * Type: `stringarray` ### `MaxKeys` Limits the number of distinct keys tracked by the sampler. Once `MaxKeys` is reached, new keys will not be included in the sample rate map, but existing keys will continue to be be counted. Use this field to keep the sample rate map size under control. Defaults to `500`; Dynamic Samplers will rarely achieve their sampling goals with more keys than this. * Type: `int` ### `UseTraceLength` Indicates whether to include the trace length (number of spans in the trace) as part of the key. The number of spans is exact, so if there are normally small variations in trace length, we recommend setting this field to `false` (the default). If your traces are consistent lengths and changes in trace length is a useful indicator to view in Honeycomb, then set this field to `true`. * Type: `bool` ## Rules-based Sampler The Rules-based sampler allows you to specify a set of rules that will determine whether a trace should be sampled or not. Rules are evaluated in order, and the first rule that matches will be used to determine the sample rate. If no rules match, then the `SampleRate` defaults to `1` and all traces will be kept. Rules-based samplers will usually be configured to have the last rule be a default rule with no conditions that uses a downstream Dynamic Sampler to keep overall sample rate under control. ### `Rules` `Rules` is a list of rules to use to determine the sample rate. * Type: `objectarray` ### `CheckNestedFields` Indicates whether to expand nested JSON when evaluating rules. If false (the default), nested JSON will be treated as a string. If `true`, nested JSON will be expanded into a `map[string]interface{}` and the value of the field will be the value of the nested field. For example, if you have a field called `http.request.headers` and you want to check the value of the `User-Agent` header, then you would set this to `true` and use `http.request.headers.User-Agent` as the field name in your rule. This is a computationally expensive option and may cause performance problems if you have a large number of spans with nested JSON. * Type: `bool` ## Rules for Rules-based Samplers Rules are evaluated in order, and the first rule that matches will be used to determine the sample rate. If no rules match, then the `SampleRate` will be `1` and all traces will be kept. If a rule matches, one of three things happens, and they are evaluated in this order: a) if the rule specifies a downstream Sampler, that sampler is used to determine the sample rate; b) if the rule has the `Drop` flag set to `true`, the trace is dropped; c) the rule's sample rate is used. ### `Name` The name of the rule. This field is used for debugging and will appear in the trace metadata if `AddRuleReasonToTrace` is set to `true`. * Type: `string` ### `Sampler` The sampler to use if the rule matches. If this is set, the sample rate will be determined by this downstream sampler. If this is not set, the sample rate will be determined by the `Drop` flag or the `SampleRate` field. * Type: `object` ### `Drop` Indicates whether to drop the trace if it matches this rule. If `true`, then the trace will be dropped. If `false`, then the trace will be kept. * Type: `bool` ### `SampleRate` If the rule is matched, there is no Sampler specified, and the `Drop` flag is `false`, then this is the sample rate to use. * Type: `int` ### `Conditions` Conditions is a list of conditions to use to determine whether the rule matches. All conditions must be met for the rule to match. If there are no conditions, then the rule will always match. A no-condition rule is typically used for the last rule to provide a default behavior. * Type: `objectarray` ### `Scope` Controls the scope of the rule evaluation. If set to `trace` (the default), then each condition can apply to any span in the trace independently. If set to `span`, then all of the conditions in the rule will be evaluated against each span in the trace and the rule only succeeds if all of the conditions match on a single span together. WARNING: The `has-root-span` operator cannot be used with `Scope: span`. The `has-root-span` operator is a trace-level condition that checks whether the trace has a root span. When using `Scope: span`, all conditions must match on a single span, which is incompatible with trace-level operators like `has-root-span`. Combining them will cause the rule to fail evaluation and be skipped. Traces that should match the rule will not be sampled as expected. * Type: `string` ## Conditions for the Rules in Rules-based Samplers Conditions are evaluated in order, and the first condition that does not match will cause the rule to not match. If all conditions match, then the rule will match. If there are no conditions, then the rule will always match. ### `Field` The field to check. This can name any field in the trace. If the field is not present, then the condition will not match. The comparison is case-sensitive. The field can also include a prefix that changes the span used for evaluation of the field. The only prefix currently supported is `root`, as in `root.http.status`. Specifying `root.` causes the condition to be evaluated against the root span. For example, if the `Field` is `root.url`, then the condition will be processed using the url field from the root span. The setting `Scope: span` for a rule does not change the meaning of this prefix -- the condition is still evaluated on the root span and is treated as if it were part of the span being processed. When using the `root.` prefix on a field with a `not-exists` operator, include the `has-root-span: true` condition in the rule. The `not-exists` condition on a `root.`-prefixed field will evaluate to false if the existence of the root span is not checked and the root span does not exist. The primary reason a root span is not present on a trace when a sampling decision is being made is when the root span takes longer to complete than the configured TraceTimeout. * Type: `string` ### `Fields` An array of field names to check. These can name any field in the trace. The fields are checked in the order defined here, and the first named field that contains a value will be used for the condition. Only the first populated field will be used, even if the condition fails. If a `root.` prefix is present on a field, but the root span is not on the trace, that field will be skipped. If none of the fields are present, then the condition will not match. The comparison is case-sensitive. All fields are checked as individual fields before any of them are checked as nested fields (see `CheckNestedFields`). * Type: `stringarray` ### `Operator` The comparison operator to use. String comparisons are case-sensitive. For most cases, only use negative operators (`!=`, `does-not-contain`, `not-exists`, and `not-in`) in a rule with a scope of "span". WARNING: Rules can have `Scope: trace` or `Scope: span`. Using a negative operator with `Scope: trace` will cause the condition be true if **any** single span in the entire trace matches. Use `Scope: span` with negative operators. As a general rule, negative operators are more difficult to use correctly and should be used sparingly. It is usually more effective to use positive operators and be more explicit about rules applied. * Type: `string` * Options: `=`, `!=`, `>`, `<`, `>=`, `<=`, `starts-with`, `contains`, `does-not-contain`, `exists`, `not-exists`, `has-root-span`, `matches`, `in`, `not-in` ### `Value` The value to compare against. If `Datatype` is not specified, then the value and the field will be compared based on the type of the field. The `in` and `not-in` operators can accept a list of values, which should all be of the same datatype. * Type: `sliceorscalar` ### `Datatype` The datatype to use when comparing the value and the field. If `Datatype` is specified, then both values will be converted (best-effort) to that type and then compared. Errors in conversion will result in the comparison evaluating to `false`. This is especially useful when a field like `http status code` may be rendered as strings by some environments and as numbers or booleans by others. The best practice is to always specify `Datatype`; this avoids ambiguity, allows for more accurate comparisons, and offers a minor performance improvement. * Type: `string` * Options: `string`, `int`, `float`, `bool` ## Total Throughput Sampler Total Throughput Sampler (`TotalThroughputSampler`) attempts to meet a goal of a fixed number of events per second sent to Honeycomb. This sampler is **deprecated** and present mainly for compatibility. Consider using either `EMAThroughputSampler` or `WindowedThroughputSampler` instead. If your key space is sharded across different servers, then this is a good method for making sure each server sends roughly the same volume of content to Honeycomb. It performs poorly when the active keyspace is very large. `GoalThroughputPerSec` \* `ClearFrequency` defines the upper limit of the number of keys that can be reported and stay under the goal, but with that many keys, you'll only get one event per key per `ClearFrequencySec`, which is very coarse. Aim for at least 1 event per key per sec to 1 event per key per 10sec to get reasonable data. In other words, the number of active keys should be less than 10 \* `GoalThroughputPerSec`. ### `GoalThroughputPerSec` The desired throughput per second of events sent to Honeycomb. This is the number of events per second you want to send. This is not the same as the Sample Rate. * Type: `int` ### `UseClusterSize` Indicates whether to use the cluster size to calculate the goal throughput. If `true`, then the goal throughput will be divided by the number of instances in the cluster. If `false` (the default), then the goal throughput will be the value specified in `GoalThroughputPerSec`. * Type: `bool` ### `ClearFrequency` The duration after which the Dynamic Sampler should reset its internal counters. It should be specified as a duration string. For example, "30s" or "1m". Defaults to "30s". * Type: `duration` ### `FieldList` A list of all the field names to use to form the key that will be handed to the Dynamic Sampler. The combination of values from all of these fields should reflect how interesting the trace is compared to another. When choosing field names for `FieldList`, a good field selection has consistent values for high-frequency, boring traffic, and unique values for outliers and interesting traffic. Including an error field, or something like `HTTP status code`, is an excellent choice. Using fields with very high cardinality, like `k8s.pod.id`, is a bad choice. If the combination of fields essentially makes each trace unique, then the Dynamic Sampler will sample everything. If the combination of fields is not unique enough, then you will not be guaranteed samples of the most interesting traces. If a trace does not contain any of the fields specified in the FieldList, it will still be evaluated by the sampler. However, since it lacks all key fields, it will be grouped under a single empty (blank) key. This means that all such traces will share the same sample rate, determined by that one shared key. As an example, consider as a good set of fields: the combination of `HTTP endpoint` (high-frequency and boring), `HTTP method`, and `status code` (normally boring but can become interesting when indicating an error) since it will allowing proper sampling of all endpoints under normal traffic and call out when there is failing traffic to any endpoint. As of Refinery 2.8.0, the `root.` prefix can be used to limit the field value to that of the root span. For example, `root.http.response.status_code` will only consider the `http.response.status_code` field from the root span rather than a combination of all the spans in the trace. This is useful when you want to sample based on the root span's properties rather than the entire trace, and helps to reduce the cardinality of the sampler key. In contrast, for example, consider as a bad set of fields: a combination of `HTTP endpoint`, `status code`, and `pod id`, since it would result in keys that are all unique, and therefore result in sampling 100% of traces. For example, rather than a set of fields, using only the `HTTP endpoint` field is a **bad** choice, as it is not unique enough, and therefore interesting traces, like traces that experienced a `500`, might not be sampled. Field names may come from any span in the trace; if they occur on multiple spans, then all unique values will be included in the key. * Type: `stringarray` ### `MaxKeys` Limits the number of distinct keys tracked by the sampler. Once `MaxKeys` is reached, new keys will not be included in the sample rate map, but existing keys will continue to be be counted. Use this field to keep the sample rate map size under control. Defaults to `500`; Dynamic Samplers will rarely achieve their sampling goals with more keys than this. * Type: `int` ### `UseTraceLength` Indicates whether to include the trace length (number of spans in the trace) as part of the key. The number of spans is exact, so if there are normally small variations in trace length, we recommend setting this field to `false` (the default). If your traces are consistent lengths and changes in trace length is a useful indicator to view in Honeycomb, then set this field to `true`. * Type: `bool` # Scale and Size Honeycomb Refinery Source: https://docs.honeycomb.io/manage-data-volume/sample/honeycomb-refinery/scale-size Size and scale your Refinery cluster using Honeycomb's recommended configuration options and the Refinery Operations Board Template to track performance. Use the [Refinery Board Template](/observe/boards/templates/#refinery-operations) to create Boards that provide an overview of your sampling operations. Refinery offers a range of [configuration options](/manage-data-volume/sample/honeycomb-refinery/configure/) to help operators tune it for varying volumes and shapes of telemetry data. After your initial [setup](/manage-data-volume/sample/honeycomb-refinery/set-up/), we recommend increasing RAM and CPU cores as needed. Use the guidance on this page for scaling, and consult our [troubleshooting](/troubleshoot/common-issues/refinery/) documentation for additional support. Refinery is a stateful service and is not optimized for dynamic auto-scaling. Changes in cluster membership can temporarily cause inconsistent sampling decisions or dropped traces. We recommend provisioning Refinery for your anticipated peak load. ## Understanding Stress Relief Refinery includes a built-in mechanism called [Stress Relief](/manage-data-volume/sample/honeycomb-refinery/configure/#stress-relief) that activates when the system is under heavy load. Frequent or prolonged activations indicate that Refinery is under-provisioned for the current load. You can monitor this via the `stress_relief_activated` field in Refinery internal metrics. ### Identifying Resources to Adjust To determine which resources need to be increased, check the activation reasons in Refinery logs: 1. Look for log messages like `StressRelief has been activated`. 2. Check the `reason` field in the log message to understand what triggered the activation. For example, a reason of [`MaxAlloc`](/manage-data-volume/sample/honeycomb-refinery/configure/#maxalloc) indicates a sudden memory usage spike. 3. Use this information to determine which resources need to be increased, such as memory, CPU, or queue sizes. ## Scaling Refinery Scaling Refinery effectively involves choosing the right balance between vertical and horizontal scaling. ### Vertical vs. Horizontal Scaling We recommend prioritizing vertical scaling (adding resources to existing nodes) over horizontal scaling (adding more nodes) whenever possible. This approach: * Reduces cluster size * Decreases the amount of peer-to-peer communication traffic * Simplifies management by having fewer nodes to maintain Focus on ensuring fewer nodes can handle your peak load effectively before considering adding additional instances. Refinery's maximum throughput is limited by single-thread CPU performance. If Refinery is not using all allocated CPU but is still falling behind processing incoming traffic, adding more CPU to a single host will not increase throughput. In this case, increase cluster size to add parallel Refinery instances. ## Managing Queues and Mapping Resources Queues control how spans are buffered before sampling. Proper queue configuration ensures that Refinery can handle peak load efficiently. ### Configuring `IncomingQueueSize` The [`IncomingQueueSize`](/manage-data-volume/sample/honeycomb-refinery/configure/#incomingqueuesize) value sets the maximum number of spans that a Refinery host can receive and queue for sampling. Monitor the current queue size using the `collector_incoming_queue_length` metric and watch for `incoming_router_dropped` values above 0. #### Interpreting Queue Length Metrics Understand what queue behavior tells you about Refinery’s ability to handle incoming traffic. * **Temporary increases:** Normal during traffic spikes when Refinery temporarily cannot process incoming data at arrival rate. * **Rising trend:** Indicates Refinery is gradually falling behind the incoming load. * **Queue at maximum:** Indicates Refinery cannot handle peak load and is dropping data. #### Scaling Guidance Use these steps to decide how to adjust queues, CPU, and cluster size for optimal performance. 1. **Memory check:** If `memory_inuse` is within 80% of allocated memory, try increasing [`IncomingQueueSize`](/manage-data-volume/sample/honeycomb-refinery/configure/#incomingqueuesize) to absorb load. 2. **Queue size limitation:** Increasing queue size delays failure but does not increase overall throughput. 3. **CPU scaling:** To increase throughput, identify whether CPU is the bottleneck and scale CPU resources accordingly. 4. **Horizontal scaling:** Add instances only if vertical scaling is insufficient. ### Configuring `PeerQueueSize` The [`PeerQueueSize`](/manage-data-volume/sample/honeycomb-refinery/configure/#peerqueuesize) value sets the maximum spans that can be received from peer Refinery hosts and queued for sampling. Apply the same scaling strategy as [`IncomingQueueSize`](/manage-data-volume/sample/honeycomb-refinery/configure/#incomingqueuesize), but note that adding instances to reduce peer queue length has diminishing returns: more peers increase overall cluster communication overhead, reinforcing the preference for vertical scaling. ### Configuring `AvailableMemory` The [`AvailableMemory`](/manage-data-volume/sample/honeycomb-refinery/configure/#availablememory) value sets the maximum amount or RAM that Refinery can use for processing and queues. #### Setting Initial Memory Values Set memory values to ensure Refinery has enough headroom for normal operation. * Set `AvailableMemory` to roughly 85% of total system memory. * Set [`MaxMemoryPercentage`](/manage-data-volume/sample/honeycomb-refinery/configure/#maxmemorypercentage) to `75`, indicating that Refinery can use up to 75% of [`AvailableMemory`](/manage-data-volume/sample/honeycomb-refinery/configure/#availablememory). For a 4GB system, set [`AvailableMemory`](/manage-data-volume/sample/honeycomb-refinery/configure/#availablememory) to \~3.4GB and [`MaxMemoryPercentage`](/manage-data-volume/sample/honeycomb-refinery/configure/#maxmemorypercentage) to 75% (\~2.5GB usable). #### Tuning Memory for Stability Adjust memory allocations to prevent restarts and handle peak load safely. Monitor `process_uptime_seconds` for unexpected restarts. If Refinery restarts due to Out-of-Memory exceptions or the host's Out-of-Memory Killer, either increase the memory made available to the Refinery host or reduce [`MaxMemoryPercentage`](/manage-data-volume/sample/honeycomb-refinery/configure/#maxmemorypercentage) to provide more headroom. # Set Up Honeycomb Refinery Source: https://docs.honeycomb.io/manage-data-volume/sample/honeycomb-refinery/set-up Install and configure Refinery for the first time, connect it to your data pipeline, and prepare it to start making tail-based sampling decisions. Just getting started with Refinery? Check out the [Introduction to Refinery](https://academy.honeycomb.io/app/courses/96b6353d-28da-4b73-9a45-e72db585cb7a) course in the [Honeycomb Academy](https://academy.honeycomb.io/)! This guided tour walks you through configuring and managing sampling strategies with Refinery, so you can get hands-on experience before deploying to your production environment. Set up Honeycomb Refinery on Kubernetes, or in Linux x86-64/AMD64 and Linux ARM64 environments. Refinery is designed to sit within your infrastructure where all sources of Honeycomb events can reach it. A standard deployment will have a cluster of servers running Refinery accessible via a load balancer. Refinery instances must be able to communicate with each other to concentrate traces on single servers. For the quickest way to get started using Refinery: 1. Meet [system requirements](#system-requirements) before starting 2. [Download and install](#getting-started) the latest version of Refinery 3. [Set up your cluster](#set-up-your-refinery-cluster) of Refinery processes 4. Customize your [configuration and sampling rules](#refinery-configuration) ## System Requirements To begin, your Refinery cluster requires a minimum of: * a `linux/amd64` or `linux/arm64` operating system * 2GB RAM for each server used * Access to 2 cores for each server used In many cases, Refinery only needs one node. If experiencing a large volume of traffic, you may need multiple Refinery nodes, and likely need a small Redis instance to handle scaling. We recommend increasing the amount of RAM and the number of cores after your initial set-up. Use our [scale](/manage-data-volume/sample/honeycomb-refinery/scale-size/) and [troubleshooting](/troubleshoot/common-issues/refinery/) documentation to learn more. ## Getting Started The recommended way to run Refinery on Kubernetes is with its [Helm chart](https://artifacthub.io/packages/helm/honeycomb/refinery). 1. Add the Honeycomb Helm repository. ```shell theme={} helm repo add honeycomb https://honeycombio.github.io/helm-charts ``` 2. Update the Honeycomb repository to ensure that `helm` has the latest chart versions. ```shell theme={} helm repo update honeycomb ``` 3. Install the latest version of the Refinery Helm chart with default values. ```shell theme={} helm install refinery honeycomb/refinery ``` Helm chart versions and Refinery versions are not in sync. For example, Refinery chart version `2.15.5` installs Refinery version `2.9.4`. When installing a specific version, you can check the [Refinery Helm chart documentation](https://artifacthub.io/packages/helm/honeycomb/refinery) to see which chart version installs the version of Refinery you want. Running on containers? We have a Docker image available on [Docker Hub](https://hub.docker.com/r/honeycombio/refinery). Find our [latest release of Refinery for your operating system and architecture on GitHub](https://github.com/honeycombio/refinery/releases/latest). Use the command line script below to download the latest released `.rpm` asset for `x86_64` from GitHub, install, and then run Refinery: ```shell theme={} curl -L -O https://github.com/honeycombio/refinery/releases/download/latest/refinery-2.9.4.x86_64.rpm rpm -ivh refinery-2.9.4.x86_64.rpm systemctl start refinery.service ``` In the above example, we use `systemctl` to run the [Refinery service](https://github.com/honeycombio/refinery/blob/main/refinery.service). Logs can be found at `/var/log/journal/refinery.service.log`. ### Command Line Flags The Refinery executable has the following command line flags: `-c`, `--config=` : Path to config file (default: `/etc/refinery/refinery.yaml`) `-r`, `--rules_config=` : Path to rules config file (default: `/etc/refinery/rules.yaml`) `-v`, `--version` : Print version number and exit `-d`, `--debug` : If enabled, runs debug service (runs on the first open port between `localhost:6060` and `:6069` by default). Can be used with a debug service, which allows you to use [`pprof`](https://github.com/google/pprof) to visualize and analyze profiling data. `-h`, `--help` : Show help message ## Set Up Your Refinery Cluster Be sure to keep configuration in-sync between the Refinery processes, so that your traces are consistent. Ensure that your Refinery cluster(s) meet the [minimum system requirements](#system-requirements). We recommend that your list of Refinery peers be configured through Redis (see [Redis-based peer management](/manage-data-volume/sample/honeycomb-refinery/configure/#redis-peer-management)). The Redis server can be small since it only maintains the list of peers. Should the Redis service become unavailable, Refinery instances will continue to use their last known peer list for inter-peer communication. Refinery does not currently support Redis Cluster or the Redis Sentinel protocol. For services that are currently sending events directly to Honeycomb's API, update these services' Honeycomb `API Host` property to be the URL for your Refinery cluster's load balancer to start sampling events with Refinery. ## Refinery Configuration The default configuration at installation will allow you to run Refinery without any other changes. Be sure to run Refinery in [Dry Run Mode](/manage-data-volume/sample/honeycomb-refinery/sampling-methods/#run-refinery-in-dry-run-mode) to verify your configuration before dropping traffic. To tune Refinery to your needs, Refinery's configuration requires additional changes in two files: * `config.yaml` contains **general configuration** options, such as Network, Access Key, and Peer Management settings. Read our [documentation on all available configuration options](/manage-data-volume/sample/honeycomb-refinery/configure/). * `rules.yaml` contains **sampling rules configuration**. Read our [documentation on all supported sampling methods and their associated configuration](/manage-data-volume/sample/honeycomb-refinery/sampling-methods/). As you modify, check out our [scale](/manage-data-volume/sample/honeycomb-refinery/scale-size/) and [troubleshooting](/troubleshoot/common-issues/refinery/) documentation for recommendations and strategies. # Sampled Data in Honeycomb Source: https://docs.honeycomb.io/manage-data-volume/sample/sampled-data-in-honeycomb Find out how Honeycomb adjusts query results to account for sample rate and what to keep in mind when working with sampled data in your datasets. Learn how Honeycomb adjusts for sample rate when querying sampled data and considerations for working with sampled data. ## How Honeycomb Adjusts for Sample Rate When you sample your data with our sampling techniques, each span in a trace is given a `SampleRate` attribute that represents `N` when you only sample `1/N` traces. This allows Honeycomb to weight counts to compensate for the fact that you are sampling your data. For example, you are doing head sampling at a 10% sampling rate, which means only 10% of traces are exported to Honeycomb: | Trace ID | Sample Rate (on each span) | duration\_ms | | -------- | -------------------------- | ------------ | | abcd1234 | 10 | 200 | | 4321dcba | 10 | 1100 | In this example, the `SampleRate` attribute is set to `10` because you are sampling 10% of traces, or 1 in 10 traces. With this information, Honeycomb can correct for sample rate and calculate accurate values for various aggregations: * `COUNT` of traces: `(2 * 10) = 20` * `AVG(duration_ms)`: `((200 * 10) + (1100 * 10)) / (10 + 10) = 650` This means you can send less data and yet still see usefully accurate data in Honeycomb. Sample rate correction applies to `SUM` and percentile aggregations as well. By setting the `SampleRate` attribute, your sampling techniques can be as simple or sophisticated as you need, and Honeycomb will do the rest. If you're using [Refinery](/manage-data-volume/sample/honeycomb-refinery/), this is done automatically for its dynamic samplers. ## `COUNT_DISTINCT` and Sampled Data [Query Builder's](/investigate/query/build/) `COUNT_DISTINCT` operator does not compensate for sampling rate, so use it with care when working with sampled data. `COUNT_DISTINCT` estimates the count of distinct values in a field using the [HyperLogLog algorithm](https://en.wikipedia.org/wiki/HyperLogLog) and can only count values that are actually present in the data. When using `COUNT_DISTINCT` in a query, you can view the `average sample rate` for the query. Locate it in the metadata below the [result summary table](/investigate/query/build/#select-summary-table) with `elapsed query time` and `rows examined` fields. `average sample rate` displays the average sample rate across all underlying events included in the query result. ## Query Sampled Data Without Correcting for Sample Rate Sometimes you may want to query sampled data without taking sample rate into account. For example, you want to see how many actual events your dynamic sampler sends so you can adjust your sampling strategy. Or you may need to debug issues with the sampled data. For these cases, you can use [Usage Mode](/get-started/manage-costs/how-honeycomb-calculates-usage/#usage-mode). Usage Mode provides a query builder that evaluates queries in an unweighted mode that does not correct for sample rate. To access Usage Mode: 1. Select **Usage** in the left navigation of the Honeycomb UI 2. Under **Per-environment Breakdown**, select **Usage Mode** for the environment you want to query Calculations in this mode don't correct for sample rates In Usage Mode, you have access to the `Sample Rate` field, and `COUNT` (and all other calculation operations) are unweighted. # Notify & Alert: Overview Source: https://docs.honeycomb.io/notify Set up Triggers and SLOs to alert your team when conditions are met, and route notifications to Slack, PagerDuty, Microsoft Teams, or a custom webhook. Honeycomb provides different methods of defining conditions that can result in alerts. You can choose who to notify when a condition is met--whether that is an individual, a popular service, or a custom integration that you build. Use triggers to send alerts when thresholds that you define and configure are passed. Use Service Level Objectives (SLOs) to define an agreement regarding delivery of a given service and be alerted when your SLO budget is threatened. ## Integrations Send trigger alerts and SLO burn alerts to popular services. Use PagerDuty as a recipient for Honeycomb trigger alerts and SLO burn alerts. Use Slack as a recipient for Honeycomb trigger alerts and SLO burn alerts. Use Microsoft Teams as a recipient for Honeycomb trigger alerts and SLO burn alerts. Use a Webhook as a recipient for Honeycomb trigger alerts and SLO burn alerts. This allows you to build custom integrations that receive JSON payloads from Honeycomb upon alerts firing. # What is Anomaly Detection? Source: https://docs.honeycomb.io/notify/anomaly-detection Anomaly Detection watches your services and notifies you when behavior deviates from normal, without requiring you to define thresholds in advance. Beta Anomaly Detection watches your services and tells you when something is worth investigating. It builds a statistical baseline of normal behavior for each service, then notifies you when behavior deviates from that baseline, so you can catch problems without predicting a failure mode or setting a threshold in advance. ## What you can do With Anomaly Detection, you can: * Catch a failure mode you haven't written a Trigger for, since Anomaly Detection doesn't require you to predict what could go wrong. * Find out when a service stops sending data entirely. * Get error rate coverage across many services without hand-configuring a threshold for each one. * Hand an anomaly straight to a Canvas investigation, so a likely cause is waiting by the time you look. For step-by-step investigation guides, visit: * [Investigate an Error Rate Anomaly](/notify/anomaly-detection/use-cases/investigate-error-rate/) * [Diagnose a Silent Outage](/notify/anomaly-detection/use-cases/diagnose-silent-outage/) ## How it works Honeycomb runs a continuous cycle for each monitored service, then surfaces the results through a set of states, an eligibility check, and a sensitivity threshold you control. ### The detection cycle For each monitored service, Anomaly Detection runs these steps: 1. **Onboarding**: Honeycomb identifies eligible services automatically and enrolls them using their existing historical data. Honeycomb then builds a statistical baseline from that historical data, defining what normal looks like for the service. (Honeycomb will continue to analyze services and signals for eligibility, traffic patterns, and detection, so the baseline adapts as a service's behavior evolves.) 2. **Aggregate**: Honeycomb continuously aggregates the relevant signal in real time. 3. **Detect**: Honeycomb compares live values against the baseline and, when a sustained deviation occurs, flags an anomaly and sends a notification. The baseline assumes relatively stable traffic. Services with strong daily or weekly cycles, such as predictable weekday spikes, can generate false positives until seasonality support ships. ### Signals Anomaly Detection currently covers two signals, built on Events data for services: | Signal | What it detects | | -------------- | ------------------------------------------------------------------------------------------------------------- | | **Error rate** | The service's error rate deviates significantly from its historical baseline. | | **Presence** | The service's data stream disappears entirely, for example after a failed deployment or a broken integration. | ### Service states Each service shows one of the following states, reflecting its current eligibility and monitoring status: | State | Description | | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Onboarding** | The service was recently identified as eligible and is still accumulating data before detection starts. | | **Normal** | The service is eligible for monitoring, turned on, and currently free of active anomalies. | | **Anomalous** | The service is eligible, turned on, and has an anomaly currently active. | | **Ineligible** | The service has too little continuous data for reliable detection. Honeycomb pauses monitoring automatically and resumes it on its own once data coverage recovers. | | **Off / Paused** | Monitoring was manually turned off. You can re-enable the service at any time. | ### Service eligibility Honeycomb evaluates services against a rolling data coverage window to decide whether detection is likely to produce meaningful results. Ineligible services remain visible in your services list, so you can see your full coverage picture along with the reason a given service isn't monitored yet. ### Sensitivity thresholds Each signal has its own sensitivity control: * **Error rate**: Uses a named sensitivity threshold (high, medium (default), or low). * **Presence**: Uses a time-based threshold, set to five minutes by default, that determines how long a service's data stream can go quiet before Honeycomb flags it as an anomaly. ### MCP support Anomaly Detection service profiles are available through the Honeycomb MCP server, so agents can pull anomaly status alongside service map data. To learn more, visit [Service Map and Anomalies](/integrations/mcp/tools#service-map-and-anomalies-2). ## Choosing between Anomaly Detection, Triggers, and BubbleUp Which tool fits depends on how much you already know about the problem: * **You already know what could go wrong and want to set a specific threshold**: Use a [Trigger](/notify/triggers/). Triggers are static: you define the condition, and Honeycomb checks your data against it. * **You already know something is wrong and need to find why**: Use BubbleUp. Select the unusual region of data, and BubbleUp highlights which dimensions differ most from the baseline. * **You want Honeycomb to tell you what to watch for**: Use Anomaly Detection. It learns what normal looks like for a service and alerts you when something changes, with no configuration required. These tools work together, each covering a different stage of the same investigation. When Anomaly Detection surfaces an anomaly, it can automatically start a Canvas investigation that surfaces a likely cause, so diagnosis is already underway by the time you look. To learn how to set up auto-investigation, visit [Auto-investigate Anomalies](/investigate/canvas/auto-investigate#anomaly-detections). ## Next steps * To get started with a service, visit [Get Started with Anomaly Detection](/notify/anomaly-detection/get-started/). * For real-world scenarios, visit: * [Investigate an Error Rate Anomaly](/notify/anomaly-detection/investigate-error-rate/) * [Diagnose a Silent Outage](/notify/anomaly-detection/diagnose-silent-outage/) # Get Started with Anomaly Detection Source: https://docs.honeycomb.io/notify/anomaly-detection/get-started Enable monitoring for a service, adjust sensitivity, and choose who gets notified when an anomaly is detected. Beta Honeycomb automatically identifies eligible services for Anomaly Detection and begins monitoring them without extra setup. You turn on the signals you want to track, adjust sensitivity, and choose who gets notified. ## Exploring your services Check which services Honeycomb already monitors and how each one is performing. 1. Select **Anomalies** () from the navigation menu. 2. Use the search bar to find a service by name, status, or signal, or select a column header to sort the list. Screenshot of Anomaly Detection listing page. Shows multiple services tagged as Normal and one service tagged as Anomalous. Each row shows a service's current status, configured recipients, monitored signals, and the last known anomaly for each signal. Selecting a service opens its detail page. ## Enabling a signal Turn on a signal to start building a baseline for a service. 1. From the Anomalies list, select a service to open its detail page. 2. Select the **Error Rate** or **Presence** view. 3. Use the **Enable** toggle to turn monitoring on. Screenshot of Anomaly Detection Error Rate signal for a service, showing the Enable toggle. The service remains in **Onboarding** while Honeycomb accumulates enough data to build a baseline, then moves into **Normal** once detection is active. ## Investigating an anomaly When a service shows as **Anomalous**, start here to explore the data behind it. 1. From the Anomalies list, find the service. 2. Open the investigation: * To launch a new investigation, select **Investigate**. * If an investigation is already underway, select **View Investigation**. 3. Review the chart and any linked Canvas investigation to see what changed. Canvas surfaces a likely cause automatically when you turn on [auto-investigate](#turning-on-automatic-canvas-investigations) for that service. ## Adjusting the sensitivity threshold Adjust sensitivity when a signal is too noisy or too quiet for a given service. ### Error rate 1. Select the **Error Rate** view. 2. Locate the sensitivity threshold and select **Change**. 3. Select the sensitivity dropdown, and choose a level. 4. Select **Save**. Screenshot of Anomaly Detection Error Rate signal for a service, showing the sensitivity threshold dropdown options. ### Presence The Presence view shows a sensitivity threshold in minutes, set to 5 minutes by default. This is the maximum gap in a service's data stream before Honeycomb flags it as an anomaly. Higher sensitivity flags smaller deviations and produces more notifications; lower sensitivity flags only larger deviations. ## Managing recipients Anomaly Detection surfaces anomalies in the product on its own, but reaching your team requires at least one configured recipient. Error Rate and Presence each have their own recipient list, so a recipient added on one signal's tab doesn't automatically notify on the other. ### Adding a recipient Add a recipient so Honeycomb notifies someone when an anomalous period starts or ends. 1. From a service's detail page, select the **Error Rate** or **Presence** view. 2. Select **Add Recipient**. 3. Choose a provider. Before adding Slack and PagerDuty recipients, configure them in the [Integration Center](/notify/). 4. Enter the recipient, such as an email address or Slack channel. For PagerDuty, also set the severity. To send a test notification, select the Send icon () next to the recipient. Use the **Mute** toggle to delay notifications for a configured recipient until you are ready to send them. 5. Select **Save**. Use the **Mute** toggle to configure a recipient and delay their notifications until you are ready to send them. Honeycomb always shows the anomaly in the Anomalies list and on the service's detail page; external notifications go out only when you configure a recipient. ### Editing a recipient 1. From the recipient list, select the Edit icon () next to the recipient. 2. Update the fields and select **Save**. ### Removing a recipient 1. From the recipient list, select the Remove icon () next to the recipient. 2. Select **Remove** to confirm. ## Turning on automatic Canvas investigations Turn on auto-investigation to let Canvas start investigating as soon as Honeycomb detects an anomaly, before your team opens the product. To learn how to set up auto-investigation, visit [Auto-investigate Anomalies](/investigate/canvas/auto-investigate#anomaly-detections). ## Pausing monitoring for a service Pause a signal to stop notifications temporarily while keeping your configuration intact. Use the **Enable** toggle on a signal's tab to turn monitoring off. Honeycomb preserves your on/off intent and resumes monitoring only on signals you left enabled, even if the service later becomes ineligible and then eligible again. ## Best practices Once you've enabled a service, use these recommendations to tune Anomaly Detection for real-world traffic. * **Lower sensitivity before turning a signal off.** If a service is noisy, set it to Low sensitivity instead of disabling monitoring entirely. * **Treat an ineligible service as useful information.** A service that can't produce reliable detections yet is telling you something about its data coverage, which is often worth investigating on its own. * **Add a recipient before you need one.** Make sure Honeycomb can notify someone as soon as an anomaly occurs. * **Pair Anomaly Detection with Canvas where you already use Slack.** Auto-investigate works best where a Slack channel is already configured as a recipient, since Canvas can join the thread directly. ## Troubleshooting If you experience difficulties when working with Anomaly Detection, explore these solutions to common issues. ### Monitoring status #### A service shows as Ineligible Honeycomb bases eligibility on a rolling data coverage window. A service that recently changed traffic patterns, or that sends data intermittently, can drop below the coverage Honeycomb needs for a reliable baseline. Monitoring resumes automatically once the service's data coverage recovers; you don't need to re-enable it. To check why a service is ineligible: 1. Select **Anomalies** () from the navigation menu. 2. Select the service. 3. Review the coverage stat next to the service's status, which shows its current data coverage against the threshold Honeycomb requires. #### A service stays in Onboarding longer than expected Onboarding reflects how much historical data Honeycomb has accumulated for the service so far. A service with sparse or irregular data takes longer to build a reliable baseline than one with continuous traffic. To check a service's onboarding progress: 1. Select **Anomalies** () from the navigation menu. 2. Select the service. 3. Select the **Error Rate** or **Presence** view to explore its current state and how much data Honeycomb has collected so far. #### Anomaly Detection flags a normal, expected traffic pattern The baseline assumes relatively stable traffic. A service with a strong daily or weekly cycle, such as a predictable weekday spike or weekend drop, can trigger false positives, since the current algorithm doesn't yet model seasonality. To reduce false positives until seasonality support ships, lower the service's sensitivity threshold: 1. Select **Anomalies** () from the navigation menu. 2. Select the service. 3. Select the **Error Rate** view. 4. Select the sensitivity dropdown and choose **Low**. 5. Select **Save**. ### Notifications #### I am not getting notified about an anomaly On the service's detail page, check that: * The signal is enabled * At least one recipient is configured * The recipient isn't muted Honeycomb still shows the anomaly in the Anomalies list and on the service's detail page even when no recipient is configured. #### A signal didn't resume monitoring after a service became eligible again Honeycomb preserves your on/off intent for each signal. If you turned a signal off before the service became ineligible, Honeycomb keeps it off rather than resuming it automatically. To resume monitoring: 1. Select **Anomalies** () from the navigation menu. 2. Select the service. 3. Locate the **Enable** toggle and turn monitoring back on. # Diagnose a Silent Outage Source: https://docs.honeycomb.io/notify/anomaly-detection/use-cases/diagnose-silent-outage Use the Presence signal to confirm whether a service has gone quiet because of a real problem or an expected change. Beta When a service stops sending data entirely, there is no error to point you toward a cause, since the service isn't emitting anything at all. This workflow uses the Presence signal to confirm the outage, rule out expected causes, and hand off to the right team with evidence. ## Investigate the anomaly Open the anomaly and start an investigation: 1. Select **Anomalies** () from the navigation menu. 2. Find the service showing as **Anomalous**. 3. Select **Investigate** (or **View Investigation** if a Canvas investigation is already underway). On the service's **Presence** view, locate the highlighted gap on the chart, which shows the service's event volume over time. Note when the data stream stopped and whether it has resumed. Check whether the gap lines up with a planned deployment, a maintenance window, or a deliberate service shutdown. A gap that starts right after a deploy points toward the deploy as the likely cause. If auto-investigate is turned on for the service, review the Canvas investigation for related changes, such as a recent deploy or a dependency also showing anomalies. If auto-investigate isn't turned on, check the **Anomalies** list for related services that are also marked as **Anomalous** and may share the same cause. ## Make the call With the gap confirmed and a likely cause identified, you have what you need to decide how to respond: * If the gap doesn't match a planned change, or a dependent service is also affected, escalate to the configured recipients and treat it as a live incident. * If the gap matches a planned deployment or maintenance window, you can close the investigation with confidence rather than escalating further. # Investigate an Error Rate Anomaly Source: https://docs.honeycomb.io/notify/anomaly-detection/use-cases/investigate-error-rate Use Anomaly Detection and Canvas together to move from an error rate anomaly to a likely cause. Beta When Anomaly Detection flags a service as **Anomalous** on its Error Rate signal, the immediate question is whether the deviation reflects a real problem and how far it has spread. This workflow takes you from the alert to a confirmed cause, using the chart, the anomaly history, and a Canvas investigation together. ## Investigate the anomaly Open the anomaly and start an investigation: 1. Select **Anomalies** () from the navigation menu. 2. Find the service showing as **Anomalous**. 3. Select **Investigate** (or **View Investigation** if a Canvas investigation is already underway). On the service's **Error Rate** view, locate the shaded typical range band on the chart. Compare the current value against that band, and note whether the deviation is a single spike or a sustained shift. In the **Anomalies** section of the service's detail page, review anomalies detected in the current time range. Select a wider time range, such as **30 days**, to see whether this is a recurring pattern for the service or a first occurrence. If auto-investigate is turned on for the service, open the Canvas investigation that started automatically and review its likely cause. If a Slack channel is configured as a recipient, check that channel too since Canvas joins the thread with its findings. If auto-investigate isn't turned on, select **Run Query** from the chart to open the underlying query in Query Builder, then run BubbleUp against the anomalous period. ## Make the call With the chart, history, and investigation findings in hand, you have what you need to decide how to respond: * If the deviation is sustained, affects a large share of traffic, or matches a known incident pattern, escalate to the configured recipients and continue the investigation in Canvas or Query Builder. * If the deviation is a brief spike, isolated to a small slice of traffic, or explained by a known deploy or maintenance window, you can close the investigation with confidence rather than escalating further. # Send Alerts to Microsoft Teams Source: https://docs.honeycomb.io/notify/microsoft-teams Route Honeycomb Trigger and SLO burn alerts to a Microsoft Teams channel to notify your team when data crosses a defined threshold. The Microsoft (MS) Teams + Honeycomb integration uses [Honeycomb Triggers](/notify/triggers/) or [Honeycomb Service Level Objective (SLO) Burn Alerts](/notify/slos/) to notify Microsoft Teams based on alerts sent from Honeycomb. ## Before You Begin Before you set up the integration, you'll need a few things: * a user account in your team's Microsoft Teams organization * a user account in your Honeycomb Team ## Setting Up Your Integration Before you can configure Honeycomb to send alerts to Microsoft Teams, you must set up your integration. Microsoft has [retired](https://devblogs.microsoft.com/microsoft365dev/retirement-of-office-365-connectors-within-microsoft-teams/) Office 365 Connectors. As of August 12, 2024, any existing O365 Connector-based Honeycomb integrations for your Honeycomb Team requires recreation as a new Microsoft Teams Workflow integration. ### Create a Workflow for your Microsoft Teams Channel First, in Microsoft Teams, you must create a Workflow that posts to a channel when a webhook request is received. To learn how to configure a Workflow in Microsoft Teams, visit Microsoft's [documentation](https://support.microsoft.com/en-us/office/creating-a-workflow-from-a-channel-in-teams-242eb8f2-f328-45be-b81f-9817b51a5f0e). Use the generated Workflow URL in the next step when [adding your Microsoft Teams Workflow in Honeycomb](#create-your-integration-in-honeycomb). For a private Microsoft Teams channel, a Workflow requires additional configuration after creation to properly receive alerts. After creating a Workflow, navigate to and edit the target Workflow. Within the Workflow editor: 1. Expand the step "Send each adaptive card". 2. Expand the action "Post your own adaptive card as the Flow bot to a channel". 3. Change the **Post as** field from "Flow bot" to "User". 4. Save the workflow. ### Create Your Integration in Honeycomb Then, to create your integration, you must add your Microsoft Teams Workflow to Honeycomb. 1. Navigate to **Team Settings**, and select the **Integrations** view. 2. Locate the **Trigger and SLO Recipients** section. 3. Select **Add Integration**. 4. For **Provider**: 1. Select **MS Teams Workflow**. 2. Enter a name that will be easy to find when you configure alerts in the future. 3. Paste the Workflow URL in the **Incoming Webhook URL**. 5. Select **Add**. ## Configuring Alerts to Use Microsoft Teams as a Recipient After your integration is set up in Honeycomb, you can configure Triggers and SLOs to use MS Teams Workflow as a recipient for alerts. ### Configuring Triggers to Alert Microsoft Teams 1. In the Honeycomb UI, navigate to **Triggers**. 2. Select the name of the trigger you want to configure, or create a new trigger by selecting **New Trigger**. 3. Locate the **Recipients** section, and select **Add Recipient**. 4. In the **Add Trigger Recipient** modal: 1. Locate the **Recipient** dropdown. 2. Choose your **MS Teams Workflow** integration. 3. Select **Add**. 5. Select **Save Trigger**. ### Configuring SLO Burn Alerts to Alert Microsoft Teams 1. In the Honeycomb UI, navigate to **SLOs**. 2. In the list, locate the SLO you want to configure, or create a new SLO by selecting **New SLO**. 3. Find your SLO in the list, and select the **Configure** button in the **Burn Alerts** column. 4. Select **New Burn Alert**. 5. In the **Create Burn Alert** form: 1. Set your desired exhaustion time 2. Choose your MS Teams Workflow integration in the **Notify** dropdown. 3. Set your desired **Severity**, as Critical is the default setting. 6. Select **Create Burn Alert**. ## Removing the Integration To remove the integration, you will need to delete it from your Honeycomb team. Deleting the integration from your team will remove it from all associated triggers and SLOs. 1. Navigate to **Team Settings**, and select the **Integrations** view. 2. Locate **Trigger and SLO Recipients**, find your MS Teams integration, and then select **Edit**. 3. In the form editor, select **Remove**. # Send Alerts to PagerDuty Source: https://docs.honeycomb.io/notify/pagerduty Route Honeycomb Trigger and SLO burn alerts to PagerDuty to notify on-call responders when your data crosses a defined threshold. The PagerDuty + Honeycomb integration uses [Honeycomb Triggers](/notify/triggers/) or [Honeycomb Service Level Objective (SLO) Burn Alerts](/notify/slos/) to notify on-call responders based on alerts sent from Honeycomb. We maintain and support this integration. ## Before You Begin Before you set up the integration, you'll need a few things: * a user account in your team's PagerDuty organization * a user account in your Honeycomb Team ## Setting Up Your Integration Before you can configure Honeycomb to send alerts to PagerDuty, you must set up your integration. ### Link Your Service to a New Integration in PagerDuty In PagerDuty, you must create an integration and link it to a specific service. Once you have linked your integration and service, you will receive an integration key that you can use to link your PagerDuty integration to Honeycomb. 1. Navigate to **PagerDuty Configuration** > **Services**. 2. Select the name of an existing service to which you want to add the integration, then select the **Integrations** view, and click the **New Integration** button. To learn how to create a new service in PagerDuty, visit PagerDuty's [Configuring Services and Integrations](https://support.pagerduty.com/docs/services-and-integrations). 3. Enter details for your integration: | Field | Value | | ---------------- | -------------------------------------------------------------------------------------------------------------- | | Integration Name | Name of your integration in the format `monitoring-tool-service-name` (for example, `Honeycomb-Shopping-Cart`) | | Integration Type | **Honeycomb** | 4. Click the **Add Integration** button to save. You will be redirected to the **Integrations** view for your service. 5. Locate the generated **Integration Key**. Save this key in a safe place; you will need it later! PagerDuty Integration Key ### Connect Your Integration to Honeycomb To use your integration, you must add your PagerDuty Integration Key to Honeycomb. 1. Navigate to **Team Settings**, and select the **Integrations** view. 2. Locate the **Trigger and SLO Recipients** section, and select **Add Integration**. 3. For **Provider**, select **PagerDuty**, then enter a name that will be easy to find when you configure alerts in the future, and paste the PagerDuty **Integration Key**. 4. Select **Add**. ## Configuring Alerts to Use PagerDuty as a Recipient After your integration is set up in Honeycomb, you can configure Triggers and SLOs to use PagerDuty as a recipient for alerts. ### Configuring Triggers to Alert PagerDuty 1. In the Honeycomb UI, navigate to **Triggers**. 2. Select the name of the trigger you want to configure, or create a new trigger by clicking **New Trigger**. 3. Locate the **Recipients** section, and select **Add Recipient**. 4. In the pop-up form titled **Add Trigger Recipient**, locate the **Recipient** dropdown, and choose your service's PagerDuty integration and desired severity (Critical is the default). Select **Add**. Add recipient in PagerDuty 5. Select **Save Trigger**. ### Configuring SLO Burn Alerts to Alert PagerDuty 1. In the Honeycomb UI, navigate to **SLOs**. 2. In the list, locate the SLO you want to configure, or create a new SLO by clicking **New SLO**. 3. Find your SLO in the list, and click the **Configure** button in the **Burn Alerts** column. 4. Click **New Burn Alert**. 5. In the **Create Burn Alert** form, set your desired exhaustion time, then choose your PagerDuty integration in the **Notify** dropdown. Set your desired **Severity** (Critical is the default). 6. Select **Create Burn Alert**. ### Example: PagerDuty Alert from Honeycomb When a configured Trigger or Burn Alert fires, you can expect to see a PagerDuty display that looks similar to this example: PagerDuty Alert PagerDuty alerts will show Honeycomb graphs for Triggers only. ## Removing Integrations To remove the PagerDuty integration, you may need administrator privileges in PagerDuty. ### Delete the Integration from PagerDuty To remove the entire PagerDuty integration, you should begin by deleting the integration in PagerDuty. You may need admin privileges. 1. Navigate to the **Service Directory** in PagerDuty. 2. Locate the service that contains your Honeycomb integration. 3. Click on the **Integrations** tab. 4. Click the Settings icon () for the integration and select **Delete**. ### Remove the Integration from Honeycomb Once the integration is deleted from PagerDuty, you should also remove it from your Honeycomb team. Deleting the integration from your team will remove it from all associated triggers and SLOs. 1. Navigate to **Team Settings**, and select the **Integrations** view. 2. Locate **Trigger and SLO Recipients** and find your PagerDuty integration, then select **Edit**. 3. In the form editor, select **Remove**. ## Troubleshooting ### I don't receive alerts from PagerDuty when a trigger fires If you are not receiving alerts, examine your PagerDuty escalation policy to ensure that a responder is always on call in PagerDuty. PagerDuty will not create an incident if no responder is on-call at the time the trigger fires. # Send Alerts to Slack Source: https://docs.honeycomb.io/notify/slack Route Honeycomb Trigger and SLO burn alerts to a Slack channel using the official Honeycomb app for Slack. Connecting Honeycomb to Slack sends [Trigger](/notify/triggers/) and [Service Level Objective (SLO)](/notify/slos/) burn alert notifications directly to your team's Slack channels, so the right people get notified where they already work. Honeycomb maintains and supports this integration as the [Honeycomb app for Slack](https://slack.com/apps/A4ADZPBC4) in the Slack app directory. ## Before you begin Before you set up the integration, you need: * a user account in your team's Slack organization * a user account in your Honeycomb Team ## Setting up your integration Setting up the integration installs the Honeycomb app into your Slack workspace and authorizes Honeycomb to post alert notifications to your channels. A team owner completes this step once; depending on your Slack workspace settings, a Slack admin may need to approve the installation. To set up your integration: 1. Select **Account** from the navigation menu, then select **Team Settings**. 2. Select the **Integrations** view. 3. Locate the **Honeycomb + Slack** section, and select **Add to Slack**. 4. When Slack requests that you authorize Honeycomb, select **Allow**. Screenshot example of Honeycomb's requested permissions when linking to your Slack workspace 5. Invite the Honeycomb Slack app to each Slack channel where you want to receive alerts. Once authorized and invited to a channel, Honeycomb sends alerts to Slack with features like link unfurling, which shows a preview of your Honeycomb query result graphs. ## Configuring alerts to use Slack as a recipient After your integration is set up, you can configure individual Triggers and SLOs to send alert notifications to a Slack channel. Each trigger and SLO recipient is configured separately. ### Configuring triggers to alert Slack Adding Slack as a recipient on a trigger means Honeycomb posts a notification to your chosen channel whenever that trigger fires. To configure a trigger to alert Slack: 1. Select **Triggers** () from the navigation menu. 2. Select the name of the trigger you want to configure, or select **New Trigger** to create a new one. 3. Locate the **Recipients** section and select **Add Recipient**. 4. In the **Add Trigger Recipient** modal, locate the **Recipient** dropdown and choose your Slack integration, then select **Add**. 5. Select **Save Trigger**. ### Configuring SLO burn alerts to alert Slack Adding Slack as a recipient on a burn alert means Honeycomb posts a notification to your chosen channel whenever that burn alert fires. To configure an SLO burn alert to alert Slack: 1. Select **SLOs** () from the navigation menu. 2. Locate the SLO you want to configure, or select **New SLO** to create a new one. 3. Select **Configure** in the **Burn Alerts** column. 4. Select an existing burn alert to edit, or select **New Burn Alert** to create a new one. 5. Set your desired exhaustion time, then choose your Slack integration in the **Notify** dropdown. 6. Set your desired **Severity** (Critical is the default). 7. Select **Create Burn Alert**. ## Removing the integration Removing the integration disconnects Honeycomb from your Slack workspace and stops alert delivery to all associated triggers and SLOs. To remove the integration: 1. Select **Account** from the navigation menu, then select **Team Settings**. 2. Select the **Integrations** view. 3. Locate the **Honeycomb + Slack** section and select **Revoke**. ## Getting AI-powered investigations in Slack If your team has [Honeycomb Canvas](/investigate/canvas), the [Honeycomb Canvas Slack App](/investigate/canvas/slack-app) can automatically post AI-powered investigations into alert threads when a trigger, SLO burn alert, or anomaly fires. Once installed, Canvas joins the alert thread and streams its findings directly in Slack, so your on-call team gets immediate context without switching tools. # What is an SLO? Source: https://docs.honeycomb.io/notify/slos Define reliability targets for your services, track error budgets, and get burn alerts when you are at risk of missing your SLO. EntPro This feature is available in the [Honeycomb Enterprise and Pro plans](https://www.honeycomb.io/pricing/). A Service Level Objective (SLO) defines the expected level of reliability of a service. Often it's an agreement between a service provider and its customers, but SLOs can also be used internally to set priorities across teams. SLOs combine both practice and philosophy. They bring discipline to how teams monitor and manage systems, following principles described in the [Google SRE book](https://landing.google.com/sre/sre-book/chapters/service-level-objectives/). For best practices when using SLOs and Triggers for alerting, visit [Guidelines for SLOs and Trigger Alerts](/get-started/best-practices/alerts/). For more structured learning, check out the [Service Level Objectives](https://academy.honeycomb.io/app/courses/cb9cafea-a5c0-46b7-b7b9-929b33a216d2) course from Honeycomb Academy. ## Key Concepts Key concepts help you understand the building blocks of Service Level Objectives (SLOs). These terms define how SLOs are structured and how they interact with one another. * **Service Level Indicator (SLI)**: A per-event measurement that defines whether your system succeeded or failed. * **Service Level Objective (SLO)**: The target proportion, expressed as a percentage or ratio, of successful SLIs over a rolling time window. Example: "99.9% for any given 30 days". * **Error Budget**: The allowable amount of failure within the SLO window, measured by events or by time. Example: At 99.9% compliance with 1 million events in 30 days, you can tolerate 1,000 failed events. Viewed as downtime, with uniform traffic and no brownouts or partial failures, 99% availability allows \~7 hours of downtime in 30 days, while 99.9% allows \~44 minutes. * **Budget Burndown**: The remaining portion of the error budget within the current time window. Example: If 550 failed events occurred in 30 days at 99.9%, then you have 45% of the budget left. * **Burn Rate**: How quickly you are consuming the error budget compared to the target. Burn rate helps you understand the severity of issues in your SLO. A burn rate of `1.0` consumes the budget evenly and depletes the error budget exactly within the SLO window. A burn rate of `2.0` depletes it twice as fast. Burn Rate is not the same as an error rate in an SLO. * Error rate = number of errors / total events in the last time period * Burn rate = actual error rate / expected error rate If burn rate > `1.0`, your service is burning through its error budget faster than expected. * **Burn Alert**: An alert triggered when the error budget is consumed unusually quickly. ## How SLOs Work SLOs let you define measurable reliability goals for your services and track them automatically in Honeycomb. Each SLO uses a Service Level Indicator (SLI) to measure success at the event level, and calculates: * **Error Budget**: How many failures your service can tolerate within the SLO window. * **Budget Burndown**: How much of the error budget remains at any point in time. * **Burn Rate**: How quickly the error budget is being consumed. When the error budget is at risk, Honeycomb can alert your team so you can investigate and respond quickly. ### Burn Alerts Burn alerts notify you when your error budget is depleting faster than expected, helping you prioritize incidents and prevent SLO violations. ### Multiple Services You can apply a single SLO across multiple services, aggregating events from selected services to get a holistic view of system reliability. Multi-service SLOs work with environment-level Calculated Fields for consistent measurement. ### Notifications When a burn alert fires, it alerts you via the configured method(s). Supported methods include: * [PagerDuty](/notify/pagerduty/) * [Slack](/notify/slack/) * [Microsoft Teams](/notify/microsoft-teams/) * [Webhooks](/notify/webhooks/) * Email ### Tags Tags help you stay organized as your Team creates more SLOs. Use them to group related SLOs by team, project, service, or any other category that fits your workflow. Tags make it easy to filter and find the SLOs you need, especially in shared or busy environments. Because tags are flexible and customizable, you can organize SLOs in the way that works best for you. ## Why Implement SLOs? SLOs do more that set reliability targets. They provide shared context for decision-making across teams: * On-call engineers can prioritize incidents effectively. * Management can measure and report on service quality with precision. * Product and engineering teams can balance new feature work against infrastructure needs. SLOs make reliability a measurable, shared concern. ## Designing Effective SLOs Designing effective SLOs means choosing objectives that reflect what matters most to your users. This involves aligning reliability goals with business priorities, selecting clear SLIs, and setting thresholds that balance risk and user experience. ### What to Track When deciding what to measure: * **Measure close to the user**: Track signals at the system's edge, then use [BubbleUp](/reference/honeycomb-ui/slos/slo-detail-view/#bubbleup) to pinpoint issues. * **Design around user workflows**: Prioritize user outcomes over team or service boundaries. Expect some triage challenge if ownership is spread across teams or instrumentation is incomplete, and be prepared to revisit and adjust as needed. * **Alert only on actionable issues**: Exclude known/expected failures (for example, invalid credentials or user disconnects) to avoid noise. Missing rare cases in SLOs is more efficient than depleting budgets with constant, non-actionable alerts. Use normalcy [Triggers](/notify/triggers/) to detect unusual patterns like sudden traffic drops to critical endpoints. * **Normalize load-dependent metrics**: Identify load-dependent measures that remain consistent with increased output. Example: For upload endpoints that may receive large files, SLOs will be more reliable if their success is independent of payload size. Use transfer speed instead of response time to ensure fair measurement. * **Favor broad, meaningful SLOs**: A single comprehensive objective often provides more insight and ease of use than many fragmented ones or filtering various unrelated spans within a single calculated field. Example: Aim for 500 ms response times for "normal" interactive endpoints but allow a few more seconds on authentication endpoints that intentionally slow down when hashing passwords. This way, the load can still impact your infrastructure and having both types of signal within the same service level indicator (SLI) can uncover weirder interactions. * **Filter selectively**: Exclude specific customers or known problematic traffic (for example, pen-testing) when it does not reflect true service health. Use filtering when: * You are aware of the problem, and the customer is informed. * No immediate fix or SLO refinement is available. * You still want to be made aware of issues affecting the rest of the data. ### Structuring SLOs Keep these guidelines in mind: * **Iterate**: Start with an initial signal, reduce noise, and refine over time. * **Include new code paths**: Add them to existing SLOs when traffic volume is significant. Use separate SLOs only for low-volume but critical paths. * **Separate concerns**: Create distinct SLOs for performance vs. availability when needed. * **Set and tune targets**: Test by injecting failures and faults to ensure alerts trigger appropriately. Adjust sensitivity iteratively based on team feedback. * **Organize around user features**: Focus on user-facing outcomes, not code structure. For additional insights, visit our blog post: [Data Availability Isn't Observability](https://www.honeycomb.io/blog/data-availability-isnt-observability). * **Document details**: Capture exceptions and SLI intricacies within the SLO description, which allows for more extended comments than the SLI page. ## Multi-Service SLOs Shared SLOs across datasets and services require the Environments and Services data model. To use this feature, migrate from [Honeycomb Classic](/troubleshoot/product-lifecycle/recommended-migrations/#migrate-from-honeycomb-classic-to-honeycomb-environments) if needed. Honeycomb supports SLOs that share a single error budget across multiple services. ### How Multi-Service SLOs Work Multi-service SLOs let you define reliability targets that cover multiple services, capturing the combined user experience across related systems. This ensures that issues in any critical part of a workflow are reflected in the overall objective. Key characteristics include: * Share a single error budget across up to 10 services. * Only events from included services are evaluated. * Traffic from all included services is weighted equally. * SLIs are defined as [environment-level calculated fields](/investigate/query/build/calculated-fields/#creating-calculated-fields). To learn how to query on these SLIs in Query Builder, visit our [example of Calculated Fields in multiple datasets](/investigate/query/build/calculated-fields/#standardizing-fields-across-multiple-datasets). ### Use Cases While most SLOs are best defined on a single edge service (the service that is closest to your end user), multi-service SLOs are useful for: | Use Case | Description | | ------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Multiple edge services | Users connect from many locations rather than from one centralized place (for example, [service meshes](/observe/service-map/#istio-service-meshes-and-gateways) or [API Gateways](/observe/service-map/#instrument-for-gateways)). | | Migrating from a monolith to microservices | During gradual migration, create SLOs that cover both legacy and new components. | | Hot paths for critical flows | Define SLOs across services that form essential user workflows. | ### Evaluating Your Use Case Follow these guidelines to determine whether a multi-service SLO is appropriate for your scenario. #### Can success/failure be defined from a single event? Honeycomb classifies individual events as successful or failed. SLOs that require relationships across multiple events are not supported. * **Supported scenario**: SLO includes `frontend` and `cart` services. SLI defines success as events with `duration_ms < 50 ms`. Independent SLO events for multiple services Because events can be categorized as successful or failed, Honeycomb supports this use case. * **Unsupported scenario**: SLO includes `frontend` and `cart` services, but success depends on a `cart` event being a child of a `frontend` event: events with `duration_ms < 50 ms` on `cart` events that are a child span of `frontend`. Dependent SLO events for multiple services This scenario requires combining two events to determine success or failure, so Honeycomb does not support this use case. #### Do you want an SLO across all services in your environment? Honeycomb does not support a single SLO that covers all services in an environment. Instead, we recommend grouping related SLOs by team, product area, or critical path. ### Calculating Multi-Service SLOs When applied to multiple services: * Events from excluded services are ignored. * SLIs apply equally to all included services. * Events are not weighted by traffic. Assume that your environment contains `service_a`, `service_b`, `service_c`, and `service_d`. Assume that your SLO includes `service_a`, `service_b`, and `service_c`: * `service_a` receives 2 events (1 failed) * `service_b` receives 3 events (1 failed) * `service_c` receives 15 events (2 failed) * `service_d` will be excluded from SLO calculations because your SLO does not include it Your SLO will calculate: SLI = (number of successful events) / (number of total events) = (1 + 2 + 13 successes) / (2 + 3 + 15 total) = 80% ### Identify Outliers with Multi-Service SLOs You can use BubbleUp with multi-service SLOs in the same way as with single-service SLOs, with a few important differences: * Clicking through the SLO Heatmap to the Query Builder loads an Environment query with a **WHERE** clause that filters by service names included in your multi-service SLO. * The service name field used in the Environment query comes from the **Service Name** field defined in your [dataset definitions](/configure/datasets/definitions/#access-dataset-definitions). * The SLO Heatmap and Query Builder heatmap may not match exactly, depending on how the service name is defined: * For the heatmaps to align, the service name must match the dataset name. * If your dataset definitions include multiple fields for service name (for example, `service.name` and `service_name`), Honeycomb will run an environment-wide query without filtering by service name. ### Limitations * You cannot create a single SLO that applies to all services in your environment. * Multi-service SLOs do not support [team activity logs](/configure/teams/investigate-activity/). # Create a Service Level Objective (SLO) Source: https://docs.honeycomb.io/notify/slos/create Define an SLO for a Honeycomb dataset by setting a target reliability percentage, a time window, and a Service Level Indicator (SLI) query. EntPro This feature is available as part of the [Honeycomb Enterprise and Pro plans](https://www.honeycomb.io/pricing/). When you create a Service Level Objective (SLO), you must define it for a single Honeycomb dataset. ## Define Your SLO When creating an SLO, you must [define a service level indicator (SLI)](/notify/slos/create/sli/) that your SLO will use to evaluate your level of success. In the process of [determining a suitable SLI](/notify/slos/create/sli/#determine-your-sli), you should identify qualified events, which are events that contain information about the SLI. Keeping these qualified events in mind, ask yourself: "Over what period of time do I expect what percentage of qualified events to pass my SLO?" For example, "I expect that 99% of qualified events will succeed over every 30 days". In this example, `99%` is the target percentage of success and `30 days` is the time period being measured. Your SLO will use your SLI alongside your identified target percentage and time period to evaluate status. As you select a level, base it off your current state, which you can find out by doing a count query grouped by your SLI calculated field after it has been created. ## Create Your SLO To create an SLO: 1. From the left sidebar, select **SLOs**. 2. Select **New SLO**. 3. Enter details for your SLO: | Field | Description | | --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Dataset/service** | Dataset(s) or service(s) to which you want your SLO to apply. You can select up to 10. If your SLO applies to only one dataset or service and you have already created an SLI as a Calculated Field, you must create your SLO inside the same dataset that contains that Calculated Field. If your [SLO applies to multiple datasets(s) or service(s)](/notify/slos/#multi-service-slos), your SLI must be created as a shared Calculated Field. | | **Name** | Name of your SLO. | | **Description** | Information that can help provide context or purpose for the SLO. You may use Markdown to insert links and format text. | | **Tags** | Labels that organize and group related SLOs, making it easier to filter by tag and find them. Enter tags in key:value format (for example, `area:pipelines` or `team:prism`). Use **Assign** to add up to 10 tags per SLO. Tag keys can contain letters only, up to 32 characters. Tag values can include alphanumeric characters and the special characters `/` and `-`, with a maximum length of 128 characters. | | **Service Level Indicator (SLI)** | SLI, expressed as a Calculated Field, that your SLO will use to evaluate your level of success. If you have already defined your SLI in a Calculated Field, select it from the dropdown. Otherwise, select **+ New SLI** and [create your SLI](/notify/slos/create/sli/#define-your-sli). If you create a new SLI from within this SLO, it will be created at the environment level, so you may use it with multiple services or datasets if so desired. | | **Time Period** | Time period (in days) to which this SLO applies. | | **Target Percentage** | Target percentage of events you expect to succeed. | SLO creation dialog 4. Select **Create SLO**. ## Create Your SLO from a Template You can create an SLO from a template. Use SLO templates to create a pre-configured SLO based on your target datasets. If no previous SLOs exist, the SLO displays the available SLO Templates and an option to create an SLO from scratch. Otherwise, the Templates section in the **List** view displays SLO Templates available to you. Want to request an SLO Template? Select **Request SLO Template** in the Templates section, and submit your suggestion. To create an SLO from a Template: 1. Navigate to **SLOs** using the left navigation menu. 2. Select from the available Template options. A creation modal appears. 3. Select the text box to view a list of available datasets. 4. Select up to 24 datasets to apply this SLO. 5. Select **Next** to finish. An SLO Detailed View of the created SLO appears. ### Available SLO Templates | Template | SLO Name | SLO Description | | ---------------------- | ------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Service Uptime | Uptime: At Least 90.0% of HTTP Requests Succeed | This SLO ensures that at least 90.0% of HTTP requests return successful responses (status codes below 400), minimizing downtime and improving user experience. This SLO was auto-generated via a template. | | Service Responsiveness | Responsiveness: At Least 95% of HTTP Requests are Fast | This SLO ensures that 95% of HTTP requests complete within 1000 milliseconds, maintaining fast and reliable responses for users. This SLO was auto-generated via a template. | ## Next Steps Now that you have an SLO, you can: * [Monitor the SLOs](/reference/honeycomb-ui/slos/) for your team * [Set up Burn Alerts](/notify/slos/monitor/), which provide notifications related to your SLO budget * Monitor sets of related SLOs alongside your queries by [adding SLOs to a Board](/observe/boards/#adding-service-level-objectives-slos) ## Best Practices To learn about best practices for using SLOs and SLIs, visit [Best Practices for Service Level Objectives (SLOs)](/get-started/best-practices/slos/). # Create a Service Level Indicator (SLI) Source: https://docs.honeycomb.io/notify/slos/create/sli Define the SLI query that your SLO uses to measure success, specifying the conditions that determine whether each request counts as a good or bad event. EntPro This feature is available as part of the [Honeycomb Enterprise and Pro plans](https://www.honeycomb.io/pricing/). When creating a Service Level Objective (SLO), you must define a service level indicator (SLI) that your SLO will use to evaluate your level of success. ## Determine Your SLI To identify a suitable SLI: 1. Express your SLI in terms of user goals. For example, "a user should be able to load our home page and see a result quickly". 2. Identify qualified events, which are events that contain information about the SLI. In this example, qualified events are events where `request.path = "/home"`. For events that are not qualified, Honeycomb returns `null`. 3. Establish the criterion you will use to determine which qualified events you consider as "successful". In this example, success means `duration_ms < 100`. Honeycomb evaluates "success" according to your definition. For each event in the Dataset, the SLI returns `true` (success), `false` (failure), or `null` (not applicable). In other words, a SLI is defined as the number of successful events divided by the total (valid) events, and multiplied by 100 for a resulting percentage: $$ SLI = (\textit{Successful events} / \textit{Total valid events}) * 100 $$ ## Define Your SLI SLIs are represented as Calculated Fields in Honeycomb, and thus visible after creation as a field in your schema, in Query Builder, or in Triggers. SLIs can be created using the [Calculated Field creation workflow](/investigate/query/build/calculated-fields/#creating-calculated-fields) in Dataset Settings, but this creation experience is not optimized for SLIs. Instead, when creating your SLO, use the New SLI workflow as outlined below. To define your SLI, we recommend creating your SLI during the [SLO creation process](/notify/slos/create/#create-your-slo). Two options exist to define your SLI: * [Build Query mode](#define-your-sli-with-a-query) - Allows to filter for total and successful events using syntax from the Query Builder. * [Write Formula mode](#define-your-sli-with-a-formula) - Allows advanced formula capabilities using Calculated Field syntax. You can switch from Build Query mode to Write Formula mode. Returning to Build Query mode from Write Formula mode removes any entered syntax. ### Define Your SLI with a Query To use query syntax to define your SLI, create a new SLI and select **Build Query**: 1. During the [SLO creation process](/notify/slos/create/#create-your-slo), select **+ New SLI**: 2. In the New Service Level Indicator (SLI) window, enter a **Display Name**, which will appear elsewhere as a field name in the Query Builder. Enter a display name that is unique across the Dataset and its containing Environment. Your SLI name should not match the name of any other Calculated Field or any other field in any Dataset contained within the Environment. Although Honeycomb tries to prevent duplicate field names, they can still occur. To learn more about behaviors related to name collision and solutions, visit [Common Issues with Queries: Calculated Fields](/troubleshoot/common-issues/queries/#a-link-points-to-the-wrong-location). 3. Optionally, include a description for your SLI. 4. Select **Build Query** to use Honeycomb's query language and to define filters for total and successful events. New Service Level Indicator (SLI) Modal - Build Query Following our previous example, this SLI's query syntax for each filter would be: **Total (valid) events**: `request.path = /home` **Successful events**: `http:response_duration < 100` Some functionality is not currently supported in Build Query mode, such as regex and type coercion. To access more advanced functionality, switch to using [calculated field syntax](#define-your-sli-with-a-formula) by selecting **Write Formula**. Learn more about translating between modes and their [Supported Syntax](#supported-syntax). 5. Optionally, use the Preview Data section to preview the results of the function. Sample data from recent events helps you to verify the expression before it is saved. 6. Select **Save** and continue [creating your SLO](/notify/slos/create/#create-your-slo). ### Define Your SLI with a Formula To use calculated field syntax to define your SLI, create a new SLI and select **Write Formula**: 1. During the [SLO creation process](/notify/slos/create/#create-your-slo), select **+ New SLI**. 2. In the New Service Level Indicator (SLI) window, enter a **Display Name**, which will appear elsewhere as a field name in the Query Builder. Enter a display name that is unique across the Dataset and its containing Environment. Your SLI name should not match the name of any other Calculated Field or any other field in any Dataset contained within the Environment. Although Honeycomb tries to prevent duplicate field names, they can still occur. To learn more about behaviors related to name collision and solutions, visit [Common Issues with Queries: Calculated Fields](/troubleshoot/common-issues/queries/#a-link-points-to-the-wrong-location). 3. Optionally, include a description for your SLI. 4. Select **Write Formula** and define the Calculated Field formula for your SLI. New Service Level Indicator (SLI) Modal - Write Formula Most SLIs are written using Honeycomb's [two-argument "IF" command](/reference/calculated-field-expression/conditional/#if): `IF(qualifier, criterion)`. With this command, `IF( $a, $b)` returns `$b` only if `$a` is `true`. Otherwise, it returns `null`. Following our previous example, the Calculated Field formula for this SLI would be: `IF( EQUALS( $request.path, "/home"), LT( $http.response_duration, 100))` To explore more examples of formulas for SLIs, visit [SLI Formulas](/notify/slos/create/sli-formulas/). To learn more about syntax and available functions, visit [Calculated Field Formula Reference](/reference/calculated-field-expression/). Hover over any syntax errors, as indicated by red underlines or red triangles, for suggestions to correct them. 5. Optionally, use the Preview Data section to preview the results of the function. Sample data from recent events helps you to verify the expression before it is saved. 6. Select **Save** and continue [creating your SLO](/notify/slos/create/#create-your-slo). ### Supported Syntax Use the chart below to translate between Calculated Field syntax in Write Formula mode and Query syntax in Build Query mode. | Calculated Field Function | Query Syntax | | ------------------------------------- | -------------------------------- | | LT() | \< | | LTE() | \<= | | GT() | > | | GTE() | >= | | EQUALS() / NOT(EQUALS()) | =, != | | IN() / NOT(IN()) | in, not-in | | EXISTS() / NOT(EXISTS()) | exists, does-not-exist | | STARTS\_WITH() / NOT(STARTS\_WITH()) | starts-with, does-not-start-with | | ENDS\_WITH() / NOT(ENDS\_WITH()) | ends-with, does-not-end-with | | CONTAINS() / NOT(CONTAINS()) | contains, does-not-contain | Referencing another Calculated Field from a SLI (or Calculated Field) is not supported. ## Test Your SLI To test your SLI: 1. From the left navigation menu, select **Query**. 2. Query the dataset that contains your SLO. | VISUALIZE | GROUP BY | | ---------------------------------- | ------------------------ | | COUNT
HEATMAP(duration\_ms) | `` | 3. In your results, confirm that three groups exist: `true` (successful qualified events), `false` (failed qualified events), and blank (events that are not qualified). 4. Confirm that the three groups look correct for your use case and understanding of the dataset's contents. To explore this process in more detail, read our [Working Toward Service Level Objectives](https://www.honeycomb.io/blog/working-toward-service-level-objectives-slos-part-1/) blog post. # Service Level Indicator (SLI) Formulas Source: https://docs.honeycomb.io/notify/slos/create/sli-formulas Copy and adapt example SLI formulas to define good and bad request criteria for common reliability scenarios in your Honeycomb datasets. EntPro This feature is available as part of the [Honeycomb Enterprise and Pro plans](https://www.honeycomb.io/pricing/). These examples show how to identify different types of criteria and qualifiers when creating SLIs. Each example includes how to formulate the SLI when using the [**Build Query** mode](/notify/slos/create/sli/#define-your-sli-with-a-query) or the [**Write Formula** mode](/notify/slos/create/sli/#define-your-sli-with-a-formula). ## No Qualifier For all events, return `true` if `duration_ms < 1000`. ### Build Query | Total (Valid) Events | Successful Events | | -------------------- | -------------------- | | | duration\_ms \< 1000 | ### Write Formula as a Calculated Field ```honeycomb theme={} LT($duration_ms, 1000) ``` ## Qualifier is trace roots A trace root does not have a parent. This SLI returns `true` for trace roots whose response duration is under 100, `false` for trace roots whose duration is over 100, and `null` for non-roots. ### Build Query | Total (Valid) Events | Successful Events | | ------------------------------- | ------------------- | | trace.parent\_id does-not-exist | duration\_ms \< 100 | ### Write Formula as a Calculated Field ```honeycomb theme={} IF( NOT(EXISTS($trace.parent_id)), LT($duration_ms, 100) ) ``` ## Criterion is Based on Both Duration and Error Our qualifier here is whether `request.path` is `/home`. If it is, then this SLI only returns `true` if **both** `duration_ms` is under 100, **and** there is no error message. ### Build Query | Total (Valid) Events | Successful Events | | -------------------- | --------------------------------------------------- | | request.path = /home | duration\_ms \< 100
app.error does-not-exist | ### Write Formula as a Calculated Field ```honeycomb theme={} IF( EQUALS($request.path, "/home"), AND( LT($duration_ms, 100), NOT(EXISTS($app.error)), ) ) ``` ## Complex Criterion, Complex Qualifier The qualifier here is events that hit the `/main` endpoint, using the method `POST`, and are not marked as error code `401`. The criterion is that events must have a status code of `200`. In addition, if they are part of a batch, then data processing must have taken less than 5 ms per item. ### Build Query This example is not supported in the Build Query mode because the `DIV()` and `IF()` operators are only supported within a calculated field. ### Write Formula as a Calculated Field ```honeycomb theme={} IF( AND( EQUALS($request.path, "main"), EQUALS($request.method, "POST"), NOT(EQUALS($response.status_code, 401)) ), AND( EQUALS($response.status_code, 200), LT( DIV( $duration_ms, IF($app.batch, $app.batch_total_datapoints, 5) ), 5 ) ) ) ``` # Historical Health of Service Level Objectives (SLOs) Source: https://docs.honeycomb.io/notify/slos/historical-health Review a time-based report of each SLO's reliability performance to identify patterns, recurring budget burns, and long-term trends. EntProBeta This feature is available as part of the [Honeycomb Enterprise and Pro plans](https://www.honeycomb.io/pricing/). This feature is in [beta](/troubleshoot/product-lifecycle/release-stages/#beta). The Historical Health view displays a list of your configured Service Level Objectives (SLOs) within Honeycomb and their SLO compliance in percentage form at certain points in time. Historical SLO compliance can be displayed up to a year, depending on when the SLO was created and its available data. Use the dropdown menu to modify the list of displayed SLOs. Navigate dates and their information using the **Older data** icon () and **Newer data** icon (). ## Displayed Fields The Historical Health view shows information for each SLO, including: * **SLO Name** - Shows the SLO Name. * **Target** - Displays the SLO Target in percentage form. * **Date** - Each column represent a date and displays their SLO compliance in percentage form over the preceding time period. The SLO Compliance calculation ignores any [SLO resets](/reference/honeycomb-ui/slos/slo-detail-view/#reset-your-remaining-slo-budget). All fields are sortable. # Monitor Service Level Objectives (SLOs) Source: https://docs.honeycomb.io/notify/slos/monitor Configure burn alerts to notify your team when SLO budget consumption accelerates beyond safe thresholds, and assign the recipients who should respond. EntPro The **Burn Alerts** feature provides notifications related to your SLO Budget. Burn Alerts can notify you when issues impact your SLO budget, which represents the maximum allocation of failures for your service. Configured alerts let you react to the incidents that matter most to you as defined in your SLO. Use cases for Burn Alerts include, but are not limited to: * Proactive awareness if you are about to miss customer expectations (SLA) ([example scenario](#example-uses-for-burn-alerts)) * Early issue detection on services as soon as they occur ([example scenario](#example-uses-for-burn-alerts)) * Maintaining service quality and preventing service disruptions * Continuous improvement on your services * Informing strategic and tactical decisions, such as resource allocation, investment in infrastructure, and service development ## Burn Alert Types When creating a Burn Alert, choose from the following Burn Alert types: | | Exhaustion Time | Budget Rate | | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Description | Notifies when your SLO is at risk of burning through its error budget within a specified number of hours. This allows for proactive steps before the SLO budget reaches zero. | Notifies when the SLO budget drops by a minimum specified percentage within a defined time window. This allows for the detection of budget burn issues and unexpected spikes in a timely manner. | | Parameters | Exhaustion Time (hours) | Time Window (hours), Budget Decrease (% or burn rate) | | Example Alert. | Alert me when I am about to run out of budget in **24 hours.** | Alert me when the SLO budget decreases by **10%** or **2.4x burn rate** in the last **2 hours**. | | Signal of the Alert. | Alert when you are x hours away from violating your SLO. | Alert when the SLO budget starts to rapidly burn or inconsistently burn. | ## Adding a Burn Alert To add a Burn Alert: 1. In the SLO List view, select the SLO's name to view its details. 2. Select **Configure Burn Alerts** in the upper right corner, which will display the SLO's existing Burn Alerts (if any) in list view. 3. Select **New Burn Alert** in the upper right corner and a Create Burn Alert form appears. 4. Select which Alert Type to configure: Exhaustion Time or Budget Rate. The display changes based on the chosen Alert Type. where: SLO Create Burn Alert Exhaustion Time Form. * **Description** adds context, such as runbook links or alert summaries for the Burn Alert. When utilized, the Burn Alert description appears in the notification instead of the SLO description. * **Notify** configures the [notification option](#notify-options) for the Burn Alert. * **Exhaustion time (hours)** is when you want to be notified based on how much time (in hours) is left until your projected SLO budget will hit zero. While it is possible to express time periods of less than an hour--for example, `0.25` corresponds to 15 minutes--usually that is not enough time to make the SLO actionable. Conversely, periods of more than a few days almost never merits notification as it effectively acts the same as the current SLO's time period. Learn about [Best Practices for Exhaustion Time burn alerts](#exhaustion-time-burn-alerts-1). SLO Create Budget Rate Burn Alert Form. * **Description** adds context, such as runbook links or alert summaries for the Burn Alert. When utilized, the Burn Alert description appears in the notification instead of the SLO description. * **Notify** configures the [notification option](#notify-options) for the burn alert. * **Time Window (hours)** is the range of time to determine a budget rate. Minimum value is `1`. Maximum value is the length of your SLO. * **Budget Decrease** is the drop in budget to be notified on. You can input this value as either a **percentage** or a **burn rate**: - **Percentage**: A drop in budget percentage to be alerted on. Honeycomb alerts if the error budget has decreased by at least this percentage in the window. Minimum value is `0.0001`. Maximum value is `100`. - **Burn Rate**: A rate of budget consumption to be alerted on. Honeycomb alerts if the budget drops at this rate or greater during the window. Minimum value is `0.0001`. Maximum value cannot exceed the equivalent of a `100%` budget decrease within the window. A [Budget Burndown graph](#budget-burndown-graph) also appears, which projects potential alert frequencies based on input values. Learn about [Best Practices for Budget Rate burn alerts](#budget-rate-burn-alerts-1). ### Notify Options **Notify by email** appears as the default notification method, which requires entering one or more email addresses. Enter multiple emails separated by commas. Additional integration options, like Slack and PagerDuty, are populated from [SLO and Trigger Recipients](/notify/#integrations), as found under **Team Settings** > **Integrations**. Once configured, these additional options can be selected. For example, a Budget Rate burn alert in Slack appears similar to: SLO Burn Alert fired ### Budget Burndown Graph When creating a Budget Rate burn alert, the Budget Burndown graph appears. Use the Budget Burndown graph to determine the Time Window and Budget Decrease values that work best. The graph shows the Budget Burndown over the SLO's time period. Change the values for Time Window and/or Budget Decrease to see different graph projections. The dashed line markers appear on the graph to represent when alerts would have been sent. The light orange range represents how long an alert would remain activated. In this example below, the SLO's time period is 7 days. A 4-hour Time Window and a 5% Budget Decrease (2.1x burn rate) would cause alerts to occur 5 times. Hovering over the marker for the second alert reveals its estimated notification date is at 6:57am on October 27. You may decide that a 5% decrease alerts too often and that amount of burn over the 4-hour window is not serious enough to alert the team. How Honeycomb evaluates Budget Rate burn alerts Further experimentation may find that a 3-hour Time Window and a 7% Budget Decrease is perfect for your team. Entering these values shows a graph with the next estimated alert notification(s), based on these values. How Honeycomb evaluates Budget Rate burn alerts ## Testing Burn Alert Notifications After creation, Burn Alert notification testing becomes available. Use this feature to test if Burn Alert notifications appear as expected before an alert situation occurs. To test your Burn Alert notifications: 1. Navigate to the individual SLO's [detailed view](/reference/honeycomb-ui/slos/slo-detail-view/) associated with the Burn Alert. 2. Select **Configure Burn Alerts** in the upper right corner to display a list of existing Burn Alerts for the SLO. 3. Select **Test** for the target Burn Alert. The test sends both a `TRIGGERED` and `RESOLVED` message via the configured notification option(s). Test messages are prefixed with `BURN ALERT TEST`. SLO Burn Alert test ## Viewing Burn Alerts Burn Alerts can be viewed in several locations: * When configured, the summary chart displays Burn Alerts in an SLO's [detailed view](/reference/honeycomb-ui/slos/slo-detail-view/). * If activated, an SLO's shortest Time Window for a Burn Alert also appears on an [SLO list](/reference/honeycomb-ui/slos/)'s status column. * If any exist, select **Configure Burn Alerts** in the upper right corner of an SLO's [detailed view](/reference/honeycomb-ui/slos/slo-detail-view/) to display a list of existing Burn Alerts for the SLO. ## Removing Burn Alerts To remove a Burn Alert: 1. Navigate to a list of existing Burn Alerts for the SLO by selecting **Configure Burn Alerts** in the upper right corner of an SLO's [detailed view](/reference/honeycomb-ui/slos/slo-detail-view/). 2. Select **Delete** next to the Burn Alert to remove. 3. Confirm your choice by selecting **Delete** in the pop-up modal. ## How Burn Alerts Work ### Exhaustion Time Burn Alerts Honeycomb computes whether an Exhaustion Time burn alert may occur by extrapolating the current rate of budget burn. If this rate reaches zero percent (`0%`) within the specified number of hours in the alert, then Honeycomb sends a notification. Honeycomb determines the extrapolation window by dividing the alert's Exhaustion Time by 4. Honeycomb looks at the past data in the extrapolation window, and then extrapolates what may happen in the future for the specified numbers of Exhaustion Time hours. An Exhaustion Time burn alert stays activated until the SLO budget will no longer exhaust within the defined exhaustion time. (Honeycomb also applies a small buffer period to avoid fluctuating notification events.) Once resolved, Honeycomb sends a notification. The example below shows how a 4-hour Exhaustion Time alert works. Honeycomb looks at how the last hour has been, which is the extrapolation window, and then extrapolates what may happen in the next four hours, which is the Exhaustion Time value. Based on this data, the four hour estimate will dip below zero, and so the system warns the user. How Honeycomb extrapolates for exhaustion time alerts ### Budget Rate Burn Alerts Honeycomb computes whether a Budget Rate burn alert may occur by evaluating historical events in a given time window. A Budget Rate is determined by a drop in error budget over a time window. If budget decreases, at minimum, by the configured Budget Decrease value, then Honeycomb sends a notification. When configuring a Budget Rate burn alert, you can express the Budget Decrease as either a percentage drop or a burn rate. This alert resolves when the consumed budget within the time window is less than the specified Budget Decrease value in the Budget Rate burn alert. (Honeycomb also applies a small buffer to avoid fluctuating notification events.) Once resolved, Honeycomb sends a notification. The example below shows how Honeycomb evaluates a Budget Rate burn alert with a 4-hour Time Window and 30% Budget Decrease value (approximately 5x burn rate for a 7-day SLO). The shaded section shows the last four hours for this SLO. Within this range, Honeycomb evaluates the Budget at the start and end of this time window. In this example, the Budget starts at 78% and and ends at 38%, or a 40% overall decrease. Therefore, Honeycomb sends a notification because the Budget Decrease value is 30% and the SLO experienced a 40% overall decrease. How Honeycomb evaluates Budget Rate alerts #### Burn Rate Calculation The decrease in budget represented by a given burn rate depends on the SLO period, budget and evaluation window. A 1x burn rate expresses the ideal case where the error budget is exhausted at the end of the full SLO period. A 2x burn rate consumes error budget twice as fast and exhausts the budget halfway through the SLO period. A 3x burn rate is 3 times as fast, etc. Honeycomb automatically converts between percent drop and burn rate for you. You can toggle between the two methods in the Budget Decrease configuration to see how changing one influences the other. Honeycomb aims to evaluate SLO Burn Alerts every minute. If you configure a Budget Rate burn alert for a 10% Budget Decrease, then an alert notification occurs when the latest evaluation is greater than 10%. Whether evaluated as a 12% or 10.1% decrease, an alert occurs. If being alerted for a 0.1% over the Budget Decrease value is too sensitive of a measure, increase the Budget Decrease value. ## Best Practices We recommend that you follow certain best practices when creating alerts. Some of these are general guidelines, and some are specific to alert type. ### General Guidelines Regardless of the alert type: * Iterate when creating Burn Alerts. Start by sending alerts to an internal recipient (either a team member's email address or a private Slack channel) to monitor the frequency of alerts in your system. Use these Burn Alerts as a first step toward understanding how your service performs and what kinds of alerts are actionable and important to your team, and then iterate. * Start with the shape of the signal that you care about: * For slow SLO burn, you care about issues that occur over a prolonged time period. * For fast SLO burn, you care about significant spikes over a shorter time period. * Use alerts to refine any new SLOs that you create. For new SLOs, start with a Budget Rate alert, which will notify you when system conditions impact your budget, to learn: * If you are missing any criteria in your SLI. * If you can historically sustain your SLO. ### Exhaustion Time Burn Alerts When choosing the length of time for a given Budget Exhaustion burn alert, consider the context and goals of your organization. Ask questions to help frame the definition of some initial Exhaustion Time burn alerts. If you are X hours away from running out of budget: * Who would need to know * Via what method * What would they need to do For example, a 24-hour exhaustion time alert can be useful if service quality is slowly degrading and a Slack-based notification allows the team to remediate the issue before the budget reaches zero (`0`). Alternatively, a 4-hour exhaustion time alert may be more urgent and require a pager notification, such as from PagerDuty. We recommend creating at least one Exhaustion Time burn alert where the Exhaustion Time is `0`. This will notify you when your SLO budget is completely exhausted. ### Budget Rate Burn Alerts When starting with a Budget Rate burn alert, consider whether you seek an alert for a smooth, slow burn or a fast, abrupt drop. Start with a less-sensitive alert and adjust as needed. Depending on the length of your SLO's time period, try these values when creating Budget Rate burn alerts. #### 30 Day SLO Example Use the following example to create a series of Budget Rate burn alerts for your SLO. Each row represents an alert and its values. | Budget Decrease | Burn Rate | Time Window | Notification Type | | --------------- | --------- | ----------- | ----------------- | | 2% | 14.4x | 1 hour | PagerDuty | | 5% | 6x | 6 hour | PagerDuty | | 10% | 1x | 3 days | Slack | #### 7 Day SLO Example Use the following example to create a series of Budget Rate burn alerts for your SLO. Each row represents an alert and its values. | Budget Decrease | Burn Rate | Time Window | Notification Type | | --------------- | --------- | ----------- | ----------------- | | 8.5% | 14.3x | 1h | PagerDuty | | 21.5% | 6.02x | 6h | PagerDuty | | 43.20% | 1.01x | 3 days | Slack | | 50% | 1x | 3.5 days | Slack | #### Use the Time Window to Determine the Notification Method A long Time Window, such as 24 hours, is useful in detecting long, slow burns that use up your SLO budget faster than expected, but not fast enough to wake someone out of bed. A short Time Window, such as one hour, is useful in detecting very fast SLO budget burns that need to be addressed quickly. Use the time window to determine the alert method. For example: * For a long, slow SLO budget decrease, send a Slack message, so the issue can be addressed during business hours. * For a short, fast SLO budget decrease, send a critical PagerDuty notification, so it can be acted on immediately. Although it may be counterintuitive, a Budget Rate alert with a long time window will also activate on a short, fast burn. For example, if you have two Budget Rate burn alerts with the parameters: * Notify when the Budget Decrease exceeds 25% over a **24** hour period * Notify when the Budget Decrease exceeds 25% over a **1** hour period If your environment encountered a large spike of errors and burned 25% of your SLO budget in the last hour, both the 24-hour Budget Rate burn alert and the 1-hour Budget Rate burn alert will fire, because both include the last hour in their calculation. You might ask, since both Burn Alerts activated, why do you need both? You need both if you want to control where the Burn Alert notifies. #### Use Budget Decrease to Control Alert Frequency To control the frequency of your Burn Alert and calibrate its sensitivity: * Increase the Budget Decrease value if the alert is too noisy. * Decrease the Budget Decrease value if the alert is too quiet. ## Example Uses for Burn Alerts You can use Burn Alerts in a variety of ways. Some examples include: **Audience:** Teams that use SLOs to decide what to prioritize and how to allocate resources in their organization. **Example scenario:** Your SLO says that 99% of web requests should complete in less than 250 ms. Any request that takes longer than 250 ms is a failure and burns some of your SLO budget. You need to know how long you have until your SLO budget is exhausted if failures continue at the current rate. **Solution:** Set up two Exhaustion Time burn alerts--one alert to represent each alert signal: * **24-hour alert**: Alerts you when you are 24 hours away from exhausting your budget. Because you can deal with this burn during normal business hours, you set the alert to notify staff through Slack. * **4-hour alert**: Notifies you when you are four hours away from exhausting your budget. Because you need to deal with a burn this fast immediately, even in the middle of the night, you set the alert to notify staff through PagerDuty. **Audience:** Teams that want more granularity when identifying significant issues that impact their SLO budget. The team wants to know when unexpected spikes are occurring, even if issues are not pageable events, so they can investigate later. When you identify issues earlier, you can proactively learn about unknowns affecting your service and find issues that influence your SLI calibration. **Example scenario:** Your SLO says that 99% of web requests should complete in less than 250 ms. Any request that takes longer than 250 ms is a failure and burns some of your SLO budget. You review your SLO and notice that you burned through over 15% of your budget in half a day: A SLO with a drop in budget You investigate and determine that the issues that caused the budget burn are worth being notified about. **Solution:** Create a Budget Rate burn alert to notify you when your budget decreases by 10% within a 6-hour time window. Because you can deal with this burn during normal business hours, you set the alert to notify staff through Slack, but because you may want to investigate the event later, you also create a ticket. **Audience:** Teams that have relatively stable services that burn at a consistent rate, so sudden increase in burn rates would indicate an issue worth investigating. **Example scenario:** Your SLO says that 99% of web requests should complete in less than 250 ms. Any request that takes longer than 250 ms is a failure and burns some of your SLO budget. Your services burn at a consistent rate: A SLO with a consistent burn rate You decide that you want to know about any changes to this consistent, steady burn rate, so you can investigate. **Solution:** Create a Budget Rate burn alert to notify you when the SLO does not burn as expected. Because you can deal with this burn during normal business hours, you set the alert to notify staff through Slack, but because you may want to investigate the event later, you also create a ticket. **Audience:** Teams that want to be sure that issues exhausting their SLO budget are resolved after receiving an Exhaustion Time burn alert. Because Exhaustion Time burn alerts will not alert again until after they resolve, a team may want to track whether a budget burn remains or reoccurs. **Example scenario:** You receive an Exhaustion Time burn alert and discover an outage, which you solve. You want to make sure that your solution addressed the actual cause and that you resolved the problem. **Solution:** Create a Budget Rate burn alert to use operationally compared to an Exhaustion Time burn alert, which will notify you if your SLO continues to burn at a high rate. Because you need to deal with any continual or recurring burn immediately, you set the alert to notify staff through PagerDuty. ## Troubleshooting To explore common issues when working with SLOs, visit [Common Issues with Alerts: SLOs](/troubleshoot/common-issues/alerts/#slos). # Report on Service Level Objectives (SLOs) Source: https://docs.honeycomb.io/notify/slos/report Pull SLO status data into external dashboards and reports using Honeycomb's SLO reporting API. EntPro While [Service Level Objectives (SLOs)](/notify/slos/) are available for Pro and Enterprise plans, this SLO reporting data is available as part of the [Enterprise plan](https://www.honeycomb.io/pricing/) only. If you are an Enterprise customer with many SLOs, you may want to show the statuses of different Service Level Objectives (SLOs) in your existing tools so stakeholders can easily see them. Honeycomb's SLO API supports [reporting](/api/slos/) on: * Last reset date * Current budget remaining * Compliance level since last reset ## Reporting on a Single SLO To report on a single SLO: 1. Use the [Get All SLOs endpoint](/api/slos/get-all-slos) to get a list of all SLOs. 2. Find the desired SLO IDs in the returned results. You can also get an SLO's ID through the Honeycomb UI: Go to the SLO's page and look in the URL path. The SLO ID is the hash ID that follows `slo/` in the path. 3. Set up a system that regularly queries the [Get an SLO endpoint](/api/slos/get-an-slo) by ID for the SLOs you would like to report on, and use it to build your dashboards. SLO reporting data has a 5-minute time-to-live (TTL), so you only need to query once every 5 minutes per SLO. ## Showing Burn Rate Honeycomb SLOs expose the current compliance level since last reset and the remaining budget. If you want to show how close an SLO is to being exhausted, the best way is to show the remaining budget. To calculate the burn rate, you can save the data to your own database and compare past data. # What is a Trigger? Source: https://docs.honeycomb.io/notify/triggers Get real-time alerts when your data crosses defined thresholds. Use Triggers to detect issues, monitor system health, and respond to anomalies before they impact users. Beta Triggers let you receive notifications when your Honeycomb data crosses thresholds that you define. They help you detect issues, monitor system health, and respond quickly to anomalies before they impact users. You can configure triggers on any graph generated by a Honeycomb query, giving you flexibility to reduce false positives caused by known errors. To learn about guidelines for using SLOs and Triggers for alerting, visit [Guidelines for SLOs and Trigger Alerts](/get-started/best-practices/alerts/). For more structured learning, check out the [Triggers](https://academy.honeycomb.io/app/courses/a9febf06-6691-49c9-b466-3639a586767e) course from Honeycomb Academy. ## How Triggers Work Triggers let you define conditions on your data and automatically notify you when those conditions are met. ### Duration and Frequency Each Trigger monitors data over a set duration and runs at a defined frequency. * **Duration**: Time window of data the trigger evaluates. * **Frequency**: How often the trigger runs. For example, a trigger with a duration of 5 minutes and a frequency of 2 minutes will check the last 5 minutes of data every 2 minutes. ### Notification Methods When a trigger fires, it alerts you via the configured method(s). Supported methods include: * [PagerDuty](/notify/pagerduty/) * [Slack](/notify/slack/) * [Microsoft Teams](/notify/microsoft-teams/) * [Webhooks](/notify/webhooks/) * Email Notifications include a direct link to the triggering graph, so you can see current status and quickly jump into investigation. ### Tags Tags help you stay organized as your Team creates more Triggers. Use them to group related Triggers by project, team, service, or any other category that fits your workflow. Tags make it easier to filter and find the Triggers you need, especially in shared or busy environments. Because they're flexible and customizable, you can organize Triggers in the way that works best for you. ### Limits and Upgrades By default, users have two triggers available across all environments. Upgrade to a [Pro or Enterprise plan](https://www.honeycomb.io/pricing) to increase your number of available Triggers. ## Common Use Cases Teams use Triggers for a variety of monitoring purposes: | Use Case | Description | | --------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Lambda cost spikes | Detect sudden increases in usage or billing. Track the cost of Lambda queries and alert when they exceed a defined "normal" range. | | Database connection limits | Prevent service interruptions. Determine your database connection limit, and alert when database connection counts approach or exceed that saturation threshold. | | Kubernetes component status | Monitor Kubernetes components. For example, monitor pod startup failures or delays that indicate deployment or infrastructure issues. | | High login activity | Identify unusual spikes in login attempts, helping identify security threats such as credential stuffing or brute-force attacks. Determine what qualifies as a high number of login attempts in your environment and alert when activity exceeds that threshold. | | Internal operations check | Confirm that critical operations, like CronJobs, ran successfully. Alert if the operation is missing or failed. | ## What's Next? Create a trigger, define recipients, and activate a trigger using the Honeycomb UI. Edit and delete triggers using the Honeycomb UI. Explore examples of trigger notifications, which you can use as inspiration for defining and configuring your own triggers. # Create a Trigger Source: https://docs.honeycomb.io/notify/triggers/create Define a query, set a threshold, assign recipients, and activate a Trigger in Honeycomb to start receiving alerts when your data crosses the limit you set. Triggers send alerts when your data in Honeycomb crosses the thresholds that you configure. To learn more about guidelines for using Triggers to alert, visit [Guidelines for SLOs and Trigger Alerts](/get-started/best-practices/alerts/). ## Creating Triggers You can create a trigger within the **Triggers** page or while using the **Query Builder**. You can create a trigger for a specific dataset or across all datasets in your environment (an environment-wide trigger). Environment-wide triggers are useful when you need to alert on conditions that span across multiple services or datasets within your environment. 1. Select **Triggers** () from the navigation menu. 2. Select **New Trigger** in the top right corner. If no previous triggers exist, select **Create Your First Trigger** instead. 3. Choose your Dataset for the trigger and select **Make Trigger**. You can select an individual dataset or choose **All Datasets** to create an environment-wide trigger. Creating a new trigger from the Triggers page will require [entering a query](#trigger-query) during trigger configuration. Triggers Page with New Trigger Button You cannot create a trigger on a heatmap or a concurrency calculation. Learn more about [trigger best practices](/get-started/best-practices/alerts/#triggers). 1. Select **Query** () from the navigation menu. 2. Build and run a query. 3. Select the Show Actions icon (), located above **Run Query**, and select **Make Trigger**. You cannot create a trigger on a heatmap, concurrency, or rate calculation. Learn more about [trigger best practices](/get-started/best-practices/alerts/#triggers). For this example, we want to know whenever our cart has an error that is considered "slow" and to have the results grouped by `userid`, `http.url`, and `requestID`. The Query Builder ## Configuring Triggers To configure the trigger, define the trigger details, trigger alert threshold, and notification preferences in the Define New Trigger page that appears. ### Define New Trigger Enter identifying information for your Trigger: | Field | Description | | --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Name** | (required) Used in notifications about the trigger. Ensure the name describes clearly what has happened. | | **Description** | (optional) Used in notifications about the trigger. Recommended use: indicate next steps or include links back to documentation, so alert receiver will know how to respond. | | **Tags** | Labels that organize and group related Triggers, making it easier to [filter by tag](/notify/triggers/modify/#filter-triggers) and find them. Enter tags in key:value format (for example, `area:pipelines` or `team:prism`). Use **Assign** to add up to 10 tags per Trigger. Tag keys can contain letters only, up to 32 characters. Tag values can include alphanumeric characters and the special characters `/` and `-`, with a maximum length of 128 characters. | | Enabled | Determines whether Trigger is active. Toggle to enable \[on] or disable \[off]. | ### Trigger Query After defining your Trigger information, the next Query Run section displays your Trigger Query. A Trigger Query scopes the conditions for your Trigger threshold. If you created a new Trigger from Query Builder, your Trigger Query automatically populates and the sample graph appears automatically. If you created a new Trigger from the Triggers page, you must enter a Trigger Query before the sample graph appears. Create a Trigger Query using **SELECT**, **WHERE**, **GROUP BY**, and **HAVING** clauses. Use the Run in Query Builder icon () to the right of the available clauses to open your Trigger Query in Query Builder in a new tab. For inspiration on trigger queries, visit our [Trigger Examples](/notify/triggers/examples/). A Trigger query must contain one statement. If your query has multiple statements, you can add a formula to evaluate those statements into a single value. #### HAVING clause Use a **HAVING** clause to filter aggregated results in your Trigger Query. This will allow you to define composite alert conditions, and will only notify when all of those unique conditions are met. This is particularly useful when using **GROUP BY** on high-cardinality attributes where numerous distinct groups can be generated. Only one **HAVING** clause can be defined per Trigger Query. Unlike filters that affect the main graph data, **HAVING** use does not impact the primary visualization in the Trigger Query preview. Instead, a second graph appears that reflects the **HAVING** filter’s criteria, as seen in the [**HAVING** example](#trigger-query-example-with-having) below. #### Sample Graph After entering your trigger query, a sample graph appears, which displays how the trigger query and the trigger alert components interact. The sample graph displays the trends for your query with the most recent 16 periods as indicated by markers. By default, the sample graph's duration and frequency are both 15 minutes. Navigate to [Duration](#duration) and [Frequency](#frequency) in the Alerts section to modify these values and your sample graph will adjust accordingly. #### Trigger Query Example In the example below, the sample graph for a 30 minute frequency with a 120 minute duration shows the previous 1920 minutes (or 32 hours). Trigger Query with filters #### Trigger Query Example with HAVING In the example below, the top graph shows the results of the Trigger Query and the bottom graph shows the results of applying **HAVING** `COUNT_DISTINCT(app.user.id) > 5` to the Trigger Query. Trigger Query with HAVING ### Alerts Next, define the conditions for the trigger alert notification. 1. [Trigger Alert Type](#trigger-alert-type) 2. [Threshold](#threshold) 3. [Frequency of Alerts](#frequency-of-alerts) 4. [Duration](#duration) 5. [Frequency](#frequency) #### Trigger Alert Type Configure the type of calculation needed to notify. Select the named tab to choose between: * **Static Threshold** - Use to notify when the condition crosses the specific value of your configured static threshold. * **Dynamic Baseline** - Use to notify when a delta, or difference in value, is detected compared to a baseline value in the past. Use cases include Performance Monitoring, such as operational KPIs (traffic volume, error rates) shifts, and Customer Behavior Monitoring, such as drops in activity or spikes in churn. Your selection determines the display in the Threshold section. #### Threshold **Threshold** indicates what trigger condition generates a notification. Enter your notification conditions, depending on your Trigger Alert Type. 1. Compose the condition of your Static Threshold. Your trigger will alert when data meets or crosses this threshold. 1. First, determine the numerical value that the trigger should alert upon, based on your Trigger Query. Use **Trigger an alert if returned (choose a calculation) is** to enter this numerical value. 2. Use the dropdown window to select a calculation value: * `>` (greater than) * `=>` (greater than or equal to) * `<`(less than) * `<=`(less than or equal to) 2. Set the number of times the Threshold, or trigger condition, should be met consecutively before alerting you. Use **Send an alert after the threshold has been met `x` times** to enter this value. This value defaults to `1` and cannot be greater than `5`. For example, if the number of times a trigger's threshold has been met is `3` before alerting and the trigger's frequency is `5` minutes, then this trigger alerts when its threshold has been met for the past 15 minutes, or 3 cycles of `5` minutes. 1. Compose the conditions of your Dynamic Baseline. Your trigger will alert when the difference between an earlier value and the present value meets or exceeds your baseline value. Choose between a percentage change (%) or specific value, and whether it is higher or lower than compared to the value found in an earlier time range. 1. First, choose between a percentage change (%) or specific value. Enter the numerical value and select **percentage (%)** or **value** in the dropdown window. 2. Determine whether the comparison between the two values should be higher or lower. Select **higher** or **lower** in the dropdown window. 3. Determine the comparative time range and use the dropdown window to choose between: * 1 hour prior * 24 hours prior * 7 days prior * 28 days prior 2. Set the number of times the Threshold, or trigger condition, should be met consecutively before alerting you. Use **Send an alert after the threshold has been met `x` times** to enter this value. This value defaults to `1` and cannot be greater than `5`. #### Frequency of Alerts Configure how frequently alerts occur for your trigger. Use the toggle to choose between: * **Limited alerts (default)** - Receive two alerts: a triggered alert when the threshold is met or exceeds, and a resolved alert when the threshold is unmet. * **Continuous alerts** - Receive an alert every time the threshold is met and the trigger runs. For example, if the Trigger's frequency is set to 5 minutes, you will receive an alert every 5 minutes. No resolution alert is sent. About Triggered Groups: If you have specified fields in the **GROUP BY** clause of a trigger, then the trigger will notify all recipients when any new group crosses the trigger threshold. For example, if a trigger is already in a triggered state, and any new group surpasses the trigger threshold, the trigger will again notify all recipients and include the new groups that have triggered the alert. **Group limit** Triggers evaluate a maximum of 1,000 groups per query execution. This limit can affect breach detection accuracy when a trigger's **GROUP BY** query returns more groups than Honeycomb can evaluate. If your **GROUP BY** query returns more than 1,000 groups, Honeycomb sorts the results so the groups closest to breaching the threshold appear first, then evaluates only those first 1,000. Groups beyond the limit aren't checked against the trigger threshold, so evaluation can miss breaches when more than 1,000 groups exceed the threshold at the same time. To guarantee complete coverage, design your trigger query so the **GROUP BY** clause returns 1,000 or fewer groups. For example, narrow the query with additional filters or group on fields with fewer distinct values to stay within the limit. Use Continuous alerts: * To receive alerts when Triggers continue to meet or exceed the threshold * When the triggered event is more important than receiving a resolved event For example, if a trigger has specified fields in its **GROUP BY** clause, and "Continuous Alerts" is selected, then the trigger will notify all recipients when any new group crosses the trigger threshold, or if any group still exceeds the threshold. If one or more groups resolve, no resolved alert will be sent. #### Duration **Duration** determines what time range of data that the trigger will check. The default Duration value is 15 minutes. The duration of a trigger query can be 1 day at most, and cannot exceed 4 times the frequency of the trigger. For example, if the trigger's frequency is 1 hour, then query duration cannot be more than 4 hours. Duration can also not be less than the trigger's frequency. ##### Event Latency Graph Use the Event History Latency chart to help determine a duration that captures all your events, even if delayed. To expand the chart display, select the downward arrow icon (). This graph describes the maximum and average amount of delay between the timestamp on the event and when it reached Honeycomb. For example, if the average event latency is 2 minutes, and you want to run your trigger every 5 min, then choose a 7 minute duration to ensure that delayed events are captured by the trigger. Please note that if your traces span a long time frame, you may see high latency in this chart, even though the traces are arriving as soon as they complete. #### Frequency **Frequency** determines how often, in minutes, to evaluate for the Threshold, or trigger, condition. The default Frequency value is 15 minutes. Consider what is normal within your frequency window so notifications only capture conditions worth alerting. Dynamic Baseline Triggers requires a minimum Frequency value of 15 minutes. Trigger frequency must be specified in whole minutes, from `1` to `1440`. Decimal values are truncated to the preceding full minute. (`3.6` becomes `3`.) ##### Custom Scheduling Option Use Custom Scheduling to specify a scheduled window in which the trigger will run. For example, you only need alerts during business hours from Monday through Friday. To enable Custom Scheduling: 1. Toggle the **Custom scheduling** toggle to \[on]. 2. Specify the time range and days of the week that the trigger should run. Note that the start time and end time must be provided in [Coordinated Universal Time (UTC)](https://en.wikipedia.org/wiki/Coordinated_Universal_Time). Custom Scheduling Options ### Recipients The trigger will notify all listed **recipients** when the measured value crosses the configured threshold. No limitation exists for the number of recipients. By default, Honeycomb will send an alert to recipients once, when the trigger crosses the configured threshold or the Triggered state, and then send a resolved alert once the trigger is back in an OK state. To add a new recipient, select **Add Recipient**. Use **Go to Integration Center** to configure [additional trigger recipient integration options](/notify/), like Slack, PagerDuty, Microsoft Teams, and Webhooks. List of Trigger Recipients with email and PagerDuty recipients After selecting **Add Recipient**, a form will appear with Recipient options in a dropdown list. By default, you can select **Notify by Email** and enter email recipients. Additional [integration options](/notify/), like Slack, PagerDuty, Microsoft Teams, and Webhooks, can be selected once configured. Add Recipient form displaying the two Notify by Email fields ### Activate Trigger Finally, select **Create Trigger** to save your trigger configuration. Once saved, the trigger is immediately active and will run at the next frequency interval, such as on the next 5 minute interval for a 5 minute frequency. You can enable or disable a trigger by [editing the trigger](/notify/triggers/modify/) and selecting the **Enabled** toggle. ## Start from a Template You can create a Trigger from a template. Trigger Templates are visible in the right sidebar when creating a new Trigger. Selecting a template populates the Name, Description, and Query in the Trigger form. Trigger Templates are only available when creating a trigger for a specific dataset. Environment-wide triggers do not support templates. Trigger Templates reference fields that are set in your [Dataset Definitions](/configure/datasets/definitions/). If you select a template that references a field mapping that does not exist in your data, a warning message displays above the Trigger Query section that lists the missing Dataset Definition(s), as seen in the example below. To resolve the issue and fully use the Trigger Template, add the missing field and/or update your [Dataset Definitions](/configure/datasets/definitions/) to include the missing Dataset Definition(s). Shows Define New Trigger form with General Errors template selected and a missing Error dataset definition message. ### Available Trigger Templates | Template | Trigger Name | Trigger Description | Dataset Definitions Required | | -------------- | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ | | Latency | Latency is too high | This trigger notifies us if the average duration of root spans is higher than 500ms over the last 15 minutes. In the future, consider using P90 or P95 operators to handle outliers more reliably. | `Span Duration`
`Parent Span ID` | | HTTP Errors | Too many HTTP request errors | This trigger notifies us if there are any 400 or 500 level HTTP status requests | `HTTP Status Code`
`Parent Span ID` | | General Errors | Too many errors | This trigger notifies us if there are errors | `Error` | # Trigger Examples Source: https://docs.honeycomb.io/notify/triggers/examples Copy and adapt example Trigger configurations to start alerting on latency spikes, error rates, cost thresholds, and other common conditions in your data. Use the Trigger examples below when [creating a trigger](/notify/triggers/create/). The specific attributes in each example may or may not exist in your data and environment. Each example contains: * the attributes in the [Trigger query](/notify/triggers/create/#trigger-query) * the threshold value in the [Alerts section](/notify/triggers/create/#alerts) The example Trigger Queries use the three `VISUALIZE`, `WHERE`, and `GROUP BY` clauses, located at the top of the Query Builder display. * `VISUALIZE`: Performs a calculation and displays a corresponding graph over time. Most `VISUALIZE` queries return a line graph while the `HEATMAP` visualization shows the distribution of data over time * `WHERE`: Filters based on attribute parameter(s) * `GROUP BY`: Groups fields by attribute parameter(s) Screenshot of Visualize, Where, and Group by clauses in Query Builder ## Slow Response Times Slow response times can be frustrating and also indicate potential problems with your service. Use these trigger examples to alert your team if response times exceed a certain threshold. ### Alert When P95 of Traces > X ms The query calculates the 95th percentile of the total duration of the traces in your application, in seconds, and checks if it is greater than 550 ms. Use to alert if a significant number of the traces in the application are taking longer than the highest expected range to complete. | VISUALIZE | WHERE | GROUP BY | | ------------------ | --------- | -------- | | `P95(duration_ms)` | `is_root` | `name` | | THRESHOLD | | --------- | | `> 550ms` | ### Alert When P90 of Database Calls > X ms The threshold for your alert for `p90` database calls should be based on the expected performance of your database, and the requirements of your application. If the expected performance of the database is known, set the alert threshold to a value that is slightly higher than the expected performance, and also give some margin for error or variability. | VISUALIZE | WHERE | | ------------------ | --------------------- | | `P90(duration_ms)` | `db.statement exists` | | THRESHOLD | | --------- | | `> 550ms` | ## Error Rates High error rates can be an indication of underlying issues that are affecting the performance and stability of your service, and can help identify areas for improvement. Monitoring specific errors can also provide valuable insights into the types of issues that are occurring, and can help you understand the root causes of those errors. ### Alert When > X Exceptions or > X Specific Exceptions Adjust the threshold of exceptions (higher or lower than `500` occurrences) to fit the specific needs of your application, and to ensure that the alert is effective at identifying potential issues. | VISUALIZE | WHERE | GROUP BY | | --------- | ----------------------- | ---------------- | | `COUNT` | `exception.type exists` | `exception.type` | | THRESHOLD | | --------- | | `> 500` | Or for specific exceptions: | VISUALIZE | WHERE | GROUP BY | | --------- | --------------------------------------------------- | --------- | | `COUNT` | `exception.type = {push-notification-send-failure}` | `user.id` | | THRESHOLD | | --------- | | `> 0` | ## Tenant Errors This type of alert can be set up to trigger when a certain number of errors are generated by a specific tenant on a particular endpoint. For example, you could set up an alert to trigger when the number of errors generated by tenant "XYZ" on endpoint "/api/users" exceeds a certain threshold, such as `500` errors in an hour. Use this trigger example to identify potential issues that are affecting a specific tenant, and take action to address those issues. ### Alert When Application Tenant Errors are Present | VISUALIZE | WHERE | GROUP BY | | --------- | -------------- | --------------- | | `COUNT` | `error exists` | `app.tenant_id` | | THRESHOLD | | --------- | | `> 0` | # Metrics-based Triggers Source: https://docs.honeycomb.io/notify/triggers/metrics Monitor key metrics and get alerts based on custom threshold conditions and temporal aggregation functions. Learn how to create and update metrics-based Triggers, see example configurations, and understand key limitations and differences from event-based Triggers. ## Creating a metrics-based Trigger Setting up a metrics-based Trigger works much like setting up an event-based Trigger, with a few key differences tailored to how metrics behave. To create a metrics-based Trigger: 1. Select **Triggers** () from the navigation menu. 2. Select **New Trigger**. 3. In the modal that appears, select the **Metrics** dataset. 4. Define the Trigger query: * Enter a name and description. * Select fields from your metrics dataset. * Optionally, use [query-scoped Calculated Fields](/investigate/query/build/calculated-fields/#choosing-the-scope) to apply temporal aggregation functions like `RATE()` or `INCREASE()`, which compute change over time. Example: `my_rate_dc RATE(http_requests_total)`. * Ensure the query returns a single scalar value, not a time series. * Most queries start with a [temporal aggregation function](/investigate/query/temporal-aggregation/) wrapped in a spatial aggregation like `SUM()` or `AVG()`. Example: `SUM(my_rate_dc)`. * You can also use spatial aggregations alone on metrics. In this case, Honeycomb applies a default temporal aggregation function based on the metric's metadata as described in [Applying Temporal Aggregation Functions: Default Behavior](/investigate/query/apply-temporal-aggregation/#default-behavior). 5. Set threshold conditions and choose where to send notifications. 6. Select **Create Trigger** to save. Your Trigger will evaluate the query at regular intervals (every 15 minutes by default) and send alerts whenever the threshold condition is met. ## Modifying a Metrics-Based Trigger You can modify a metrics-based Trigger the same way you edit an event-based Trigger. To modify a metrics-based Trigger: 1. Select **Triggers** () from the navigation menu. 2. Find the Trigger you want to update, and select its name. 3. In the editor, adjust the query, threshold, or notification settings as needed. 4. Select **Save Trigger** to apply your changes. You cannot change a Trigger's dataset after it has been created. To use a different dataset, create a new Trigger. ## Examples Use these examples as a starting point for building your own metrics-based Triggers. Each highlights a common use case and shows how to structure the Trigger query. Define your calculated field before using it in a Trigger. You can do this while building the Trigger; appropriate clauses in the query editor include a **Define calculated field** option. **Error Rate Spike** * **Goal**: Detect a spike in errors * **Calculated Field**: `my_error_rate RATE($k8s.pod.network.errors)` * **Trigger Query**: `AVG(my_error_rate)` * **Threshold**: `> 0.05` This configuration alerts when the average error rate across the Environment exceeds 5%. **Saturation Check** * **Goal**: Detect a spike in CPU usage * **Calculated Field**: `last_cpu_util LAST($k8s.pod.cpu.utilization)` * **Trigger Query**: `AVG(last_cpu_util)` * **Threshold**: `> 0.9` This configuration tracks the most recent CPU utilization across containers and alerts when it rises above 90%. It uses `LAST()` to get the most recent sample for each container. **Throughput Threshold** * **Goal**: Detect sustained high request volume * **Calculated Field**:`incr_requests INCREASE($http.server.requests, 300)` * **Trigger Query**: `SUM(incr_requests)` * **Threshold**: `> 1000` This configuration alerts when total requests in the last 5 minutes exceed 1000. ## Compare Metrics-Based and Event-Based Triggers Metrics-based and event-based Triggers share a similar setup process, but they behave differently in how they evaluate data and support configuration. | Feature | Metrics-Based Triggers | Event-Based Triggers | | ------------------------------ | ---------------------------- | ---------------------- | | **Temporal Aggregation** | Via Calculated Fields only | Not applicable | | **Query Preview** | One bucket only; no 16x view | 16x historical preview | | **Templates** | Not supported | Supported | | **Granularity Selector in UI** | Available | Not Applicable | # Modify Triggers Source: https://docs.honeycomb.io/notify/triggers/modify Edit trigger queries, thresholds, and recipients, or delete Triggers you no longer need using the Honeycomb UI. ## Edit Triggers View all triggers for your team by selecting **Triggers** () in the left navigation bar. You will see a full list of the triggers. Select the trigger name to view and edit each trigger. Use the search function to find a Trigger based on its name. When editing a Trigger, using the Run in Query Builder icon () within the Query Trigger section only opens your Trigger Query in Query Builder in a new tab. Any changes made to the subsequent Query Builder display will not update the original Query Trigger. Triggers Page ### Remove Recipients To remove a Recipient from a Trigger: 1. Navigate to **Triggers** () in the left navigation bar. 2. Select the Trigger you want to modify. 3. In the Edit Trigger page, navigate to the Recipients section. 4. Select **Remove** next to the Recipient to remove. 5. Select **Save**. The page refreshes, and the Trigger updates to reflect your changes. ## Test Triggers After creation, Trigger notification testing becomes available. Use this feature to test if Trigger notifications appear as expected before an alert situation occurs. * For a Trigger with a limited alert, the test sends a Triggered and Resolved message for each configured notification option(s). * For a Trigger with a continuous alert, the test sends the Triggered notification only for each configured notification option(s). To test your Trigger notifications: 1. Navigate to the [Triggers display](/reference/honeycomb-ui/triggers/). 2. Select **Test** for the target Trigger. A confirmation modal appears. 3. Select **Launch Test** to confirm. ## Disable Triggers To disable a Trigger: 1. [Edit an existing Trigger](#edit-triggers). 2. Select the Enabled toggle to \[off]. 3. Select **Save Trigger** to save changes. Once disabled, a Trigger will not run and stop alerting. ## Delete Triggers To delete a trigger, either select the **Delete** button on the Triggers page, or while editing, select the **Delete** button at the bottom of the Edit Trigger page. ## Filter Triggers If your Triggers have tags applied to them, you can filter by tags. This helps you focus on related items. To filter Triggers by tag: 1. Select **Triggers** () from the navigation menu. 2. Select the **Filter by tags** field (or the tag area if a default tag is already applied), and choose the tags you want to filter by. # Send Alerts to Webhooks Source: https://docs.honeycomb.io/notify/webhooks Route Honeycomb Trigger and SLO burn alerts to any service that accepts a JSON payload, including third-party tools and custom integrations. The Webhooks + Honeycomb integration uses [Honeycomb Triggers](/notify/triggers/) or [Honeycomb Service Level Objective (SLO) Burn Alerts](/notify/slos/) to notify an arbitrary webhook based on alerts sent from Honeycomb. Use to integrate with third parties that receive JSON payloads. A webhook can be any HTTP endpoint which accepts JSON that you want Honeycomb to send notification of a trigger or SLO's changing state. Once configured, Honeycomb sends JSON payloads to your webhook upon alerts firing. The content will include an authentication header and the result of the alert in JSON in the body of the webhook. Honeycomb expects the webhook to respond within 10 seconds; if no response is received within this timeframe, the request will fail. If a delivery attempt fails due to a transient error, Honeycomb may automatically retry the request. Each request includes an `X-Honeycomb-Webhook-Delivery-ID` header with a unique identifier that stays the same across retries of the same delivery, so your endpoint can use it to deduplicate requests. You can [customize your webhook](#customize-your-webhook) in Honeycomb with [functions](/notify/webhooks/functions/) and [variables](/notify/webhooks/variables/). View our available [example webhook templates](/notify/webhooks/example-templates/) for inspiration. Refer to our API documentation for [programmatic management of webhook notifications](/api/recipients/). ## Before You Begin Before you set up the integration, you'll need a user account in your Honeycomb Team. ## Set Up Your Integration Before you can configure Honeycomb to send alerts to your webhook, you must set up your webhook integration. ### Create a Webhook To create a webhook: 1. Navigate to **Team Settings**, and select the **Integrations** view. 2. Locate **Trigger and SLO Recipients**, and select **Add Integration**. 3. For **Provider**, select **Webhook**. 4. Enter a **Name**. We recommend using a name that will be easy to find when configuring alerts in the future. 5. Enter your **Webhook URL**, and optionally a **Shared Secret** for either: * an HTTP endpoint running within your infrastructure * the URL and headers needed by the target service to send alerts 6. Optionally, [customize your webhook](#customize-your-webhook) by using the [Payload](#customize-webhook-payload), [Variables](#customize-webhook-variables), and/or [Headers](#customize-webhook-headers) tabs. 7. Select **Add**. ## Configure Alerts to Use Your Webhook After your webhook integration is set up in Honeycomb, you can configure Triggers and SLOs to use your webhook as a recipient for alerts. ### Configure Triggers to Use Your Webhook To configure Triggers to use your Webhook: 1. In the Honeycomb UI, navigate to **Triggers**. 2. Select the name of the existing trigger you want to configure, or create a new trigger by selecting **New Trigger**. 3. Locate the **Recipients** section, and select **Add Recipient**. 4. In the **Add Trigger Recipient** modal, locate the **Recipient** dropdown and select your webhook integration. 5. Select **Add**. 6. Select **Save Trigger**. ### Configure SLO Burn Alerts to Use Your Webhook To configure SLO Burn Alerts to use your webhook: 1. In the Honeycomb UI, navigate to **SLOs**. 2. Select the name of the existing SLO you want to configure, or create a new SLO by selecting **New SLO**. 3. Find your SLO in the list, and select the **Configure** button in the **Burn Alerts** column. 4. Select **New Burn Alert**. 5. In the **Create Burn Alert** form: 1. Set your desired exhaustion time. 2. Select your webhook integration in the **Notify** dropdown. 3. Set your desired **Severity**. (Critical is the default value.) 6. Select **Create Burn Alert**. ## Customize Your Webhook Customizing your webhook integration allows for the tailoring your alert notifications for Triggers and SLOs to your needs. You can: * Customize Alert Content: Modify the structure and content of your alert payloads, including adding, removing, or reordering fields to meet the specific requirements of your target systems * Customize Alert Headers: Include relevant header keys and values accompanying the JSON payload. This allows you to integrate with services that expect specific HTTP header values * Include Alert-level Variable Support: Automatically include relevant alert context, such as the severity of the alert. This will allow you to pass critical context to your alert recipients without needing to manually customize each notification ### Customize Webhook Payload A webhook that uses custom payloads must have a corresponding payload for an alert type in order for it to be used with that alert type. For example, a webhook with only a configured Trigger payload cannot be used by an SLO Budget Rate Burn Alert. A webhook can have up to all three payload types configured. If no payload types are configured, then a webhook will operate as a standard webhook in Honeycomb. To customize your webhook payload: 1. Within the webhook integration modal, navigate to the **Payload** tab. 2. Toggle **Enable** next to each alert type to configure its payload. All three alert payload types - Triggers, (SLO) Budget Rate Burn, (SLO) Exhaustion Time Burn Alerts - can be enabled if desired. A text area will appear to enter a JSON template. 3. Use the pre-configured **Generic Webhook** option or use the text area to further customize your JSON template. Refer to our [template example documentation](/notify/webhooks/example-templates/) for inspiration. 4. Optionally, you can configure and include custom [variables](#customize-webhook-variables) and [headers](#customize-webhook-headers) for use within your webhook. 5. Select **Add** for new webhooks or **Update** for existing webhooks to complete the process. Once saved, you can configure the [Trigger](#configure-triggers-to-use-your-webhook) or [SLO Burn Alert](#configure-slo-burn-alerts-to-use-your-webhook) to use your custom webhook. ### Customize Webhook Variables Webhooks with enabled custom payload templates may define up to 10 variables that can be referenced in the templates. Our [custom payload variable documentation](/notify/webhooks/variables/) includes a list of available variables. Optionally, these variables can be [overridden](#override-payload-template-variables) when configuring the webhook to a given Trigger or SLO Burn Alert. #### Define Payload Template Variables Webhooks with enabled custom payload templates may define up to 10 variables that can be referenced in the templates. Variables must first be defined in the Webhook integration: 1. Navigate to **Team Settings**, and select the **Integrations** view. 2. Locate **Trigger and SLO Recipients**. 3. Create a new webhook or navigate to an existing webhook. 1. If creating a new webhook, start the [webhook creation process](#create-a-webhook) by selecting **Add Integration** and entering values. 2. If editing an existing webhook, locate the desired Webhook integration in the list of integrations, and select **Edit**. 4. In the modal, select the **Variables** tab. 5. Select **Add variable**. You can add up to 10 variables. 6. Enter a name for the variable. The variable name must: 1. be alphanumeric 2. be 64 characters or less 3. begin with a lowercase letter 4. be unique among all variables defined for this Webhook 7. Optionally, enter a default value for the variable. This default value must be 256 characters or less. Once defined, variables can be referenced in the payload template. For example, in a format similar to: ```text theme={} {{ .Vars.severity }} ``` #### Override Payload Template Variables Once defined in the Webhook integration, payload template variables may be overridden when using the Webhook integration with a Trigger or SLO Burn Alert. For example, you could define a `severity` variable, and give it a default value of `warning`. Then, when configuring an important Trigger, you could override that variable's default value with a value of `critical`. When the Trigger fires, the value of the payload template variable will evaluate in the following order: * The override value for the variable, if it exists. * The default value for the variable, if it exists. * The empty string `""`. ##### Triggers To override payload template variable(s) in a Trigger: 1. In the Honeycomb UI, navigate to **Triggers**. 2. Select the name of the trigger you want to configure, or create a new trigger by selecting **New Trigger**. 3. Locate the **Recipients** section, and select **Add Recipient**. 4. In the **Add Trigger Recipient** modal, locate the **Recipient** dropdown and select your webhook integration. 5. All defined payload template variables for the selected webhook integration are displayed in rows. 6. Locate the row for the variable you would like to override. 7. Optionally, enter the override value for the variable in the "Value" text box. This override value must be 256 characters or less. 8. Select **Add**. 9. Select **Save Trigger**. ##### SLO Burn Alerts To override payload template variable(s) in SLO Burn Alerts: 1. In the Honeycomb UI, navigate to **SLOs**. 2. In the list, locate the SLO you want to configure, or create a new SLO by selecting **New SLO**. 3. Find your SLO in the list, and select the **Configure** button in the **Burn Alerts** column. 4. Select **New Burn Alert**. 5. In the **Create Burn Alert** form: 1. Set your desired exhaustion time. 2. Select your webhook integration in the **Notify** dropdown. 6. Locate the target variable to override. All defined payload template variables for the selected webhook integration are displayed in rows. 7. Optionally, enter the override value for the variable in the "Value" text box. This override value must be 256 characters or less. 8. Select **Create Burn Alert**. ### Customize Webhook Headers When sending a notification to the specified webhook endpoint, Honeycomb will always include the following HTTP headers: | Header name | Value | | --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | | `Content-Type` | `application/json` | | `User-Agent` | `Honeycomb Triggers` | | `X-Honeycomb-Webhook-Token` | The value of the Webhook integration's **Shared Secret** | | `X-Honeycomb-Webhook-Delivery-ID` | A unique identifier for this webhook delivery. Consistent across retries of the same delivery, so you can use it to deduplicate requests. | You may need to provide additional HTTP headers for the specified webhook endpoint. For example, a webhook endpoint could require a `Authentication` header with a value of `Bearer `. To customize your webhook header(s): 1. Navigate to **Team Settings**, and select the **Integrations** view. 2. Locate **Trigger and SLO Recipients**. 3. Locate the desired Webhook integration in the list of integrations, and select "Edit". 4. Select the **Headers** tab. 5. Select **Add header**. You can add up to 5 headers. 6. Enter a name for the header. The name must: 1. Be 64 characters or less 2. Not match `Content-Type`, `User-Agent`, or `X-Honeycomb-Webhook-Token` 7. Enter a value for the header. The value must be 512 characters or less. ## Remove a Webhook Integration To remove a webhook integration, you will need to delete it from your Honeycomb team. Deleting the webhook integration from your team removes it from all associated Triggers and SLOs. 1. Navigate to **Team Settings**, and select the **Integrations** view. 2. Locate **Trigger and SLO Recipients**. 3. Find your webhook integration. 4. Select **Edit**. 5. In the form editor, select **Remove**. # Examples: Webhook Templates Source: https://docs.honeycomb.io/notify/webhooks/example-templates Copy and adapt example webhook payload templates for Discord, OpsGenie, and incident.io to customize how Honeycomb alert data is delivered to your tools. Use the example templates below as inspiration when creating custom webhooks. ## Discord Payload Template To learn more, visit [Discord's Developer Documentation](https://discord.com/developers/docs/resources/webhook#execute-webhook). ### Discord Template Example ```go-template theme={} { "username": "Honeycomb Triggers", "avatar_url": "https://i.imgur.com/4M34hi2.png", "embeds": [ { "title": ":bee: {{ .Alert.Summary }}", "url": "{{ .Resource.URL}}", "description": "{{ .Description }}", "color": {{ if eq .Alert.Status "TRIGGERED"}}1127128{{ else }}14177041{{ end }}, "fields": [ { "name": "Status", "value": "{{ .Alert.Status }}", "inline": true } ] } ] } ``` ## Incident.io Payload Template To learn more, visit [Incident.io Documentation](https://api-docs.incident.io/tag/Alert-Events-V2). ### Incident.io Template Example ```go-template theme={} { "deduplication_key": "{{ .Alert.InstanceID }}", "description": "{{ .Description }}", "metadata": { "team": "my-team", "result_url": "{{ .Result.URL }}" }, "source_url": "{{ .URL }}", "status": "{{ if eq .Alert.Status "TRIGGERED"}}firing{{ else }}resolved{{ end }}", "title": "[{{ .Environment }}] {{ .Name }}" } ``` ## OpsGenie Payload Template OpsGenie requires that an "Authorization" header be included with the value of the header in the format: `GenieKey YOUR-APIKEY` To learn more, visit [OpsGenie Documentation](https://docs.opsgenie.com/docs/alert-api#create-alert). ### OpsGenie Template Example ```go-template theme={} { "message": "{{ .Alert.Summary }}", "alias": "{{ .Alert.InstanceID }}", "description": "{{ .Alert.Description }}", "note": "{{ .Description }}", "source": "{{ .URL }}", "details": { "env": "{{ .Environment }}", "team": "my-team", "result_url": "{{ .Result.URL }}" } } ``` # Custom Webhook Functions Source: https://docs.honeycomb.io/notify/webhooks/functions Transform JSON template data in your Honeycomb webhook payloads using Go template functions to format, filter, and restructure alert content before delivery. On occasion, there is a need to transform JSON template data in order to use it with an integration’s endpoint. Use functions to further [customize your webhook payloads](/notify/webhooks/#customize-your-webhook). The Go template language – and other tools that make use of it – uses template functions and pipelines to make transformation flexible and powerful. Template functions follow the syntax `function arg1 arg2…`, and pipelines draw on the UNIX concept of chaining together a series of template commands to express a series of transformations separated by a "pipe" (`|`) character. An example combining functions and pipelines together looks like this: ```go-template theme={} {{ .Environment | upper | quote }} ``` When evaluated with an Environment of prod, the result will be `"PROD"`. All the standard Go template [actions](https://pkg.go.dev/text/template#hdr-Actions), [functions](https://pkg.go.dev/text/template#hdr-Functions), and a dozen or so additional template functions are available for use when authoring templates. ### date `date` formats a timestamp: ```go-template theme={} {{ now | date "2006-01-02" }} ``` The above returns `2024-11-22`. Useful in conjunction with `.Alert.Timestamp` ### join `join` joins a list of things into a single string with the provided separator: ```go-template theme={} {{ list group1 group2 group3 | join "," }} ``` The above returns `group1,group2,group3`. ### lower `lower` converts the entire string to lowercase: ```go-template theme={} {{ lower "HELLO" }} ``` The above returns `hello`. ### now `now` returns the current time at the time of template execution. Most useful with `date`. ### quote `quote` wraps the string in double quotes: ```go-template theme={} {{ quote .Environment }} ``` The above returns `"prod"` assuming the value of ".Environment" is `prod`. ### sort `sort` sorts a list of strings into alphabetical (lexicographical) order: ```go-template theme={} {{ list orange apple banana | sort }} ``` The above returns `[apple banana orange]`. ### splitList `splitList` splits a string into a list of strings: ```go-template theme={} {{ splitList ":" "one:two:three" }} ``` The above returns `[one two three]`. ### split `split` splits a string into a map of strings, keyed by index: ```go-template theme={} {{ $a := split ":" "one:two:three" }} {{ $a._0 }} {{/* one */}} {{ $a._1 /} {{/* two */}} {{ $a._2 }} {{/* three */}} ``` ### toJson `toJson` encodes an item into a JSON string. If the item cannot be converted to JSON, then the function returns an empty string. ```go-template theme={} {{ list apple banana orange | toJson }} ``` The above returns `["apple", "banana", "orange"]`. ### trim `trim` removes whitespace from either side of a string: ```go-template theme={} {{ trim " hello " }} ``` The above returns `hello`. ### trunc `trunc` truncates a string by a specified number of characters: ```go-template theme={} {{ trunc 5 "hello world" }} ``` The above returns `hello`. ```go-template theme={} {{ trunc -5 "hello world" }} ``` The above returns `world`. ### upper `upper` converts the entire string to uppercase: ```go-template theme={} {{ upper "hello" }} ``` The above returns `HELLO`. ### duration `duration` formats a given amount of seconds in human-readable time: ```go-template theme={} {{ duration 95 }} ``` The above returns `1m35s`. # Custom Webhook Variables Source: https://docs.honeycomb.io/notify/webhooks/variables Customize Honeycomb webhook payloads with dynamic variables that populate alert context for precise, actionable notifications. Customize Honeycomb alerts with variables for precise, actionable notifications. ## Introduction Use variables to customize payloads for your Honeycomb trigger alerts and SLO burn alerts. These variables dynamically populate your webhook payloads, ensuring that alerts contain the relevant information for your workflows. To learn more about working with variables in custom webhooks, visit [Custom Webhooks: Define Payload Template Variables](/notify/webhooks/#define-payload-template-variables) and [Custom Webhooks: Override Payload Template Variables](/notify/webhooks/#override-payload-template-variables). ## Simple Example You can reference a variable in a JSON payload template like this: ```json theme={} { "message": "{{ .Alert.Summary }}" } ``` In this example, `.Alert.Summary` is a variable that dynamically evaluates to the summary of the alert when the webhook is sent. ## Array Variables When using variables that return arrays, wrap them with `toJson` to generate valid JSON: ```json theme={} { "datasets": {{ toJson .Datasets }} } ``` In this example, the `.Datasets` variable contains a list of dataset names associated with the alert. Wrapping the variable with `toJSON` ensures proper JSON formatting. Omitting `toJson` for array variables will trigger an error like: `Failed to send: invalid character 'e' in literal true (expecting 'r')`. ## Variables for Triggers Trigger variables provide contextual information about alerts. Use them to customize payloads for your integrations. | Variable | Type | Description | Example | | ------------------------------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | `.Name` | string | Human-readable name of the trigger. Use this in messages to identify which trigger fired. | "Deflector Shield Overload" | | `.ID` | string | Unique identifier for the trigger. Useful for programmatic references or deduplication. | "JwwZxfcP5kH" | | `.Description` | string | Short summary of the trigger. We suggest including what it monitors and why it exists. Helps recipients understand context. | "One or more deflector shields are overloaded. Consider diverting power from other shields to compensate. See YT-1300 Operations Manual page 167 for diagnostics." | | `.URL` | string | Direct link to the trigger's detail page in the Honeycomb UI. Allows quick access for troubleshooting or investigation. | `"https://ui.honeycomb.test/rebel-alliance/environments/test/datasets/falcon/triggers/4a77775a78666350356b48"` | | `.Environment` | string | Name of the Honeycomb environment where the trigger is defined. Useful for scoping alerts to the correct context. | "test" | | `.Datasets` | array | List of dataset names monitored by the trigger. Can be used to include dataset context in alerts. For correct formatting, [wrap array variables with `toJSON`](#array-variables). | `["test"]` | | `.Tags` | array | List of tags assigned to the trigger, each with a `key` and `value` field. For correct formatting, [wrap array variables with `toJSON`](#array-variables). | `[{"key": "team", "value": "rebel-alliance"}]` | | `.Operator` | string | Comparison operator used to evaluate the trigger condition. | "less than or equal to" | | `.Threshold` | float | Numeric threshold value that, when exceeded or met, causes the trigger to fire. | 1.5 | | `.Frequency` | integer | How often the trigger is evaluated, in minutes. | 15 | | `.Query.TimeRange` | integer | Duration of the query that the trigger uses for evaluation, in seconds. | 60 | | `.Result.URL` | string | Direct link to the query result that caused the alert. Useful for viewing data behind the trigger. | `"https://ui.honeycomb.test/rebel-alliance/environments/test/datasets/falcon/result/4656626d79/a/6e694854a6241"` | | `.Result.Groups` | array | Groups included in the trigger evaluation. For correct formatting, [wrap array variables with `toJSON`](#array-variables). | | | `.Result.GroupsTriggered` | array | Groups that met or exceeded the trigger threshold. For correct formatting, [wrap array variables with `toJSON`](#array-variables). | | | `.Result.Groups[0].Group.Key` | string | Column name used for grouping results. Helps identify which metric or dimension caused the trigger. | "endpoint" | | `.Result.Groups[0].Group.Value` | any | Value of the grouping column for this group. | "/1/example/endpoint" | | `.Result.Groups[0].Result` | float | Query result for this specific group. Can be included in alert messages to show actual values. | 10 | | `.Alert.InstanceID` | string | Unique identifier for this specific trigger firing. Useful for deduplication or correlating alerts. | "c0fd570f-e920-4022-96d2-39e7df3e0621" | | `.Alert.Description` | string | Short summary of the alert. We suggest including which groups or values caused it to fire. | "test environment:\nCurrently less than or equal to threshold value (less than or equal to) for location: rear (value 0), location: port (value 0)" | | `.Alert.Status` | string | Status of the trigger. Possible values include: `"TRIGGERED"` (indicates the condition was met), `"OK"` (means it is normal). | "TRIGGERED" | | `.Alert.Summary` | string | Concise summary of the alert suitable for notifications or messages. | "TEST: Triggered: Rear Deflector Shield Overload" | | `.Alert.IsTest` | boolean | Indicates whether this alert firing is a test or a real evaluation. | true | | `.Alert.Timestamp` | time | Timestamp for the time at which the Trigger was evaluated. Useful for tracking and audit purposes. | 2024-11-21T16:40:22.896871538Z | | `.Alert.Type` | string | Type of trigger evaluation. Possible values include: `"on_change"` (fires when the status changes), `"on_true"` (fires whenever the condition is true). | "on\_change" | | `.Alert.InvestigateURL` | string | Direct link to the Canvas investigation for this alert. Populated when Honeycomb Intelligence is enabled; empty otherwise. | `"https://ui.honeycomb.test/rebel-alliance/v2/canvas/investigations/4a77775a78666350356b48"` | | `.Recipient.Name` | string | Name of the person or system receiving the alert. | "Primary On Call" | | `.Recipient.Secret` | string | Shared secret of the recipient. Useful if you need to include authorization in the request body. | "some-shared-secret" | ## Variables for SLO Budget Rate Burn Alerts These variables provide information about SLO burn alerts for monitoring error budget consumption. | Variable | Type | Description | Example | | ------------------------------ | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | `.Name` | string | Human-readable name of the SLO associated with the burn alert. Use this to identify which SLO is impacted. | "Diagnostics Check Errors" | | `.ID` | string | Unique identifier for this specific burn alert. Useful for programmatic references. | "U7nREbqQ3z" | | `.Description` | string | Short summary of the burn alert. We suggest including why the burn alert exists and what it monitors. Helps recipients understand the alert context. | "Many diagnostics checks are failing. If this continues, critical systems may go offline. BubbleUp on component to understand failures." | | `.URL` | string | Direct link to the burn alert's detail page in the Honeycomb UI. Allows quick access for investigation. | `"https://ui.honeycomb.test/rebel-alliance/environments/test/datasets/falcon/slos/burn_alerts/55376e5245627151337a"` | | `.Environment` | string | Name of the Honeycomb environment where the burn alert is active. Helps scope alerts to the correct context. | "test" | | `.Datasets` | array | List of dataset names associated with the burn alert. For correct formatting, [wrap array variables with `toJSON`](#array-variables). | \["test"] | | `.BudgetRateWindowMinutes` | integer | Time window used to calculate the budget rate, in minutes. | 10 | | `.BudgetDecreaseThreshold` | float | Threshold of budget decrease rate that triggers this alert. | 1 | | `.SLO.URL` | string | Direct link to the associated Service Level Objective (SLO) in the Honeycomb UI. Useful for deeper investigation. | `"https://ui.honeycomb.test/rebel-alliance/environments/test/datasets/falcon/slo/6a373935455846566a4844"` | | `.SLO.ID` | string | Unique identifier for the associated SLO. | "R74738d7" | | `.SLO.Tags` | array | List of tags assigned to the SLO associated with this burn alert, each with a `key` and `value` field. For correct formatting, [wrap array variables with `toJSON`](#array-variables). | `[{"key": "team", "value": "rebel-alliance"}]` | | `.SLI.URL` | string | Direct link in the Honeycomb UI to Service Level Indicator (SLI) underlying the SLO. | `"https://ui.honeycomb.test/rebel-alliance/environments/test/datasets/falcon/schema?dc=sli.diagnostics"` | | `.Alert.InstanceID` | string | Unique identifier for this instance of the burn alert firing. Useful for deduplication. | "c056e6a4-6a76-444d-a475-d4b02569fa26" | | `.Alert.Description` | string | Brief explanation of the alert. | "Diagnostics Check Errors" | | `.Alert.Status` | string | Status of the burn alert. Possible values include: `"TRIGGERED"` (indicates the budget rate threshold was exceeded), `"OK"` (means it is within limits). | "TRIGGERED" | | `.Alert.Summary` | string | Concise summary of the alert, suitable for notifications. | "Triggered: Diagnostics Check Errors budget rate is above 5%" | | `.Alert.IsTest` | boolean | Indicates whether this alert was generated during a test run. | true | | `.Alert.Timestamp` | time | Timestamp of the time when the burn alert was evaluated. Useful for auditing and tracking. | 2024-11-21T16:40:22.896871538Z | | `.Alert.CurrentBudgetDecrease` | float | Rate of budget decrease at the time the alert fired. | 1.34 | | `.Alert.InvestigateURL` | string | Direct link to the Canvas investigation for this alert. Populated when Honeycomb Intelligence is enabled; empty otherwise. | `"https://ui.honeycomb.test/rebel-alliance/v2/canvas/investigations/burn-alerts"` | | `.Recipient.Name` | string | Name of the person of system receiving this alert. | "Primary On Call" | | `.Recipient.Secret` | string | Shared secret of the recipient. Useful if you need to include authorization in the request body. | "some-shared-secret" | ## Variables for SLO Exhaustion Time Burn Alerts Use these variables when configuring burn alerts that monitor projected SLO exhaustion time. | Variable | Type | Description | Example | | ----------------------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | `.Name` | string | Human-readable name of the SLO tied to this burn alert. Helps identify which SLO may be at risk. | "Diagnostics Check Errors" | | `.ID` | string | Unique identifier for this specific burn alert. Useful for referencing programmatically. | "U7nREbqQ3z" | | `.Description` | string | Short summary of the burn alert. We suggest including why the burn alert exists and what it monitors. Helps recipients understand the alert context. | "Many diagnostics checks are failing. If this continues, critical systems may go offline. BubbleUp on component to understand failures." | | `.URL` | string | Direct link to the burn alert page in the Honeycomb UI. Enables quick investigation. | `"https://ui.honeycomb.test/rebel-alliance/environments/test/datasets/falcon/slos/burn_alerts/55376e5245627151337a"` | | `.Environment` | string | Name of the Honeycomb environment where the burn alert is active. | "test" | | `.Datasets` | array | List of dataset names associated with the burn alert. For correct formatting, [wrap array variables with `toJSON`](#array-variables). | \["test"] | | `.ExhaustionMinutes` | integer | Configured amount of time until the SLO budget is projected to be exhausted, in minutes. | 60 | | `.SLO.URL` | string | Direct link to the associated Service Level Objective (SLO). Useful for reference or investigaton. | `"https://ui.honeycomb.test/rebel-alliance/environments/test/datasets/falcon/slo/6a373935455846566a4844"` | | `.SLO.ID` | string | Unique identifier for the SLO associated with this burn alert. | "R74738d7" | | `.SLO.Tags` | array | List of tags assigned to the SLO associated with this burn alert, each with a `key` and `value` field. For correct formatting, [wrap array variables with `toJSON`](#array-variables). | `[{"key": "team", "value": "rebel-alliance"}]` | | `.SLI.URL` | string | Direct link to the Service Level Indicator (SLI) driving this SLO. | `"https://ui.honeycomb.test/rebel-alliance/environments/test/datasets/falcon/schema?dc=sli.diagnostics"` | | `.Alert.InstanceID` | string | Unique identifier for this instance of the burn alert firing. Can be used to deduplicate alerts. | "c056e6a4-6a76-444d-a475-d4b02569fa26" | | `.Alert.Description` | string | Short explanation of the alert event. | "Diagnostics Check Errors" | | `.Alert.Status` | string | Status of the burn alert. Possible values include: `"TRIGGERED"` (exhaustion is approaching), `"OK"` (the SLO is within budget). | "TRIGGERED" | | `.Alert.Summary` | string | Concise summary of the alert, useful for notifications. | "Triggered: Diagnostics Check Errors will violate SLO in 1h" | | `.Alert.IsTest` | boolean | Indicates if the alert firing occurred during a test. | true | | `.Alert.Timestamp` | time | Timestamp of the time when the burn alert was evaluated. | 2024-11-21T16:40:22.896871538Z | | `.Alert.InvestigateURL` | string | Direct link to the Canvas investigation for this alert. Populated when Honeycomb Intelligence is enabled; empty otherwise. | `"https://ui.honeycomb.test/rebel-alliance/v2/canvas/investigations/burn-alerts"` | | `.Recipient.Name` | string | Name of the person or system receiving the alert. | "Primary On Call" | | `.Recipient.Secret` | string | Shared secret of the recipient. Useful if you need to include authorization in the request body. | "some-shared-secret" | # Reference: Calculated Field Expression Source: https://docs.honeycomb.io/reference/calculated-field-expression Reference for calculated field syntax, operators, and functions, with example formulas to use as inspiration when building your own calculated fields. Calculated Fields, previously called derived columns, are fields with values calculated by expressions or formulas you provide. You can learn more about basic syntax, operators, and supported values on the [Calculated Field Syntax](/reference/calculated-field-expression/syntax/) page. If you need some inspiration, check out our [example formulas](/reference/calculated-field-expression/example-formulas/) for some ideas on what you can do with your own calculated fields. ## Available functions * [Math functions](/reference/calculated-field-expression/math/) * [SUM](/reference/calculated-field-expression/math/#sum) * [SUB](/reference/calculated-field-expression/math/#sub) * [MUL](/reference/calculated-field-expression/math/#mul) * [DIV](/reference/calculated-field-expression/math/#div) * [MOD](/reference/calculated-field-expression/math/#mod) * [MIN](/reference/calculated-field-expression/math/#min) * [MAX](/reference/calculated-field-expression/math/#max) * [LOG10](/reference/calculated-field-expression/math/#log10) * [BUCKET](/reference/calculated-field-expression/math/#bucket) * [Comparison functions](/reference/calculated-field-expression/comparison/) * [LT (less than)](/reference/calculated-field-expression/comparison/#lt) * [LTE (less than or equal)](/reference/calculated-field-expression/comparison/#lte) * [GT (greater than)](/reference/calculated-field-expression/comparison/#gt) * [GTE (greater than or equal)](/reference/calculated-field-expression/comparison/#gte) * [EQUALS](/reference/calculated-field-expression/comparison/#equals) * [Logical functions](/reference/calculated-field-expression/logical/) * [AND](/reference/calculated-field-expression/logical/#and) * [OR](/reference/calculated-field-expression/logical/#or) * [NOT](/reference/calculated-field-expression/logical/#not) * [IN](/reference/calculated-field-expression/logical/#in) * [EXISTS](/reference/calculated-field-expression/logical/#exists) * [Conditional functions](/reference/calculated-field-expression/conditional/) * [IF](/reference/calculated-field-expression/conditional/#if) * [SWITCH](/reference/calculated-field-expression/conditional/#switch) * [COALESCE](/reference/calculated-field-expression/conditional/#coalesce) * [String and Regular Expression functions](/reference/calculated-field-expression/string/) * [CONCAT](/reference/calculated-field-expression/string/#concat) * [TO\_LOWER](/reference/calculated-field-expression/string/#to_lower) * [STARTS\_WITH](/reference/calculated-field-expression/string/#starts_with) * [ENDS\_WITH](/reference/calculated-field-expression/string/#ends_with) * [CONTAINS](/reference/calculated-field-expression/string/#contains) * [REG\_MATCH](/reference/calculated-field-expression/string/#reg_match) * [REG\_VALUE](/reference/calculated-field-expression/string/#reg_value) * [REG\_COUNT](/reference/calculated-field-expression/string/#reg_count) * [LENGTH](/reference/calculated-field-expression/string/#length) * [Time functions](/reference/calculated-field-expression/time/) * [UNIX\_TIMESTAMP](/reference/calculated-field-expression/time/#unix_timestamp) * [EVENT\_TIMESTAMP](/reference/calculated-field-expression/time/#event_timestamp) * [INGEST\_TIMESTAMP](/reference/calculated-field-expression/time/#ingest_timestamp) * [FORMAT\_TIME](/reference/calculated-field-expression/time/#format_time) * [Type cast functions](/reference/calculated-field-expression/cast/) * [INT](/reference/calculated-field-expression/cast/#int) * [FLOAT](/reference/calculated-field-expression/cast/#float) * [BOOL](/reference/calculated-field-expression/cast/#bool) * [STRING](/reference/calculated-field-expression/cast/#string) Calculated fields can be created for a specific dataset or for an entire environment. * [Create environment calculated fields](/configure/environments/calculated-fields/) * [Create dataset calculated fields](/configure/datasets/calculated-fields/) # Type Conversion in Calculated Fields Source: https://docs.honeycomb.io/reference/calculated-field-expression/cast Type conversion functions available for calculated field formulas in Honeycomb, including INT, FLOAT, STR, and BOOL casts. Type cast functions convert one data type into another. ## `INT` The expression T(v) converts the value v to the type T. The `INT(arg)` Casts the argument to an integer, truncating the value if necessary. The argument is first coerced to a float if possible. Non-numeric values return 0. ```ruby theme={} # Usage: INT(arg1) # Examples INT($price_dollars) INT(DIV($seconds, 3600)) ``` ## `FLOAT` Casts the argument to a float. Non-numeric values return 0.0. ```ruby theme={} # Usage: FLOAT(arg1) # Examples FLOAT($price_dollars) # For example, 300.5 FLOAT("3.1415926535") # 3.1415926535 ``` ## `BOOL` Casts the argument to a bool. Evaluates to `true` if the argument is truthy: | source type | `value` | `BOOL($value)` | | ----------- | ------------------- | -------------- | | int | `0` | `false` | | int | **(anything else)** | `true` | | float | `0.0` | `false` | | float | **(anything else)** | `true` | | string | `"true"` | `true` | | string | **(anything else)** | `false` | | bool | `true` | `true` | | bool | `false` | `false` | | | `nil` | `false` | ```ruby theme={} # Usage: BOOL(arg1) # Examples BOOL($price_dollars) # For example, true BOOL("") # false BOOL(true) # true ``` ## `STRING` Casts the argument to a string. Empty arguments are converted to `""`. ```ruby theme={} # Usage: STRING(arg1) # Examples STRING($price_dollars) # "300.5", for example STRING(true) # "true" STRING($empty_column) # "" ``` # Comparison Functions in Calculated Fields Source: https://docs.honeycomb.io/reference/calculated-field-expression/comparison Comparison functions available for calculated field formulas in Honeycomb, including LT, GT, LTE, GTE, EQ, and NEQ for values and strings. Comparison functions compare values and assert the equality of a statement. ## `LT` If both arguments are numbers, returns true if the first provided value is less than the second. If both arguments are strings, returns true if the first provided value falls lexicographically before the second. Always false if either argument is empty, or if the types of the columns do not match. ```ruby theme={} # Infix operator usage: left < right # Examples $roundtrip_us < 500 $mysql_read_ms < $mysql_write_ms # Function usage: LT(left, right) # Examples LT($roundtrip_us, 500) LT($mysql_read_ms, $mysql_write_ms) ``` ## `LTE` If both arguments are numbers, returns true if the first provided value is less than or equal to the second. If both arguments are strings, returns true if the first provided value is the same as, or falls lexicographically before, the second. Always false if either argument is empty, or if the types of the columns do not match. ```ruby theme={} # Infix operator usage: left <= right # Examples $roundtrip_ms <= 0.5 $get_schema_ms <= $persist_schema_ms # Function usage: LTE(left, right) # Examples LTE($roundtrip_ms, 0.5) LTE($get_schema_ms, $persist_schema_ms) ``` ## `GT` If both arguments are numbers, returns true if the first provided value is greater than the second. If both arguments are strings, returns true if the first provided value falls lexicographically after the second. Always false if either argument is empty, or if the types of the columns do not match. ```ruby theme={} # Infix operator usage: left > right # Examples $payload_size_kb > 300 $num_invalid_columns > $num_valid_columns # Function usage: GT(left, right) # Examples GT($payload_size_kb, 300) GT($num_invalid_columns, $num_valid_columns) ``` ## `GTE` If both arguments are numbers, returns true if the first provided value is greater than or equal to the second. If both arguments are strings, returns true if the first provided value is the same as, or falls lexicographically after, the second. Always false if either argument is empty, or if the types of the columns do not match. ```ruby theme={} # Infix operator usage: left >= right # Examples $payload_size_mb >= 0.3 $memory_inuse >= ($max_memory_process * 0.75) # Function usage: GTE(left, right) # Examples GTE($payload_size_mb, 0.3) GTE($memory_inuse, MUL($max_memory_process, 0.75)) ``` ## `EQUALS` Returns true if the two provided arguments are equal. Arguments of different types, such as the integer `200` and the string `"200"`, are not considered equal. ```ruby theme={} # Infix operator usage: left = right # Examples $remote_addr = "216.3.123.12" $gzipped = true $oversize_num_columns = 0 # Function usage: EQUALS(arg1, arg2) # Examples EQUALS($remote_addr, "216.3.123.12") EQUALS($gzipped, true) EQUALS($oversize_num_columns, 0) ``` ### `NOT(EQUALS)` `NOT()` with `EQUALS()` as an argument returns true if the two provided arguments are not equal. This is equivalent to the not equal operator (`!=`). ```ruby theme={} # These are equivalent $method != "POST" !EQUALS($method, "POST") NOT(EQUALS($method, "POST")) ``` # Conditional Functions in Calculated Fields Source: https://docs.honeycomb.io/reference/calculated-field-expression/conditional Conditional functions available for calculated field formulas in Honeycomb, including IF, ELSE, and related boolean expression operators. Conditional functions evaluate a condition that is applied to boolean expressions. ## `IF` The `IF` statement takes two or more arguments. Every pair of arguments is evaluated as a condition; the final argument is the default: `IF( condition, then-val [, condition2, then-val2]... [, else-val])`. * If `condition` evaluates to true, evaluates to `then-val`. * If `condition2` is specified, then if it is true, evaluates to `then-val2`. * If `else-val` is not specified, evaluates to null. * Otherwise evaluates to `else-val`. All non-zero numbers, as well as the string `true`, evaluate to `true`. ```ruby theme={} # Usage: `IF( condition, then-val [, condition2, then-val2]... [, else-val])` # Examples IF(CONTAINS($team_name, "acme"), "important-customer", "everyone else") IF(GTE($http_status, 400), 1, 0) IF(GTE($duration_ms, 500), "slow") # The multiple-value form can be used as a type of case statement, # but SWITCH is more efficient if the same expression is being tested for strict equality. IF(EQUALS($path,"/login"),"login", CONTAINS($path,"/browse/"),"browsing", "other" ) ``` Note that the multi-argument `IF` is equivalent to nested `IF` statements: ```ruby theme={} # nested IF IF(condition, value, IF(condition2, value2, IF(condition3, value3, default) ) ) # equivalent with multi-condition IF IF(condition, value, condition2, value2, condition3, value3, default) ``` ## `SWITCH` The `SWITCH` statement takes three or more arguments. The first argument is the value to test the cases against. Every pair of arguments is evaluated as a case and the value to return. If there is an unpaired final argument, it will be returned as the default if none of the cases match. If no default value exists, then null will be returned. `SWITCH( expression, case1, val1[, case2, val2]... [, default-val])`. * If `expression` equals `case1`, evaluates to `val1`. * If `case2` is specified and equals `expression`, evaluates to `val2`. * If `default-val` is not specified, evaluates to null. * Otherwise evaluates to `default-val`. The rules for [`EQUALS`](/reference/calculated-field-expression/comparison/#equals) apply for testing cases. ```ruby theme={} # Usage: `SWITCH( expression, case1, val1[, case2, val2]... [, default-val])` # Examples SWITCH(REG_VALUE($service.name, "^([a-z]+)-shard-"), "alpha", "blue-owls", "beta", "violet-octopi", "delta", "violet-octopi", "gamma", "orange", "platform" ) ``` ## `COALESCE` Evaluates to the first non-empty argument. This is useful for similar fields where fallback values are preferable to null. ```ruby theme={} # Usage: COALESCE(arg1, arg2, ...) # Examples COALESCE($full_name, $email) COALESCE($container_id, $hostname, $availability_zone, "unknown") COALESCE($service.name, $service_name, "unknown") # This can be used to approximate a case statement. For some cases, this is easier to write than the multi-factor IF statement. COALESCE( IF(GTE($duration_ms, 200), "slow"), IF(GTE($status, 500), $error_message), IF(CONTAINS($team, "acme"), "high priority"), "normal" ) ``` # Calculated Field Example Formulas Source: https://docs.honeycomb.io/reference/calculated-field-expression/example-formulas Example calculated field formulas covering common use cases in Honeycomb, to use as a starting point when building your own. You can use these example formulas for calculated fields, otherwise known as Derived Columns, as inspiration when [creating your own calculated fields](/configure/environments/calculated-fields/). The specific attributes in each example may or may not exist in your data and environment. Each example contains: * the formula to add when you [create your Calculated Field](/configure/datasets/calculated-fields/#creating-calculated-fields) * an example query that used your Calculated Field when [building a query](/investigate/query/build/); most of these use three clauses Most of the example queries use `SELECT`, `WHERE`, and `GROUP BY` clauses, which are located at the top of the Query Builder display. * `SELECT`: Performs a calculation and displays a corresponding graph over time. Most `SELECT` queries return a line graph while the `HEATMAP` visualization shows the distribution of data over time * `WHERE`: Filters based on attribute parameter(s) * `GROUP BY`: Groups fields by attribute parameter(s) ## Determine the percentage of successful requests Determine the percentage of successful requests by using a Calculated Field. [Create a Calculated Field](/configure/datasets/calculated-fields/#creating-calculated-fields) and enter the following function in the Calculated Field Editor: ```ruby theme={} # Count a successful result as 1 and an error as 0. # Then multiply by 100 to get a percentage IF($http.status_code = 200, 1, 0) * 100 # Function equivalent MUL( IF(EQUALS($http.status_code, 200), 1, 0), 100 ) ``` To get the success rate, use the Calculated Field name in a query, such as `success-rate-calculated-field`: | SELECT | | ---------------------------------- | | AVG(success-rate-calculated-field) | ## Find failures in sequential events Monitor the health of a pipeline-style process by using a Calculated Field that tells the number of requests that failed to complete. [Create a Calculated Field](/configure/datasets/calculated-fields/#creating-calculated-fields) and enter the following function in the Calculated Field Editor: ```ruby theme={} # Assign pipeline-step-1 events a value of 1 and the pipeline-step-2 events a value of -1. IF( $name = "pipeline-step-1", 1, $name = "pipeline-step-2", -1, 0 ) # Function equivalent IF( EQUALS($name, "pipeline-step-1"), 1, EQUALS($name, "pipeline-step-2"), -1, 0 ) ``` To determine the volume difference between events from the two pipeline steps, use the Calculated Field name in a query, such as `failed-pipeline-step-calculated-field`: | SELECT | | ------------------------------------------ | | SUM(failed-pipeline-step-calculated-field) | If there are an equal number of `pipeline-step-1` events as `pipeline-step-2` events, then the `SUM` will be zero. When there are fewer `pipeline-step-2` events than `pipeline-step-1` events, then the `SUM` will be a positive integer. ## Find traces with missing root spans Find traces with missing root spans by [creating a Calculated Field](/configure/datasets/calculated-fields/#creating-calculated-fields) and entering the following function in the Calculated Field Editor: ```ruby theme={} # If trace.parent_id exists, then assign a value of 0, else assign a value of 1 IF( EXISTS($trace.parent_id), 0, 1 ) ``` To find traces with a missing root span, use the Calculated Field name in a query, such as `check-trace-parent-calculated-field`: | SELECT | GROUP BY | HAVING | | ---------------------------------------- | --------------- | -------------------------------------------- | | SUM(check-trace-parent-calculated-field) | trace.trace\_id | SUM(check-trace-parent-calculated-field) = 0 | The sum will return at least `1` if you have a root span and `0` if you have no root span. ## Use regular expressions to select Kubernetes deployment metrics To select Kubernetes deployment metrics, [create a Calculated Field](/configure/datasets/calculated-fields/#creating-calculated-fields) and enter the following function in the Calculated Field Editor: ```ruby theme={} REG_VALUE($k8s.pod.name, `(.*)-.*-.*`) ``` To select Kubernetes deployment metrics, use the Calculated Field name in a query, such as `k8s.deploy.name.calculated.field`: | SELECT | WHERE | GROUP BY | | --------------------------- | ---------------------------------------- | -------------------------------- | | `MAX(metrics.memory.usage)` | k8s.namespace.name = your-namespace-name | k8s.deploy.name.calculated.field | Any other [metric operations](/investigate/query/examples-metrics/#common-select-operations) can be used instead of **SELECT** `MAX()` in this query example. ## Compare window sizes to screen sizes For front end developers, compare window sizes to screen sizes using a Calculated Field. [Create a Calculated Field](/configure/datasets/calculated-fields/#creating-calculated-fields) and enter the following function in the Calculated Field Editor: ```ruby theme={} ($window_height * $window_width) / ($screen_height * $screen_width) # Function equivalent DIV( MUL( $window_height, $window_width ), MUL( $screen_height, $screen_width ) ) ``` To compare window sizes to screen sizes, use the Calculated Field name in a query, such as `screen-used-calculated-field`: | SELECT | WHERE | | --------------------------------------- | ---------------------------------- | | `HEATMAP(screen-used-calculated-field)` | `screen-used-calculated-field < 1` | After running the query, if most of the data in the heatmap clusters in a band closer to the top of the display, then most users are already using the majority of their screens. ## Group incoming data by content size Group, or bucket, incoming data by content size using a Calculated Field. It is helpful to know that the [IF Operator](/reference/calculated-field-expression/operators-functions/conditional/) works very similar to a `switch` or `case` statement in other languages, allowing you to provide multiple outputs based on many separate conditions. [Create a Calculated Field](/configure/datasets/calculated-fields/#creating-calculated-fields) and enter the following function in the Calculated Field Editor: ```ruby theme={} IF( $headers.Content-Length > 1000, "0:bytes", $headers.Content-Length > 1000000, "1:kbytes", $headers.Content-Length > 1000000000, "2:mbytes", "3:huge" ) # Function equivalent IF( LT($headers.Content-Length, 1000), "0:bytes", LT($headers.Content-Length, 1000000), "1:kbytes", LT($headers.Content-Length, 1000000000), "2:mbytes", "3:huge" ) ``` To group incoming data by content size, use the Calculated Field name in a query, such as `content-length-bucket-calculated-field`: | SELECT | GROUP BY | | ------- | -------------------------------------- | | `COUNT` | content-length-bucket-calculated-field | This query can help answer questions about whether larger file uploads fail more often, and give a general idea of the distribution of file sizes across uploads. ## Derive browser version from the user-agent header Derive the browser version from the user-agent header by using a Calculated Field. [Create a Calculated Field](/configure/datasets/calculated-fields/#creating-calculated-fields) and enter the following function in the Calculated Field Editor: ```ruby theme={} IF( REG_MATCH($http.user_agent, `Firefox/[0-9\.]+`), REG_VALUE($http.user_agent, `Firefox/[0-9\.]+`), REG_MATCH($http.user_agent, `Chrome/[0-9\.]+`), REG_VALUE($http.user_agent, `Chrome/[0-9\.]+`), REG_MATCH($http.user_agent, `Safari/[0-9\.]+`), REG_VALUE($http.user_agent, `Safari/[0-9\.]+`), REG_MATCH($http.user_agent, `Edg/[0-9\.]+`), REG_VALUE($http.user_agent, `Edg/[0-9\.]+`), REG_MATCH($http.user_agent, `Trident\/4.0`), "IE 8", REG_MATCH($http.user_agent, `Trident\/5.0`), "IE 9", REG_MATCH($http.user_agent, `Trident\/6.0`), "IE 10", REG_MATCH($http.user_agent, `Trident\/7.0`), "IE 11", "Unknown" ) ``` To derive the browser versions in use, use the Calculated Field name in a query, such as `browser-version-calculated-field`: | SELECT | GROUP BY | | ------- | -------------------------------- | | `COUNT` | browser-version-calculated-field | This query can help you answer questions about whether requests from particular browser types are failing more frequently. ## Derive browser name from the user-agent header Derive the browser name from the user-agent header by using a Calculated Field. [Create a Calculated Field](/configure/datasets/calculated-fields/#creating-calculated-fields) and enter the following function in the Calculated Field Editor: ```ruby theme={} IF( REG_MATCH($http.user_agent, "Gecko/"), "Firefox", OR( REG_MATCH($http.user_agent, "Chrome/"), REG_MATCH($http.user_agent, "Chromium/") ), "Chrome", REG_MATCH($http.user_agent, "AppleWebKit/"), "Webkit", REG_MATCH($http.user_agent, "Trident/"), "IE", REG_MATCH($http.user_agent, "Edge/"), "Edge", "Unknown" ) ``` To derive the browser names in use, use the Calculated Field name in a query, such as `browser-name-calculated-field`: | SELECT | GROUP BY | | ------- | ----------------------------- | | `COUNT` | browser-name-calculated-field | This query can help you answer questions about whether requests from particular browser types are failing more frequently. ## Derive browser operating system from the user-agent header Derive the browser operating system (OS) from the user-agent header by using a Calculated Field. [Create a Calculated Field](/configure/datasets/calculated-fields/#creating-calculated-fields) and enter the following function in the Calculated Field Editor: ```ruby theme={} IF( CONTAINS($http.user_agent, "Macintosh"), "Macintosh", CONTAINS($http.user_agent, "Windows"), "Windows", CONTAINS($http.user_agent, "Android"), "Android", CONTAINS($http.user_agent, "CrOS"), "ChromeOS", REG_MATCH($http.user_agent, "iPhone|iPad"), "iOS", CONTAINS($http.user_agent, "Linux"),"Linux", "Unknown" ) ``` To derive the browser operating systems in use, use the Calculated Field name in a query, such as `browser-os-calculated-field`: | SELECT | GROUP BY | | ------- | --------------------------- | | `COUNT` | browser-os-calculated-field | This query can help you answer questions about whether requests from particular browser types are failing more frequently. ## Derive browser architecture from user-agent header Derive browser architecture from the user-agent header by using a Calculated Field. [Create a Calculated Field](/configure/datasets/calculated-fields/#creating-calculated-fields) and enter the following function in the Calculated Field Editor: ```ruby theme={} IF( REG_MATCH($http.user_agent, "x86|Intel"), "Intel", REG_MATCH($http.user_agent, "aarch64|armv|Android"), "ARM", "Unknown" ) ``` This Calculated Field example assumes that Android has Arm architecture. To derive the browser architecture in use, use the Calculated Field name in a query, such as `browser-architecture-calculated-field`: | SELECT | GROUP BY | | ------- | ------------------------------------- | | `COUNT` | browser-architecture-calculated-field | This query can help you answer questions about whether requests from particular browser types are failing more frequently. # Logical Functions in Calculated Fields Source: https://docs.honeycomb.io/reference/calculated-field-expression/logical Logical and boolean functions available for calculated field formulas in Honeycomb, including AND, OR, NOT, and EXISTS. Logical functions define logical relationships between values. ## `AND` Takes a variable number of arguments and returns true if all arguments are truthy. ```ruby theme={} # Infix operator usage: $a AND $b # Examples $roundtrip_ms >= 100 AND $method = "POST" !IN($method, "GET", "DELETE") AND EXISTS($batch) # Function usage: AND(arg1, arg2, ...) # Examples AND(GTE($roundtrip_ms, 100), EQUALS($method, "POST")) AND(NOT(IN($method, "GET", "DELETE")), EXISTS($batch)) AND(EQUALS($api_version, "v3"), OR(LT($request_ms, 30), GT($request_ms, 300))) ``` ## `OR` Takes a variable number of arguments and returns true if any arguments are truthy. ```ruby theme={} # Infix operator usage: $a OR $b # Examples $company = "acme" OR $priority >= 5 $mysql_latency_ms >= 20 OR ($s3_latency_ms >= 100 AND $method = "GET") # Function usage: OR(arg1, arg2, ...) # Examples OR(EQUALS($company, "acme"), GTE($priority, 5)) OR(GTE($mysql_latency_ms, 20), AND(GTE($s3_latency_ms, 100), EQUALS($method, "GET"))) ``` ## `NOT` Evaluates the provided argument to a boolean value, and then inverts that value. ```ruby theme={} # Infix operator usage: !(arg1) # Examples !EXISTS($batch) !IN($build_id, "175", "176") !IN($company, "acme", "globex", "soylent") # Usage: NOT(arg1) # Examples NOT(EXISTS($batch)) NOT(IN($build_id, "175", "176")) NOT(IN($company, "acme", "globex", "soylent")) ``` ## `IN` Returns true if the first provided argument is equal to any of the subsequent arguments. `IN` can be thought of as a more compact form of a series of `OR` equality checks. ```ruby theme={} # Usage: IN(arg1, compare1, ...) # Examples IN($method, "DELETE", "POST", "PUT") IN($build_id, "9051", "9052") IN($num_invalid_payloads, 0, 1, -1) ``` ## `EXISTS` Returns true when the supplied argument has a defined value. Returns false when the supplied argument does not have a defined value. ```ruby theme={} # Usage: EXISTS(arg1) # Examples EXISTS($batch_size) EXISTS($team_name) EXISTS($json_serialization_ms) ``` # Math Functions in Calculated Fields Source: https://docs.honeycomb.io/reference/calculated-field-expression/math Math functions available for calculated field formulas in Honeycomb, including SUM, AVG, CEIL, FLOOR, and arithmetic operators. Math functions perform common mathematical operations. ## `SUM` Evaluates to the sum of all numeric arguments. Strings are parsed into numbers if possible, unparseable strings or other values evaluate to zero. ```ruby theme={} # Infix operator usage: arg1 + arg2 # Examples $serialize_ms + $scan_ms + $publish_ms 1.0 + 5 + "2.3" # Function usage: SUM(arg1, arg2, ...) # Examples SUM($serialize_ms, $scan_ms, $publish_ms) SUM(1.0, 5, "2.3") ``` ## `SUB` Evaluates to the first argument subtracted by the second, or `arg1 - arg2`. Strings are parsed into numbers if possible, unparseable strings or other values evaluate to zero. ```ruby theme={} # Infix operator usage: arg1 - arg2 # Examples $serialization_ms - 100 $total_ms - ($local_ms + $merge_ms + $serialize_ms) # Function usage: SUB(arg1, arg2) # Examples SUB($serialization_ms, 100) SUB($total_ms, SUM($local_ms, $merge_ms, $serialize_ms)) ``` ## `MUL` Multiplies all numeric arguments and returns the product. Strings are parsed into numbers if possible, unparseable strings or other values evaluate to zero. ```ruby theme={} # Infix operator usage: arg1 * arg2 # Examples $count * $time_per_item 100 * ($json_decode_ms / $total_ms) # Function usage: MUL(arg1, arg2, ...) # Examples MUL($count, $time_per_item) MUL(100, DIV($json_decode_ms, $total_ms)) ``` ## `DIV` Divides the first argument by the second, or `arg1 / arg2`. Strings are parsed into numbers if possible, unparseable strings or other values evaluate to zero. A division by zero evaluates to null. ```ruby theme={} # Infix operator usage: arg1 / arg2 # Examples $io_bytes_read / 1024 $total_ms / $rows_examined $json_parse_time_ms / $total_request_time_ms # Function usage: DIV(arg1, arg2) # Examples DIV($io_bytes_read, 1024) DIV($total_ms, $rows_examined) DIV($json_parse_time_ms, $total_request_time_ms) ``` ## `MOD` Computes the remainder of `arg1 / arg2`. Strings are parsed into floats if possible, unparseable strings or other values evaluate to zero. Evaluates to null if `arg2` is zero. ```ruby theme={} # Infix operator usage: arg1 % arg2 # Examples 15 % 12 # 3 5.5 % 4 # 1.5 6 % 5.5 # 0.5 # Function usage: MOD(arg1, arg2) # Examples MOD(15, 12) # 3 MOD(5.5, 4) # 1.5 MOD(6, 5.5) # 0.5 ``` ## `MIN` Evaluates to the smallest argument of the same type as the first non-empty argument. "Smallest" means the smaller, if numeric, or lexicographically first, if a string. ```ruby theme={} # Usage: MIN(arg1, arg2, ...) # Examples MIN($memory_inuse_local, $memory_inuse_merge, $memory_inuse_fetch) ``` ## `MAX` Evaluates to the largest argument of the same type as the first non-empty argument. "Largest" means the larger, if numeric, or lexicographically last, if string. ```ruby theme={} # Usage: MAX(arg1, arg2, ...) # Examples MAX($mysql_latency_ms, $redis_latency_ms) MAX(1, DIV($total_volume, $count)) ``` ## `LOG10` Computes the base-10 logarithm of the argument. Strings are parsed into numbers if possible. Unparseable strings, and arguments less than or equal to 0, evaluate to null. ```ruby theme={} # Usage: LOG10(arg1) # Examples LOG10($duration_ms) ``` ## `BUCKET` Computes discrete (categorical) bins, or buckets, to transform continuous fields into categorical ones. This can be useful to group data into groups. The syntax is `BUCKET( $column, size, [min, [max]])`. The function returns `size`-sized buckets from `min` to `max`. For example, `BUCKET( $column, 10, 0, 30)` will return groups named `< 0`, `0 - 10`, `10 - 20`, `20 - 30`, and `> 30`. If only the `min` is specified, then the function will run without an upper bound; if neither a `min` nor `max` is specified, then the function will run without either bound, starting from a bucket `0 - size`. In all versions, points on the boundary between two bins will fall into the lower bin. The size, min, and max may not be columns. If the column is not a float value, the function returns null. ```ruby theme={} # Usage: BUCKET( $column, size, [min, [max]]) # Examples BUCKET($duration_ms, 500, 0, 3000) # size, min and max BUCKET($current_budget, 10, -5) # min only BUCKET($num_users, 10) # size only ``` # String Functions in Calculated Fields Source: https://docs.honeycomb.io/reference/calculated-field-expression/string String functions available for calculated field formulas in Honeycomb, including CONCAT, LOWERCASE, LENGTH, MATCH, and CONTAINS. String functions manipulate and perform operations on strings. ## `CONCAT` Concatenates string representations of all arguments into a single string result. Non-string arguments are converted to strings, empty arguments are ignored. ```ruby theme={} # Usage: CONCAT(arg1, arg2, ...) # Examples CONCAT($api_version, $sdk) IF($is_batch, CONCAT($url, "-batch"), $url) ``` ## `TO_LOWER` Converts an input string to be all lower-case. ```ruby theme={} # Usage: TO_LOWER(string)` # Examples TO_LOWER($service.name) IF(CONTAINS(TO_LOWER(app.user.name), "bob"), "bob!", "not bob!") ``` ## `STARTS_WITH` Returns true if the first argument starts with the second argument. Returns false if either argument is not a string. ```ruby theme={} # Usage: STARTS_WITH(string, prefix) # Examples STARTS_WITH($url, "https") STARTS_WITH($user_agent, "ELB-") ``` ## `ENDS_WITH` Returns true if the first argument ends with the second argument. Returns false if either argument is not a string. ```ruby theme={} # Usage: ENDS_WITH(string, suffix) # Examples ENDS_WITH($filename, ".json") ``` ## `CONTAINS` Returns true if the first argument contains the second argument. Returns false if either argument is not a string. ```ruby theme={} # Usage: CONTAINS(string, substr)` # Examples CONTAINS($email, "@honeycomb.io") CONTAINS($header_accept_encoding, "gzip") IF(CONTAINS($url, "/v1/"), "api_v1", "api_v2") ``` ## `REG_MATCH` Returns true if the first argument matches the second argument, which must be a defined regular expression. Returns false if the first argument is not a string or is empty. The provided `regex` must be a string literal containing a valid regular expression. Golang regex syntax can be [tested here](https://regex101.com/). If your regular expression contains character classes such as `\s`, `\d` or `\w`, enclose the regular expression in `` `backticks` `` so that it is treated as a raw string literal. ```ruby theme={} # Usage: REG_MATCH(string, regex) # Examples REG_MATCH($error_msg, `^[a-z]+\[[0-9]+\]$`) REG_MATCH($referrer, `[\w-_]+\.(s3\.)?amazonaws.com`) ``` ## `REG_VALUE` Evaluates to the **first** regex submatch found in the first argument. Evaluates to an empty value if the first argument contains no matches or is not a string. The provided `regex` must be a string literal containing a valid regular expression. Golang regex syntax can be [tested here](https://regex101.com/). If your regular expression contains character classes such as `\s`, `\d` or `\w`, enclose the regular expression in `` `backticks` `` so that it is treated as a raw string literal. ```ruby theme={} # Usage: REG_VALUE(string, regex) # Examples REG_VALUE($user_agent, `Chrome/[\d.]+`) REG_VALUE($source, `^(ui-\d+|log|app-\d+)`) ``` The first example above yields a string like `Chrome/1.2.3` and the second could be any one of `ui-123`, `log`, or `app-456`. `REG_VALUE` is most effective when combined with other functions. As an example, the `honeytail` agent sets its `User-Agent` header to a string like `libhoney-go/1.3.0 honeytail/1.378 (nginx)`, but there are also `User-Agent`s like `"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36...`. In order to extract only the name of the parser used and not get caught up with other things in parentheses (such as the `Macintosh...` bit), we use this as a calculated field: ```ruby theme={} IF(CONTAINS($user_agent, "honeytail"), REG_VALUE($user_agent, `\([a-z]+\)`), null) ``` This results in fields that contain `(nginx)`, `(mysql)`, and so on. Combining `CONTAINS` or `REG_MATCH` with `REG_VALUE` is a way to limit the total number of strings available to the match and more effectively grab only the values you are expecting. ## `REG_COUNT` Returns the number of **non-overlapping successive** matches yielded by the provided regex. Returns `0` if the first argument contains no matches or is not a string. The provided `regex` must be a string literal containing a valid regular expression. Golang regex syntax can be [tested here](https://regex101.com/). If your regular expression contains character classes such as `\s`, `\d` or `\w`, enclose the regular expression in `` `backticks ` ``so that it is treated as a raw string literal. ```ruby theme={} # Usage: REG_COUNT(string, regex) # Examples REG_COUNT($sql, `JOIN`) REG_COUNT($ip, `19.`) ``` ## `LENGTH` Returns the length of a string in either bytes, or user-perceived characters. The second argument must be either "bytes" or "chars". Returns `0` if the first argument is not a string, or if the first argument is not valid utf8 when second argument is "chars". ```ruby theme={} # Usage: LENGTH(string[, "bytes" | "chars"]) # Examples LENGTH($hostname, "bytes") # returns the number of bytes that make up the string. LENGTH($hostname, "chars") # returns the number of user-perceived characters that make up the string. ``` "User-perceived characters" are also known as ["grapheme clusters"](https://unicode.org/reports/tr29/) and represent a basic unit of a writing system for a language. To show the difference between the two units, refer to the single character 🏳️‍🌈 (unicode rainbow flag) in the example below: ```ruby theme={} LENGTH("🏳️‍🌈", "bytes") # == 14 LENGTH("🏳️‍🌈", "chars") # == 1 ``` # Calculated Field Syntax Source: https://docs.honeycomb.io/reference/calculated-field-expression/syntax Syntax rules, operators, and supported value types for calculated field formulas in Honeycomb Datasets and Environments. An expression performs functions, and mathematical and/or logical operations on other primitives and field's values to return a result; similar to expressions in a spreadsheet. You can use various functions in Calculated Field formulas. Functions operate within the context of a single event, meaning that each function takes field values from an event and produces a new Calculated Field attached to that event. ## Field names Reference fields, or columns, by prefixing their name with a dollar sign `$`. ```c theme={} $durationMs ``` Field names that start with a number or contain spaces must be enclosed in double quotes `"`. ```c theme={} $"1stToken" $"Context Key Length" ``` ## Literals ```ruby theme={} "a string" # string `raw string` # raw string 10 # integer -3 # negative integer 12.02 # float -4.82 # negative float 4e+2 # scientific E notation 4e-2 # scientific E notation true # boolean false # boolean null # null ``` ### Strings String literals are enclosed in double quotes (`"a string"`) and support interpretation. Special characters are escaped with a backslash `\`. Within the quotes, any character may appear except newline (`"\n"`) and unescaped double quote (`"\\"`) which require the use of the backslash character. ### Raw strings Raw string literals are enclosed in single back ticks (`` `a raw string` ``). Within the quotes, any character may appear except a back quote. This is useful for expression of text that use the backslash character. For example, file paths and regular expressions. ### Integers and floating point numbers Positive or negative whole numbers or floating point numbers. [E notation style](https://en.wikipedia.org/wiki/Scientific_notation#E_notation) numbers are also supported. ```ruby theme={} 10 # integer -3 # negative integer 12.02 # float -4.82 # negative float 1.5e2 # scientific E notation 1.5e+2 # scientific E notation 1.5e-2 # scientific E notation ``` ### Booleans A truthy value represented with `true` and false `false`. ### Null An empty, missing value represented with `null`. ## Operators Calculated fields support infix arithmetic, logical, and comparison operators. Add spaces around infix operators, otherwise your expression may not evaluate how you expect. For example: * `$column+5` returns the value of a field named `column+5`. * `$column + 5` returns the sum of five and the `column` field's value. ### Arithmetic operators ```txt theme={} + sum - subtraction * multiplication / division % modulo ``` Sum, subtraction, multiplication, division, and modulo infix operators are supported. | Operator syntax | Equivalent function | | --------------- | ------------------- | | `$a + $b` | `SUM($a, $b)` | | `$a - $b` | `SUB($a, $b)` | | `$a * $b` | `MUL($a, $b)` | | `$a / $b` | `DIV($a, $b)` | | `$a % $b` | `MOD($a, $b)` | ### Comparison operators ```txt theme={} = equal != not equal < less than <= less than or equal > greater >= greater than or equal ``` | Operator syntax | Equivalent function | | --------------- | --------------------- | | `$a = $b` | `EQUALS($a, $b)` | | `$a != $b` | `NOT(EQUALS($a, $b))` | | `$a < $b` | `LT($a, $b)` | | `$a <= $b` | `LTE($a, $b)` | | `$a > $b` | `GT($a, $b)` | | `$a >= $b` | `GTE($a, $b)` | ### Logical operators ```txt theme={} AND conditional AND OR conditional OR ! NOT ``` Infix operators for conditional AND, conditional OR, and logical NOT. | Operator syntax | Equivalent function | | -------------------- | ------------------- | | `$a AND $b` | `AND($a, $b)` | | `$a OR $b` | `OR($a, $b)` | | `!$a` (also `!($a)`) | `NOT($a)` | ## Functions A function's name is all-capitalized. Function arguments (if any) are enclosed in parenthesis. Field names, literal values, and other functions are valid function arguments. ```ruby theme={} SUM(1.0, 5, "2.3") MUL(100, DIV($json_decode_ms, $total_ms)) ``` # Time Functions in Calculated Fields Source: https://docs.honeycomb.io/reference/calculated-field-expression/time Time functions available for calculated field formulas in Honeycomb, including UNIX_TIMESTAMP, DATE_STRING, and duration helpers. Time functions calculate and manipulate time data. ## `UNIX_TIMESTAMP` Converts a date string in RFC3339 format (for example, `2017-07-20T11:22:44.888Z`) to a Unix timestamp (`1500549764.888`). This is useful for comparing two timestamps in an event; for example, to calculate a duration from a start and an end timestamp. ```ruby theme={} # Usage: UNIX_TIMESTAMP(string) # Examples UNIX_TIMESTAMP($timestamp) ``` ## `EVENT_TIMESTAMP` Returns the Unix timestamp, also known as the Epoch timestamp, of the current event as a float (`1500549764.888`, for example). This is useful for comparing two timestamps in an event; for example, to calculate a duration from a start and an end timestamp. This function takes no arguments. ```ruby theme={} # Usage: EVENT_TIMESTAMP() # Examples EVENT_TIMESTAMP() ``` ## `INGEST_TIMESTAMP` Returns the Unix timestamp, also known as the Epoch timestamp, indicating when Honeycomb's servers received the current event, as a float (`1500549764.888`, for example). This is useful for debugging event latency by comparing the event timestamp to the ingestion time. This function takes no arguments. ```ruby theme={} # Usage: INGEST_TIMESTAMP() # Examples # Event latency, in seconds. May be negative for future-dated events. SUB(INGEST_TIMESTAMP(),EVENT_TIMESTAMP()) # Event latency, in minutes. May be negative for future-dated events. DIV(SUB(INGEST_TIMESTAMP(),EVENT_TIMESTAMP()),60) # Event latency, accounting for span duration. Assumes `duration_ms` is in milliseconds. SUB(INGEST_TIMESTAMP(),SUM(EVENT_TIMESTAMP(),DIV($duration_ms,1000))) ``` ## `FORMAT_TIME` Formats a Unix timestamp, also known as an Epoch timestamp, as a string. The first argument is a format specifier string compatible with [POSIX strftime](https://pubs.opengroup.org/onlinepubs/9699919799/functions/strftime.html), and the second argument is the numeric timestamp. Does not support not-UTC timezones or locale-modified specifiers. Also note this formatting is more expensive than other calculated field functions and may slow down queries, especially when using a complex format. ```ruby theme={} # Usage: FORMAT_TIME(format, timestamp) # Examples FORMAT_TIME("%A", 1626810584) # Tuesday FORMAT_TIME("%FT%TZ", 1626810584) # 2021-07-20T19:49:44Z ``` # Calculated Field Reference Source: https://docs.honeycomb.io/reference/calculated-field-reference # UI Reference Source: https://docs.honeycomb.io/reference/honeycomb-ui A screen-by-screen reference for the Honeycomb UI, organized to match the left navigation menu. Find details on every page, panel, and setting. The menu below reflects the left navigation menu in the Honeycomb UI. Use our User Interface (UI) Reference to navigate through Honeycomb and its capabilities by screen. The Environment menu displays your Environment(s) and offers access to Environment Settings. Get a feel for the general health of your system in Honeycomb's Home section. Query allows you to investigate your data with Query Builder. Create custom views of your data with Honeycomb Boards. View and configure notifications for Triggers. View and configure notifications for Service Level Objectives (SLOs). Use Service Map to visualize how traffic flows through your system. Explore your and your Team's query history. View your Environments, your Datasets, and Send Data instructions. Any usage warning state appears on the usage radial. Account relates to personal and team-related settings in Honeycomb. # Account Source: https://docs.honeycomb.io/reference/honeycomb-ui/account Reference for the Account section in the Honeycomb UI, covering both personal settings and settings for team-wide configuration. Account relates to personal and team-related settings in Honeycomb. ## My Account My Account lists your name, associated email, sign-in method, and any team membership(s). ## Switch between light and dark mode Select the theme toggle, located near **Account** in the navigation sidebar, to switch the Honeycomb UI between light and dark mode. The toggle shows your current mode: **Light** or **Dark**. Honeycomb saves your preference and applies it each time you sign in. If you have not set a preference, Honeycomb follows your operating system's color scheme setting. ## Team settings [Team Settings](/reference/honeycomb-ui/account/team-settings/) displays information and allows for team-wide settings management. ## Switch Teams If you belong to multiple teams, select **Switch Teams** to navigate between different teams. ## Changelog **Changelog** activates a pop-up display that shows the three latest Changelog entries, or changes in Honeycomb, with an option to read the Changelog in full. ## Contact Support **Contact Support** activates a pop-up display that offers knowledge base articles and support contact options. ## Documentation **Documentation** sends you to our Honeycomb docs site. ## Log out Select **Log out** to log out of Honeycomb. # Team Settings Source: https://docs.honeycomb.io/reference/honeycomb-ui/account/team-settings Reference for the Team Settings page in the Honeycomb UI, covering team name, API keys, SSO, Query Assistant, and notification preferences. ## Team Details Team Details displays information and allows for team-wide settings management. ### Displayed Information and Settings * Team Name * Environments and API Keys * Default Environment * Single Sign-On * Query Assistant * Email notifications * Allowed domains * Team Members * Invitations #### Allowed Domains Allows Team Owners to control team behavior related to: * **Email domains**: Specify the domains from which Honeycomb will allow users to join their Team. Honeycomb compares the email domain allowlist against user email addresses to determine whether a user may join a team. * **Web domains**: Specify the URLs that Honeycomb will display as external links. Honeycomb compares the web domain allowlist against URLs in the Honeycomb instance to determine whether we should display a URL as an external link rather than as static text in the Query Builder, the Explore Data tab, and the Trace View. Honeycomb notifies all Team Owners any time a change is made to the allowed domains. ##### Valid Domains and URLs Domains and URLs must meet certain criteria to be valid in Honeycomb: * **Valid domains**: * Consist of a series of one or more labels separated by periods, followed by a top-level domain (TLD) (for example, `honeycomb.io`) * Include a TLD that: * Contains only lowercase alphanumeric characters (a-z & 0-9) * Contains at least 2 characters * Include labels that: * Contain only alphanumeric characters (a-z, A-Z, 0-9) and dashes (-) * Contain fewer than 64 characters * Both start and end with an alphanumeric character (a-z, A-Z) * **Valid URLs**: * Can be parsed by [JavaScript's new `URL()` constructor](https://developer.mozilla.org/en-US/docs/Web/API/URL/URL) * Include a protocol of either `http://` or `https://` * Include a hostname that: * Is non-null * Ends in one of the domains listed in the web domain allowlist #### Team Members Displays the profile icon, email, and role of each team member. Possible roles include Owner and Member. To learn more about permissions granted to Team roles, visit [Manage Permissions](/configure/teams/manage-permissions/). ### Tasks * Manage Environments and API Keys * Choose a Default Environment * Enable and Manage SSO * Manage Query Assistant * Manage Email Notifications * Manage Web Domain Allowlist * Manage Email Domain Allowlist * Manage Team Members * Invite New Team Members ## Usage Usage shows details and trends about your team's event volume and throughput, such as events per month (EPM). ### Monthly Events Along with a text summary, a bar indicator compares the number of used events versus the total number of available events for the month. ### Daily Event Traffic, last 60 days The graph shows the daily event traffic over the last 60 days. The last full calendar month is highlighted. The graph key shows types of Accepted Traffic and Rejected Traffic events: * Accepted Traffic * Successful * Burst Protection * Rejected Traffic * Rate Limited * Throttled ### Per-environment Breakdown Fields for each listed Environment include: * Environment Name * Date Created * Date Last Received * Billable Ingested Events (since start of month) * Percent of Traffic (since start of month) ### Per-dataset Breakdown Fields for each listed Dataset include: * Dataset Name * Environment Name * Date Created * Date Last Received * Billable Ingested Events (since start of month) * Percent of Traffic (since start of month) ### Tasks * Activate Usage Mode (by environment) * Activate Usage Mode (by dataset) * Pagination navigation ## Enhanced Reporting Enhanced Reporting is visible if you are a [Honeycomb Enterprise customer](https://www.honeycomb.io/pricing/). Enhanced Reporting shows a variety of information through graphs, charts, and statistics on your Honeycomb Events Ingest, Queries, and more. ## Activity Log [Activity Log](/configure/teams/investigate-activity/) is visible if you are a [Honeycomb Enterprise customer](https://www.honeycomb.io/pricing/). From Team settings, Team Owners can view and download reports of who or what caused a change in specific resource configurations. All team members, regardless of role, can also investigate this activity in the [Activity Log Environment](/configure/teams/investigate-activity/#investigate-team-activity-using-activity-log-datasets). ## Integrations Within **Integrations**, view and configure third-party integrations and webhooks for notification purposes. The **Honeycomb + Slack** and **Honeycomb + GitHub** sections indicate their respective integration's implementation status. In **Trigger and SLO Recipients**, add, remove, or edit team-level integration settings for [Triggers](/notify/triggers/) and [SLOs](/notify/slos/). Read the detailed instructions to set up your team-level [trigger recipients](/notify/#integrations), such as Slack, PagerDuty, Microsoft Teams, and Webhooks. ### Tasks * Authorize Slack * Revoke Slack * Authorize GitHub * Add Integration for notification * Search Trigger Recipients ## Billing Billing shows your current plan, payment settings, and payment history. # Boards Source: https://docs.honeycomb.io/reference/honeycomb-ui/boards Reference for the Boards section of the Honeycomb UI, including Board Listing, Board Detail, Board Templates, and available actions. Create customized workspaces that let you track and organize data for distinct use cases using the **Boards** () section of the Honeycomb UI. To learn more about how you can use Boards, visit [Create Custom Boards](/observe/boards/). Provides a snapshot of all Boards that you can access. Explore Boards for which you have been designated a collaborator or create your own custom workspaces. Provides a focused view of a single Board, including its associated queries and Service Level Objectives (SLOs). Manage an individual workspace, including filtering and controlling the display of queries and SLOs. Provides a snapshot of all Board Templates you can use to create a Board. Access all Board Templates available to you or create your own Board from a template. Provides a focused view of a single Board Template, including its field mappings. View template details and create a new Board from a template. # Board Detail Source: https://docs.honeycomb.io/reference/honeycomb-ui/boards/board-detail Reference for the Board Detail page in the Honeycomb UI, which shows a single Board's queries, SLOs, and options for editing and sharing. Explore an individual workspace using the **Board Detail** page. ## What is the Board Detail page? The **Board Detail** page provides a focused view of a single Board, including its associated queries and Service Level Objectives (SLOs). Use this page to review key information, analyze data, and manage settings for an individual Board. ## Layout and Components The **Board Detail** page is divided into these sections: * **Board Details and Actions**: Displays key information about the Board and provides management options. * **SLOs**: Shows Service Level Objectives (SLOs) added to the Board, along with their current status and compliance metrics. * **Queries**: Shows queries added to the Board, allowing you to explore and customize data analysis. ## Board Details and Actions This section provides key information about the Board and tools to manage it. Use this section to keep your board organized and up to date. ### Board Details This section provides essential information about the Board, including: * **Board name**: Assigned title of the Board. * **Board description**: Brief explanation of the Board's purpose or contents. * **Last edited by and date**: Name of the last person who modified the Board and when. * **Tags**: Key:value pairs assigned to the Board. Valid on Flexible Boards only. ### Board Actions Manage your Board using these options: * **Share** (): Share the Board and manage collaborator access. * **Manage Board settings** (): Access key actions: * **Add query**: Attach a new or existing query. * **Add SLO**: Attach a new or existing Service Level Objective (SLO). * **Duplicate**: Create a copy of the Board. * **Delete board**: Permanently remove the Board. ## SLOs Section If at least one Service Level Objective (SLO) has been added to the Board, then the **SLOs** section appears. The **SLOs** section contains panels, each of which displays compliance and performance metrics for a single SLO. ### SLO Panel Each Service Level Objective (SLO) panel represents an individual SLO. It displays the SLO's details and setting options. #### SLO Details Each Service Level Objective (SLO) panel includes: * **Applicable dataset**: Dataset associated with the SLO, including its name and an associated type icon. Icon options include: | Icon | Description | | ----------- | -------------------------------------------- | | | All datasets in the environment. | | | Single dataset that contains traces. | | | Single dataset that does not contain traces. | * **Status indicator**: Indicator that reflects the SLO's current state. Options include: | Option | Description | | ------ | --------------------------------- | | Normal | Operating within expected limits. | * **Name**: Title of the SLO. * **Time period**: Timeframe over which compliance is measured. * **Performance metrics**: Metric summaries, including: * **Compliance summary**: Represents the overall percentage of requests that meet the defined SLO within the specified time period. Details include: * **Current compliance percentage**: Proportion of requests meeting the defined SLO. * **Compliance target**: Defined goal for compliance. * **Error budget summary**: Represents the remaining allowable proportion of requests that can fail before the SLO is breached. Details include: * **Remaining budget percentage**: Percentage of the error budget that is left. * **Burn rate and time period**: Multiplier and time period indicating the rate at which the budget is being used. #### SLO Settings Use **Manage SLO** settings () to manage your Service Level Objective (SLO). Options include: | Option | Description | | ---------- | ------------------------------ | | Remove SLO | Detach the SLO from the Board. | ## Queries Section Because every Board requires at least one query, this section is always present. Use it to analyze data across different time ranges and customize query result displays. ### Section Controls Adjust how query panels appear across the entire **Queries** section using these controls: * **Time range & granularity**: * **Original time range**: Use the default time setting. * **Relative time ranges**: Dynamically adjust the timeframe based on preset dynamic time ranges (for example, `Last 10 minutes`, `Last 2 hours`, `Last 28 days`). * **Custom time range**: Manually select a specific timeframe. * **Granularity**: Define how detailed the data points are. * **Time navigation**: * **Previous time range**: Step back to an earlier time window. * **Next time range**: Advance to a later time window. * **Column layout**: * **One-Column**: Stack query panels vertically in a single column. * **Multi-Column**: Display panels side by side, adjusting to the width of your browser window. * **Filters**: * **Filter field**: Enter text to filter queries. * **Apply**: Apply selected filters to query results. * **Save Parameters**: Save filters so they persist for all users of the Board. ### Query Panel Each query panel represents an individual query and displays its settings, details, and visualization. #### Query Details Each query includes: * **Applicable dataset**: Dataset from which the query retrieves data, including its name and an associated type icon. Icon options include: | Icon | Description | | ----------- | -------------------------------------------- | | | All datasets in the environment. | | | Single dataset that contains traces. | | | Single dataset that does not contain traces. | * **Name**: Title of the query. * **Description**: Brief summary of what the query does. * **Time range**: Time period covered by the query. * **Granularity**: Level of data aggregation. * **Visualization preview**: * **Graph**: Visual representation of the data. * **Table**: Structured, tabular view of the data. If using a heatmap visualization, the table contains a histogram. #### Query Settings Use **Settings** () to manage your query: * **Display settings**: Choose the display format. Options include: | Option | Description | | --------------------- | ----------------------------------------------- | | Display Graph Only | Show only the visualization. | | Display Graph & Table | Show both the visualization and the data table. | | Display Table Only | Show only the data table. | # Board Listing Source: https://docs.honeycomb.io/reference/honeycomb-ui/boards/board-listing Reference for the Board Listing page in the Honeycomb UI, which shows all accessible Boards with key details and filtering options. Find and explore all of the Boards available to you using the **Board Listing** page. ## What is the Board Listing page? The **Board Listing** page provides a snapshot of all Boards that you can access. Use this page to review key details, explore content, and jump into individual Boards. ## Layout and Components The **Board Listing** page is divided into these sections: * **Controls and Navigation**: Manage Boards and adjust your view. * **Available Boards**: Browse Boards and their details. ### Controls and Navigation This section provides tools for navigating and managing your Boards. Use these controls to stay organized and easily add new content: * **New Board**: Select to create a new Board. * **Navigation bar**: Switch between views. Selecting **Templates** takes you to the Board Template Listing page. * **Pagination controls**: * **Previous**: Step back to an earlier page. * **Next**: Advance to a later page. * **Filters**: * **Filter field**: Enter text to narrow the list of Boards. * **Tags field**: Choose tag(s) to narrow the list of Boards. When used, the listed boards reflects all selected tags. ### Available Boards If you have access to at least one Board, then this section appears. Otherwise, you will be prompted to create a Board. The **Available Boards** section contains panels, each of which represents an individual Board. Each panel displays a Board's details, including: * **Board name**: Title of the Board. * **Creator details**: Avatar and name of the person who created the Board. * **Description**: Brief summary of the Board's purpose or content. * **Content overview**: Count of how many queries and SLOs the Board contains. # Board Template Detail Source: https://docs.honeycomb.io/reference/honeycomb-ui/boards/board-template-detail Reference for the Board Template Detail page in the Honeycomb UI, which provides a focused view of a single Board Template. The template name is located at the top of the page. Each template detail view consists of two tabs - Template Overview and Setup. **Use Template** and an bar display appears in the upper right corner regardless of the selected tab. The bar indicates how many queries within the Board Template is possible to create with the available data in your dataset. ## Template Overview Template overview includes the template description and a preview for each query including: * applicable dataset * query name * query description * a query visualization preview based on your current data ## Setup Setup lists the template description and the components of each query including: * Query name * Query description * Required fields * Availability (based on if the required fields are populated in Honeycomb) This template information can also be found in our [available Board Template documentation](/observe/boards/templates/). ## Tasks * Create a new Board from a Board Template with **Use Template** * Filter Boards within Board Template * Change applicable Time Range # Board Template Listing Source: https://docs.honeycomb.io/reference/honeycomb-ui/boards/board-template-listing Reference for the Board Template Listing page in the Honeycomb UI, which shows all accessible Board Templates with key details. Find and explore all of the Board Templates available to you using the **Board Template Listing** page. ## What is the Board Template Listing page? The **Board Template Listing** page provides a snapshot of all Board Templates that you can access. Use this page to review key details and jump into individual templates to learn more about a specific Board Template or use that template to create a new Board. ## Layout and Components The **Board Template Listing** page is divided into these sections: * **Page Navigation**: Navigate between sections. * **Available Board Templates**: Browse templates and their details. ### Page Navigation The navigation bar in this section lets you navigate between views. Select **Boards** to navigate to the Board Listing page. ### Available Board Templates If you have access to at least one Board Template, then this section appears. The **Available Board Templates** section contains panels, each of which represents an individual Board Template. Each panel displays a Board Template's details, including: * **Template name**: Title of the Board Template. * **Description**: Brief summary of the template's purpose or content. Select a panel to go to the associated template's Board Template Detail page. # Environment Source: https://docs.honeycomb.io/reference/honeycomb-ui/environment Reference for the Environment menu in the Honeycomb UI, including how to switch environments and access environment-level settings. The Environment label below the Honeycomb logo displays the current Environment. When selected, a pop-out menu expands to list your team's existing environments. ## Tasks * Access a different Environment by selecting from the Environment list in the menu * Access [Environment Settings](/reference/honeycomb-ui/environment/environment-settings/) with the Settings icon () * Access [a list of all Environments](/reference/honeycomb-ui/environment/manage-environments/) with Manage Environments # Environment Settings Source: https://docs.honeycomb.io/reference/honeycomb-ui/environment/environment-settings Reference for the Environment Settings page in the Honeycomb UI, covering the Overview, API Keys, and Markers tabs and available options. For Environments, the Settings page consists of the Overview, API Keys, and Markers tabs. Environment Settings are not available if you are a [Honeycomb Classic](/troubleshoot/product-lifecycle/recommended-migrations/#migrate-from-honeycomb-classic-to-honeycomb-environments) user. In the Environment **Overview** tab, view and edit the Environment's description and its associated color. Though an Environment's color is selected at creation, the color can be changed at a later time. Select a new choice from a set range of colors in the Color section. The **Default Scope for New Queries** setting designates a specific dataset or all datasets in an environment to use when starting a New Query. If set to **None**, Honeycomb defaults to using your last viewed dataset. This setting is specific to your user account. The API Keys tab lists the API keys associated with its Environment. You must be a [team owner](/configure/teams/manage-permissions/) to create and edit [API keys](/configure/environments/manage-api-keys/). API Keys are divided into Ingest and Configuration keys. Navigate between the two tabs that reflect the two API Key types. ## Ingest Displayed fields include: * Name * Key ID * Created (user and date) * Details ### Tasks * Search for Ingest API Keys * Create Ingest API Key * Modify Key by selecting **Details** ## Configuration Displayed fields include: * Name * Key ID * Key * Permissions * Created (date) ### Tasks * Search for Configuration API Keys * Copy existing API Key The Schema tab lists the Environment's existing [Calculated Fields](/configure/environments/calculated-fields/) with the ability to search and add new Calculated Fields. The Markers tab lists any Environment-wide Marker and its associated color. Markers display as vertical lines on graphs to mark points in time where interesting things happen, such as deploys or outages. You must be a [team owner](/configure/teams/manage-permissions/) to change the Marker color in the Honeycomb UI. Modify a Environment-wide Marker's color setting by selecting the field under the Color column in the Markers tab. Alternatively, use the [Marker Settings API](/api/marker-settings/). Learn more about [Marker configuration](/configure/environments/manage-markers/). In the **Delete** tab, a [team owner](/configure/teams/manage-permissions/) can delete an environment. You cannot delete the last environment in your team. # Manage Environment Source: https://docs.honeycomb.io/reference/honeycomb-ui/environment/manage-environments Reference for the Manage Environment page in the Honeycomb UI, where you can create, edit, and delete environments for your team. **Environments** displays a list of existing environments in your team. ## Displayed Fields Fields for each listed Environment include: * Name * API Keys * Datasets * Date Created * Data Last Received ### Available Tasks * Search Environments * Create Environment * Sort Fields by selecting field headers * Access Environment Settings by selecting target Environment's name. * View API Keys for Environment * Pagination navigation # History Source: https://docs.honeycomb.io/reference/honeycomb-ui/history Reference for the Honeycomb History page, which shows Recent Queries, Recent Boards, and your team's full query activity across all datasets. Query History allows you to view and search through a timeline of your entire team's activity across all datasets. ## Recent Queries **Recent Queries** shows details about the most recent queries made in the Environment. ## Recent Boards **Recent Boards** lists any [Boards](/observe/boards/) created by you or your teammates. ## My Saved Queries **My Saved Queries** displays a list of your saved queries. ## Team's Saved Queries **Team's Saved Queries** displays a list of your teammates' saved queries. # Home UI Source: https://docs.honeycomb.io/reference/honeycomb-ui/home Reference for the Honeycomb Home page, including the Traces, Logs, and Explore Data views and how each displays your telemetry data. Home displays multiple views: * **Traces**: Populated for tracing datasets. * **Logs**: Populated for log datasets. * **Explore Data**: Populated for all datasets. ## Traces View The **Traces** view contains data visualizations that can help you explore data for tracing datasets. To learn more about what makes a dataset a tracing dataset, visit [Common Issues with Visualization](/troubleshoot/common-issues/visualization/#traces-view-is-empty). ### Visualizations The **Traces** view contains the following data visualizations for the selected time range: * **Total Traces**: Total number of distinct traces or requests that have been sent. * **Total Spans with Errors**: Total number of spans with errors. * **95th Percentile Latency**: 95th-percentile latency of traces or requests that have been sent. ### Recent Traces If you have sent traces into your dataset, the **Recent Traces** view displays the five traces with the most recent root spans for the selected service. ## Logs View The **Logs** view contains data visualizations that can help you explore data for log datasets. To learn more about what makes a dataset a log dataset, visit [Common Issues with Visualization](/troubleshoot/common-issues/visualization/#logs-view-is-empty). ### Visualizations The **Logs** view contains the following data visualizations for the selected time range: * **Total Logs:** Displays the total number of logs received within the selected time range. * **Total Errors:** Displays the total number of logs that contain `error` or `fatal` severities within the selected time range. * **Total Warnings:** Displays the total number of logs with `warn` severities within the selected time range. * **Logs by Severity:** Displays the percent of logs by severity levels within the selected time range. Only standard severities, which include `fatal`, `error`, `warn`, `info`, `trace`, `debug`, and `unspecified`, are distinctly represented. Other, non-standard severities are bucketed into an `Other` group. For more insights using BubbleUp, [parse your severities into Honeycomb standard severities](/send-data/standardize/transform-data/#transform-source-severities-into-honeycomb-standard-severities). * **Log Volume:** Displays a line graph of the log volume within the selected time range. * **Total Events by Severity:** Displays the volume of logs, grouped by severity, within the selected time range. Select the Show table icon () or Show chart icon () to switch between displaying this data as a table or line graph. Non-standard severities are also displayed in this chart. * **Top Messages:** Displays the most frequently occurring log messages within the selected time range. Select the Show table icon () or Show chart icon () to switch between displaying this data as a table or line graph. * **Total Errors by Severity:** Displays the volume of logs where severity is `error` or `fatal`, grouped by severity, for the selected time range. Select the Show table icon () or Show chart icon () to switch between displaying this data as a table or line graph. * **Top Errors:** Displays the most frequently occurring errors within the selected time range. Select the Show table icon () or Show chart icon () to switch between displaying this data as a table or line graph. ## Explore Data The **Explore Data** view lets you [explore all of the events](/investigate/analyze/explore-events/) in the dataset. ## Available Tasks * Navigate between Datasets * Change applicable Time Range * Access Dataset Settings * View displayed data in Query Builder by selecting **Expand** * Select different data fields to Group By * Access Board Templates by selecting **Explore Templates** * Access individual Recent Traces * Access individual Recent Events # Manage Data Source: https://docs.honeycomb.io/reference/honeycomb-ui/manage-data Reference for the Manage Data menu in the Honeycomb UI, which provides access to Datasets, Environments, and the Send Data setup page. The Manage Data menu provides a way to access your Datasets, Environments, and information on how to send data to Honeycomb. View your Honeycomb Datasets, which group your data into collections of related events. View your Honeycomb Environments, which group your data into collections of Datasets and their related events. Access instructions on how to send data to Honeycomb. # Datasets Source: https://docs.honeycomb.io/reference/honeycomb-ui/manage-data/datasets Reference for the Datasets page in the Honeycomb UI, which lists datasets in the current environment. **Datasets** displays a list of existing datasets in the selected environment. ## Displayed Fields Fields for each listed Dataset include: * Name * Date Created * Data Last Received All fields are sortable. ## Tasks * Search datasets * Pagination navigation * Select New Query icon () to go to Query Builder for that dataset * Select name for Dataset's Dataset Settings * Use Send Data button to add new instrumentation # Dataset Settings Source: https://docs.honeycomb.io/reference/honeycomb-ui/manage-data/datasets/dataset-settings Reference for the Dataset Settings page in the Honeycomb UI, covering the Overview, Schema, Definitions, Markers, and Delete tabs. For Datasets, the Settings page consists of Overview, Schema, Definitions, Markers, and Delete tabs. ## Tasks In the Dataset **Overview** tab: * locate and modify the Dataset's Description * set [Default Granularity](#default-granularity) * select and modify [Suggested Queries](#suggested-queries) * locate information about your Events Retention and Usage, Daily Event Traffic, Event Latency History, and Event Rate ## Default Granularity **Default Granularity** affects the display of your Query Results visualizations. Granularity refers to the regular, known interval that data is captured. Queries in this dataset do not drop below the default granularity unless you choose to override it manually when making an individual query. Default Granularity controls the default granularity seen: * after running a query * for charts on the [Home page](/observe/honeycomb-home/) * for Suggested Queries on a blank Query page Choose your Default Granularity from the options in the dropdown list. Best practice is to set the default granularity with the interval at which data enters Honeycomb, which prevents the appearance of spiky graphs. For example, if your data enters the dataset at regular 30 second intervals, we recommend setting a default granularity of 30 seconds. ## Suggested Queries Suggested Queries allow you to select a board to provide suggested queries for this dataset. The selected Board must have at least one query that is specific to the dataset you want to use suggested queries for, be public, and the queries must be named. The queries will be shown anytime you land on a blank Query page. Multiple datasets can use the same board. The Schema tab allows you to select whether nested JSON automatically unpacks, and lists the Dataset's Unique Fields and [Calculated Fields](/configure/datasets/calculated-fields/). Unique Fields lists all the unique fields seen in events from this dataset. You can modify a field's data type here if needed. If you change the type of a field in the Schema page and then later send an event where the data type does not match, then Honeycomb will try to coerce the value. If Honeycomb cannot coerce the value, it will get set to zero (`0`) rather than dropping the value. The **Definitions** tab allows you to indicate which fields in your Dataset have special meaning in Honeycomb. At the top of Dataset Definitions, two configuration completion indicators appear: [Tracing](/reference/honeycomb-ui/query/trace-waterfall/) () and [Home](/observe/honeycomb-home/) (). Example of Tracing and Home configuration completion indicators with Tracing complete and Home partially complete. Each indicator displays the level of field configuration completion in progress bar and in numerical format. If all fields are configured, then text will confirm completion. Otherwise, it warns about missing displays. Below the indicators, Dataset Definitions appear in rows. Two rows of dataset definitions with their fields mapped Each row consists of one or more icons, the **Dataset field**, and the **Field name**. The icons indicate if the Dataset Definition applies to the display configuration of Tracing and/or Home. Some Dataset fields overlap between the two configuration sets. The Dataset field is the fixed field that Honeycomb references in its configuration. The Field name options populate from fields in your dataset. If a Field name is blank, a Dataset Definition is not configured. To configure, use the dropdown list in Field name to choose from the available dataset fields. Selecting a dataset field maps it to Honeycomb's Dataset field. Multiple Dataset Definitions cannot use the same dataset field. If attempted, an "all fields must be unique" error message appears in the display. Honeycomb uses these definitions to provide more visualizations of your data in various Honeycomb interfaces, such as in [Home](/observe/honeycomb-home/), and in the [trace waterfall](/reference/honeycomb-ui/query/trace-waterfall/).\` The **Correlations** tab controls settings related to [Correlations](/investigate/analyze/correlate/) in Query Builder. ## Default Correlations Board Default Correlations Board sets a default [Board](/observe/boards/), which contains your queries of interest, to appear when using the Correlations tab in Query Builder. All charts from the default Correlations Board appear when you select the Correlations tab. Their order reflects their order on the Board. The selected Board must be public. Multiple datasets can use the same board. The Markers tab lists any Dataset-wide Marker and its associated color. Markers display as vertical lines on graphs to mark points in time where interesting things happen, such as deploys or outages. You must be a [team owner](/configure/teams/manage-permissions/) to change the Marker color in the Honeycomb UI. Modify a Dataset-wide Marker's color setting by selecting the field under the Color column in the Markers tab. Alternatively, use the [Marker Settings API](/api/marker-settings/). Learn more about [marker configuration](/configure/datasets/manage-markers/). In the **Delete** tab, a [team owner](/configure/teams/manage-permissions/) can delete a dataset. # Manage Environments Source: https://docs.honeycomb.io/reference/honeycomb-ui/manage-data/environments Reference for the Manage Environments page in the Honeycomb UI, where you can create and manage environments across your team. **Environments** displays a list of existing environments in your team. ## Displayed Fields Fields for each listed Environment include: * Name * API Keys * Datasets * Date Created * Data Last Received ### Available Tasks * Search Environments * Create Environment * Sort Fields by selecting field headers * Access Environment Settings by selecting target Environment's name. * View API Keys for Environment * Pagination navigation # Send Data Source: https://docs.honeycomb.io/reference/honeycomb-ui/manage-data/send-data Reference for the Send Data page in the Honeycomb UI, which displays OpenTelemetry auto-instrumentation setup instructions for supported languages. **Send Data** displays instructions on how to send trace data to Honeycomb. ## Displayed Information OpenTelemetry automatic instrumentation instructions for available languages and platforms include: * Node.js * Python * Java * .NET * Ruby * Go * Browser * Kubernetes * Other ## Available Tasks * View OpenTelemetry automatic instrumentation instructions # Query Source: https://docs.honeycomb.io/reference/honeycomb-ui/query Reference for the Honeycomb Query page, including Query Builder, Query Assistant, and how results are displayed in the query interface. Query allows you to investigate your data with Query Builder. When creating a new Query, the display includes the following components: * [Query Builder](#query-builder) - to enter your query * [Query Assistant](#query-assistant) - which translates your natural language query to Query Builder * Suggested Queries - a list of suggested queries based on a selected Board configuration After selecting **Run Query**, the screen refreshes to show: * [Query Builder](#query-builder) with your query * [Query Assistant](#query-assistant) * [Query Results](/reference/honeycomb-ui/query/query-results/) ## Query Builder The Query Builder A query in Honeycomb consists of up to six clauses: * **SELECT** - Performs a calculation and displays a corresponding graph over time. Most **SELECT** queries return a line graph while the `HEATMAP` visualization shows the distribution of data over time * **WHERE** - Filters based on field or attribute parameter(s) * **GROUP BY** - Groups fields by field or attribute parameter(s) * **ORDER BY** - Sort the results * **LIMIT** - Specify a limit on how many results to return * **HAVING** - Filter results based on aggregate criteria Learn more about [creating a query](/investigate/query/build/) and refer to our [example queries](/investigate/query/examples-traces/) to try. You can create a calculated field, or derived column, from the Query Builder! Start by selecting the **GROUP BY** field, and then select **Create calculated field** from its menu. If you need more help creating a calculated field, visit [Manage Calculated Fields](/configure/environments/calculated-fields/). ### Frequently Queried Values Dropdowns for the **SELECT**, **WHERE**, and **GROUP BY** clauses contain a section that shows the top five values that your team queries most frequently, so your team members can more easily construct repeated queries. Query Builder with the WHERE clause dropdown open. The frequently-queried fields section is highlighted. Listed values include data that has been most frequently queried and: * used within the last three weeks * used in manual queries * specific to the currently selected dataset and environment ## Query Assistant Query Assistant consists of: * a search box * **Get Query** * suggested questions Based on your entry or suggested question selection, Query Assistant creates and runs a query in the Query Builder. Query results appear after the screen refreshes. You can expand and collapse the Query Assistant display. Any changes you make will persist. You can also control your team's ability to use Query Assistant in [Team Settings](/reference/honeycomb-ui/account/team-settings/). To learn how to enable or disable Query Assistant, visit [Teams: Manage Behavior](/configure/teams/manage-behavior/#manage-query-assistant). ## Tasks * Query your data * Edit query * Change Datasets * Change applicable Time Range * Compare time ranges # Query Results Source: https://docs.honeycomb.io/reference/honeycomb-ui/query/query-results Reference for the Query Results panel in Honeycomb, including the Overview, BubbleUp, Correlations, Traces, and Explore Data tabs. In Query Results, any **SELECT** chart(s) displays first. Below, a series of tabs for further analysis appears, including: * [Overview](#overview) * [BubbleUp](#bubbleup) * [Correlations](#correlations) * [Traces](#traces) * [Explore Data](#explore-data) ## Overview The **Overview** view displays a summary table based on your query. If your query includes a **GROUP BY** clause, then the summary reflects a summary of grouped fields. ## BubbleUp The **BubbleUp** view activates after you select an area in a chart or heatmap. Honeycomb's BubbleUp feature compares your selection to all other results, or the baseline. Each comparison is represented as a chart. A dataset or environment has many fields. BubbleUp represents each field with a chart. The charts divide into two groups: * **Dimensions** contain fields with categorical or ordinal values * **Measures** contain fields with numeric values Each chart categorizes the data into two groups: * **Selection**, rendered in yellow on the right side of a value, contains the points in the area selected in the heatmap. * **Baseline**, rendered in blue on the left side of a value, contains all the points outside of the area selected. BubbleUp dimensions chart example with annotations The title of the chart is the name of the field. In the upper right corner, the two donut charts display a ratio of how often the field is found in the data. A field and its values may not be populated in a dataset or environment. Hover over the title and donut charts to display a tooltip with the full field name and a percentage of how often the field appears in the Selection (yellow) and Baseline (blue). The bar chart displays each value in bar form, which represents its frequency in the Selection or in the Baseline. The height of each bar is proportional to the number of times the value occurs in the results of the query. The bar chart displays a maximum of seventy-five values, a subset of both Selection and Baseline values. Hover over the bar for a value, to display a tooltip with its full value name and a percentage of how often the value appears in the Selection and Baseline. BubbleUp dimension bar chart value tooltip when hovered A field may contain largely unique values. These are sometimes referred to as **nominal** data. The tooltips for nominal columns show the exact number of occurrences instead of a percentage in the Selection or the Baseline. For example, events that capture a span in a trace maintain a unique ID for the span in the `trace.span_id` column. BubbleUp dimension with nominal values that show a value occurred 1 time in the baseline and 0 times in the selection Click on a value, or a pair of bars, to display an action menu to take further actions. For charts in the **Dimensions** section, this actions menu appears: BubbleUp dimension bar chart value action menu when clicked **Group by Field** : Adds a **GROUP BY ``** clause and re-runs the query. Select **Results** to view a summary of grouped fields below the heatmap. **Show only where field is value** : Adds a **WHERE** clause to filter with ` = ` and re-runs the query. **Show only where field is not value** : Adds a **WHERE** clause to filter with ` != ` and re-runs the query. **Copy field name** : Copies the field name to your OS clipboard. For charts in the **Measures** section, this actions menu appears: BubbleUp measures histogram chart value action menu when clicked **Show only where field less than** : Adds a **WHERE** clause to filter with ` < ` and re-runs the query. **Show only where field greater than** : Adds a **WHERE** clause to filter with ` > ` and re-runs the query. ## Correlations The **Correlations** view consists of a dropdown window that displays the selected data source, a Filter search box, and up to the first six saved queries from the selected data source. Screenshot showing the **Correlations** view display with a Service Health board selected and a filter of service.name=frontend Each query contains one or more chart visualization(s) and a Show Query Details icon (). Hover over the Show Query Details icon () to reveal the query's name and composition, and an option to open the query in a new tab. Selecting anywhere in the expanded query details opens the query in a new tab. Screenshot showing display with query name, link to Open Query in new tab, and query details ## Traces The **Traces** view displays up to 10 traces with the slowest spans that match your query's filters. Click to a trace. ## Explore Data The **Explore Data** view shows the raw data from the current query, which ignores the query's aggregates, any **GROUP BY** fields, and any **ORDER BY** fields. ### Events View Your data starts with the most recent events that occurred from the timestamp of the point you selected. At any time, you can choose to display your data either as a table display or as a log lines display. #### Table Display To display events data in a table, select the Show Table icon (). Each column represents a field from your dataset. Each row represents an event with associated values. Expanding a row displays all of the event's fields and their corresponding values. Query Builder with Explore Data view selected and table display #### Log Lines Display To display events data in log lines, select the Show Log Lines icon () icon. Each line represents an event, along with the values associated with the fields from your dataset. Expanding a line displays all of the event's fields and their corresponding values. Where applicable, events are color-coded to match their corresponding standard severity level: * Red: `error` * Yellow: `warn` * Light blue: `info` * Dark blue: `debug` * Light gray: `unspecified` * Dark gray: No severity set Color-coding relies on a source field being mapped to the **Logs: Severity** dataset field when you [map your data](/send-data/standardize/map-data/). In addition, if you are using non-standard severities, use Calculated Fields to [parse your severity values into Honeycomb standard severity values](/send-data/standardize/transform-data/#transform-source-severities-into-honeycomb-standard-severities). Query Builder with Explore Data view selected and log lines display To wrap long log lines, press \[`w`] on your keyboard or select **Line wrap log lines** from the display settings. ### Fields List On the left side of the **Explore Data** view, the fields list displays fields with data for this query. This list does not show all fields in the dataset. If a field is not visible, then spans in the query results have no data for that field. Use the Field Search box to search for a particular field name within the fields list. To expand the list and view all fields, scroll down the fields list and select **Load More** below the Displayed Fields list. #### Filter Fields To control which fields are visible in the table, select the Add icon () to the right of each field in the list of fields. Only the selected fields appears in the Explore Data table. A summary at the top of the fields list displays all selected fields under the Displayed fields section. To reorder fields in the table, select the Drag icon () and drag each field to the desired position. Fields list display with three selected fields in the displayed fields section. #### Download Your Data To download your data: 1. In the **Events** view, locate and select the Download options icon (). 2. In the **Export data** modal, choose the fields to include in your download. Use the **Export displayed fields only** toggle to export all event fields \[off] or export only fields displayed in the Events view \[on]. 3. Choose the file format that you would like to download: * **CSV**: Download Events data in comma-separated values format in a `.csv` text file. * **JSON** Download Events data in JSON format in a `.json` text file. Download menu with Export displayed fields only toggled on and options for CSV and JSON downloads You can download a maximum of 1000 rows. ### Search Within Results The Explore Data search feature is in [beta](/troubleshoot/product-lifecycle/release-stages/#beta). Your feedback can help us improve this feature! Share feedback in Pollinators or through your account team. Enter a string in the search bar to highlight occurrences of your search term within the query results. Honeycomb will search each field for your search term, display the total number of matches found, and highlight matches in both your query results and the fields list. For every field that matches your search term, Honeycomb may highlight: * a field value that matches, in the table display. For example, given the search term `logs`, Honeycomb would highlight the field value `honeycomb-logs` in the table display, regardless of field name. * a field name that matches, in the fields list. For example, given the search term `logs`, Honeycomb would highlight the field name `logs_ingest_sli`, regardless of field value. * a field name, in the fields list, that has a corresponding field value that matches. For example, given the search term `logs`, Honeycomb would highlight the field name `app.dataset.name` in the fields list if the field had a value of `honeycomb-logs`. **Scenario:** You run a simple COUNT query that returns all events that were captured in the last two hours. You want to search through the returned events to find occurrences of the term `error`. **Solution:** Enter your search term, `error`, in the search bar, and execute your search. Honeycomb highlights the word `error` anywhere it is found in your query results, and displays the total number of matches found. If matches are found, Honeycomb will highlight: * field values that contain `error`, in the table display * field names that contain `error`, in the fields list * field names, in the fields list, that have a corresponding field value that contains `error` Results returned in the Explore Data view for the search term 'error'. The total number of matches found is displayed near the search bar, and each occurrence of the word 'error' is highlighted in the table display and the fields list. Field names that do not contain the word 'error' may also be highlighted in the fields list, but only if the corresponding field value contains the word 'error'. To clear highlighted areas, cancel out of your search by selecting **x** in the search bar. #### Limitations The Explore Data search function: * Accepts only string arguments * Excludes calculated field field names and values ### Page Through Results To page through your data, use the arrow buttons located above and to the right of the **Explore Data** view data table. To adjust the number of events displayed per page, use the dropdown window next to the arrow buttons. Load more rows button at bottom of table ### Customize Event Formatting To customize event formatting, select the Display settings icon () in the top-right corner of the Events table, and then select the target toggle: **Format events** : Displays all fields in a line \[off] or one field per line \[on]. **Highlight full event** : Displays all field names and values in expanded events in black \[off] or enables syntax highlighting \[on]. **Line wrap log lines** : In the log lines display, allows text to extend beyond the visible area \[off] or wraps text to the next line \[on]. Event View Display Settings menu with the 'Format events' option selected, the 'Highlight full event' option selected, and the 'Line wrap log lines' option deselected. ### Interact with Expanded Events When you select a field within an expanded event, this action menu appears: **Remove column from table** : Removes field from displayed fields in **Explore Data** view. **Show only where field exists** : Adds a **WHERE** clause to filter with ` exists` and re-runs the query. **Show only where field does not exist** : Adds a **WHERE** clause to filter with ` does-not-exist` and re-runs the query. **Show only where field is value** : Adds a **WHERE** clause to filter with ` = ` and re-runs the query. **Show only where field is not value** : Adds a **WHERE** clause to filter with ` != ` and re-runs the query. **Group by field** : Adds a **GROUP BY** clause with `` and re-runs the query. **Copy field name** : Copies the field name to your OS clipboard. **Copy value** : Copies the value name to your OS clipboard. Events Column action menu with eight menu options listed. ### View Tracing Details If your dataset is a tracing dataset, then the `trace.trace_id` column displays trace ID fields as hyperlinks. Select any trace ID hyperlink to display the [trace waterfall view](/reference/honeycomb-ui/query/trace-waterfall/), which contains the span represented by that row. Tracing link example # Trace Waterfall Source: https://docs.honeycomb.io/reference/honeycomb-ui/query/trace-waterfall Reference for the Trace Waterfall view in Honeycomb, covering trace identification, summary metadata, the waterfall display, and span details. ## Interact with Traces The trace detail view displays information in four areas: * [trace identification](#trace-identification) with navigation and trace ID * [trace summary](#trace-summary) with trace metadata * [waterfall representation](#waterfall-representation) of spans with search and customization options * [trace sidebar](#trace-sidebar) with details about the selected span Trace view with each section outlined ### Trace Identification Each trace has a unique identifier presented at the top of page along side navigation elements. Trace view identification The left-arrow navigates away from the trace view back to the visualization or results table where the trace was selected. Honeycomb presents a trace when it has received the root span. Each span has a unique identifier and datetime stamp of when it was created. The **Reload Trace** button reloads the trace to ensure the waterfall representation contains all spans in the trace. Traces may display a warning that it is missing spans with a link to resources to assist with [troubleshooting the missing spans](/troubleshoot/common-issues/data-in-honeycomb/#traces-have-a-missing-root-span-or-missing-spans). Trace view missing spans ### Trace Summary The trace summary displays important metadata and provides a condensed view of the trace waterfall diagram. Metadata about the trace includes its total number of spans, the timestamp of the root span, and the total trace duration. Use this view to find long-running spans and spans with errors within your trace without scrolling through the entire trace waterfall. Expand or collapse the summary view by selecting the directional caret. Trace summary view The trace summary displays up to 6 levels of span dependency. The first level in the topmost row starts with the root span. The second row shows the root span's dependent spans, and each following row displays a dependent span level, if applicable. The width of the summary represents the whole duration of the trace. Hover over any span to see the name of the longest running span at that depth and point in time. Select the span to view its highlighted location in the waterfall representation below. Trace summary hover view Use **Highlight errors** to toggle span error highlighting on and off. Spans with errors appear in red. Select a span with an error to view its location in the waterfall representation below and additional metadata in the trace sidebar. Highlight errors in the summary ### Waterfall Representation Honeycomb uses the metadata from each span to reconstruct the relationships between them and generate a trace diagram. This is also called a **waterfall diagram** because it shows how the order of operations cascades across the total execution time. Trace view waterfall representation Each span contains a collection of fields and values. The diagram displays, at a minimum, the span's relationship, its name, and a representation of its duration. Next to each span's name shows its relationship in the trace. A span with dependencies displays a box with the number of dependent spans. A span without a box represents a span with no dependencies. The currently selected span's row is highlighted in blue. Details about the selected span appear to the right in the [trace sidebar](#trace-sidebar). Trace diagram ### Trace Sidebar When a span is selected, the trace sidebar updates with details about the span, including its fields, span events, and links. The Span Events tab of the trace sidebar displays details about span events, if applicable. To access, navigate to the Span Events tab and select the Span Event name to show its details. Alternatively, in the waterfall diagram, select the circle that represents a span event to display the span event's details in the trace sidebar's Span Events tab. The Links tab of the trace sidebar displays details about span links, if applicable. To access, navigate to the Links tab to view span link details. Alternatively, in the waterfall diagram, select the link icon that represents a span link to display details in the trace sidebar's Links tab. Trace sidebar #### The Minigraph The minigraph, at the top of the trace sidebar, shows a heatmap view of the selected span relative to others with the same fields displayed in the waterfall. Selecting anywhere in the minigraph sends you to the Query Builder display with a query that corresponds to the minigraph. ## Tasks * Reload trace * Search for spans that contains a field or value name * Expand or collapse trace summary * Collapse and expand Spans * Zoom in on Spans * Navigate between highlighted Errors * Customize Waterfall Representation * Customize Displayed Fields * Resize Columns * Change Span Color * Filter results in Trace Sidebar * Refine search based on field and return to Query Builder # Service Map Source: https://docs.honeycomb.io/reference/honeycomb-ui/service-map Reference for the Service Map page in the Honeycomb UI, covering the service count header, traffic flow visualization, and span filtering controls. ## Interact with Service Map At the top, the Service Map summarizes how many services are displayed. Service map header to show service count and time picker A label indicates when the Service Map last regenerated. Use the **time picker** to modify the selected timespan. Use a preset time range or a custom time range. Navigate your selection history with the left and right arrows. The Service Map displays a network of [services](#service) connected by [edges](#edge). Service map overview Use the [**Services**](#select-services) and [**Filter Traces**](#filter-traces) dropdowns in the top left corner to modify and show a specific view of your Service Map based on entered service names or specific fields. Service Map will display a maximum of 300 services. If your map is larger than 300 services, apply [filters](#filter-traces) to focus on a set of services important to you. The [**Gateways**](#gateways) and [**Entry Services**](#entry-services) buttons in the top right corner highlight their respective service type. Use your mouse or trackpad to magnify and view parts of the map in detail. Use the **Recenter** button in the top right corner to reset the map display to an overview magnification level. Select the **Show Legend** icon () to translate symbol meanings. Select a service to trigger a hover box with service name and `p95` duration information. Select **Isolate** in the hover box to activate [Isolate Mode](#isolate-mode). Hovering on a service also highlights that service's dependencies within the Service Map. The [right side panel](#right-side-panel) displays details about services and lists a sample of related traces. Service map right side panel on overview Use the collapsible [right side panel](#right-side-panel) to: * view details about the entire map in Overview, or about a selected service or edge * access a sample of traces ### Service Each **Service** is represented by a circular node. The size of the service represent the relative volume of requests that the service receives compared to other services in your environment. Services in purple have the highest number of dependencies, or combined incoming and outgoing services. The service's labels display the `service.name` value and its `p95` duration. Disconnected services display separately from the main set of connected services. Disconnected services are services that do not communicate to or reference other services. Select a service to populate its details in the [right side panel](#right-side-panel). ### Edge An **Edge**, or line, represent communication between two services. The thickness of the edge represents the relative volume of requests between the two services compared to other services. When it appears, the edge's label displays its `p95` duration. Select an edge to populate its details in the [right side panel](#right-side-panel). ### Right Side Panel The right side panel displays details about services, lists a sample of related traces, and provides the ability to filter and highlight. The panel's title indicates if it summarizes the **Overall** Service Map, a specific service by its name, or a selected edge. The panel displays an **Overall** view when the map initially loads, or when no service or edge is selected. All services are displayed in an alphabetized list with their `p95` durations. **Disconnected** appears in the Services list with the total of disconnected services present. Disconnected services are services that do not communicate to or reference other services. When a Service is selected, the side panel displays: * Service Name * Service `p95` Latency: The `p95` duration for this service to respond to requests * [Traces](#traces): a sample of five related traces within the selected time range * Incoming Services: a list of services that send requests to this service, and the `p95` duration between the selected service and the incoming service * Outgoing Services: a list of services that this service sends requests to, and the `p95` duration between the selected service and the outgoing service When an Edge is selected, the side panel displays: * Edge `p95` Latency: The `p95` duration for the receiving service to respond to the requesting service * [Traces](#traces): a sample of five related traces within the selected time range * The requesting service and its overall `p95` latency * The receiving service and its overall `p95` latency #### Search Services In the right side panel, use **Search services** to enter terms and search for a specific service. As you type, Honeycomb updates the list of displayed services. Service map filters #### Traces In the right side panel, Service Map provides sample traces that correspond to the Service Map. When selecting a service or edge, the right side panel updates to display a list of five traces that contain the selected service(s). Service map traces list with See More button Select **See More** for a longer list of traces in [Query Builder](/investigate/query/build/) and the ability to explore related traces in detail. For a service, **See More** creates a query with a filter where `service.name = `. For an edge, **See More** creates a query with a filter where ` calls = true`. This unique filter includes a custom-created Honeycomb [calculated field](/configure/environments/calculated-fields/), specific for this query, to isolate traces where the requesting service (``) calls the receiving service (``). If any [filter](#filter-traces) is applied to Service Map, **See More** creates a query as described above and includes an additional [calculated field](/configure/environments/calculated-fields/)-based filter where the applied filter's conditions are also met. ### Select Services In the **Services** dropdown, enter one or more service names to modify the Service Map display and show only the entered service(s). As you type, Honeycomb autocomplete prompts with selectable service names. Service map search service ### Filter Traces In the **Filter Traces** dropdown, enter fields to modify the Service Map display and show only services with traces that contain at least one span that matches the entered criteria. To define a filter, enter a field name, operator, and field value. As you enter terms, Honeycomb autocomplete prompts with selectable field options. Service map preset-filters Use the environment-wide fields that appear as a prompt to start defining a filter. For example, use the `Route` preset to filter for all routes that contains `/checkout`. The following environment-wide preset filters are available and based on each dataset's [dataset definitions](/configure/datasets/definitions/): * Name * User * Error * Route * Status Code ### Isolate Mode **Isolate Mode** focuses the map to display a single service and its immediate dependents. Service map isolate map enabled and disabled for a service When activated, "Isolate Mode" appears at the top of the Service Map display to indicate its status. The map updates to show only the target service, the **Incoming Services** that send requests to the target service, and **Outgoing Services** that the target service sends request to. Select **Show full map** at the top left to leave Isolate Mode and return to the overall map. ### Gateways Use **Gateways** to illustrate which services communicate to another through a known gateway. Service map toggling gateways When toggled on, any **Gateway** appears as a blue square on an edge. Hover over the blue square to see the Gateway's name and its `p95` latency. Display that appears when hovering over a square Gateway icon [Learn more about instrumenting gateways](/observe/service-map/#instrument-for-gateways). ### Entry Services Use **Entry Services** to highlight which services are in the root span of any trace. Service map entry services highlighted Toggle **Entry Services** in the top right corner of the Service Map to modify the Service Map display. When activated, any Entry Service appears with an additional dashed circle around its circular node. # SLOs Source: https://docs.honeycomb.io/reference/honeycomb-ui/slos Reference for the SLOs page in the Honeycomb UI, which lists your configured SLOs and their current status. This feature is available as part of the [Honeycomb Enterprise and Pro plans](https://www.honeycomb.io/pricing/). SLOs displays a list of your configured SLOs within Honeycomb. If no SLOs exist, then a prompt to create your first SLO or to learn more about SLOs appears instead. Select an SLO name in the list to view the target SLO's [details](/reference/honeycomb-ui/slos/slo-detail-view/). Enter search terms in the [SLO search box](#slo-search) to filter your SLO list display. Select **New SLO** in the top right corner to [create a new SLO](/notify/slos/create/). ## Displayed Fields The SLO list view shows information for each SLO, including: * **SLO Name** - Shows the SLO Name. * **SLO Description** - Shows the SLO description * **SLI** - Shows the SLI and Dataset associated with the SLO. Selecting the SLI sends you to the [Calculated Fields](/configure/environments/calculated-fields/) display to see the SLI in more detail. Selecting the Dataset creates an [SLO search](#slo-search) based on the dataset name. * **Time** - Shows the time period in days. * **Target** - Shows the set target for the SLO in percentage form. * **Current** - Shows the current historical compliance for the SLO in percentage form. * **Budget** - Shows the current budget burndown for the SLO in percentage form. If the budget is >0%, it is green. Otherwise, it is red. * **Status** - Shows if a [Burn Alert](/notify/slos/monitor/) is currently active, which indicates that the error budget is rapidly burning down, or if the SLO is not receiving data. When active, the Burn Alert with the shortest configured exhaustion time (Exhaustion Time burn alert) or shortest time window (Budget Rate burn alert) also displays here. If the SLO received no data during the entire SLO window, then "No events" appears. * **Last Edited** - Displays the user who edited the SLO and on what date. All fields are sortable. The SLO table is also customizable where you can select which columns to display. ## SLO Search The SLO search box searches across SLO name, SLO description or associated Dataset. The results appear as a filtered list of your SLOs in the SLO list display. To filter SLOs based on their associated Dataset, use the search prefix `dataset:` before the dataset name. For example, `dataset:frontend`. SLO search works particularly well if your SLOs have detailed names and descriptions. This practice adds additional human context and makes it easier to find a specific query. ## Filter by Tags Filter by Tags searches for assigned key:value pairs in SLOs. The results appear as a filtered list of your SLOs in the SLO list display. For example, filter your SLOs based on tags, such as: * team name (`team:sre`) * environment (`env:prod`) * service (`service:payments`) Assign Tags to SLOs during [SLO Creation](/notify/slos/create/#create-your-slo), or while modifying existing SLOs. ## Tasks * Create new SLO by selecting **New SLO** * View SLO details by selecting an SLO name * Pin an SLO to the top of the list with "Pin" * Search by SLO Name * Sort SLOs by field * Select visible fields via Table Settings * Pagination navigation # SLO Detail View Source: https://docs.honeycomb.io/reference/honeycomb-ui/slos/slo-detail-view Reference for the SLO Detail View in the Honeycomb UI, showing SLO parameters, error budget status, and burn alert configuration. EntPro This feature is available as part of the [Honeycomb Enterprise and Pro plans](https://www.honeycomb.io/pricing/). Each SLO has a detailed view that shows information based on its parameters. At the top, the SLO detailed view shows the SLO's: * **Name** * **Creator user name** * **Creation date** * **Description** * **Tags** of assigned key:value pairs * **Summary chart** of existing [Burn Alerts](/notify/slos/monitor/) with set exhaustion time and status Select **Configure Burn Alerts** to view [existing Burn Alerts](/reference/honeycomb-ui/slos/slo-detail-view/burn-alerts-for-slo/) and create new Burn Alerts. Also, an SLO detailed view displays information in the following areas: * **[Budget Burndown](#budget-burndown)** - shows the cumulative error against the set SLO budget. * **[Burn Rate](#burn-rate)** - gives the ratio of actual failures in the SLO to expected failures in the given time window. * **[Historical SLO Compliance](#historical-slo-compliance)** - shows often the SLI has succeeded for each day over the preceding SLO Time Period. * **[Heatmap](#heatmap)** - shows events that succeed the SLI (in blue-green) and that fail (in yellow) on a heatmap of duration. * **[BubbleUp](#bubbleup)** - shows the dimensions where the events that pass the SLI (in blue) and those that fail it (yellow) are most different. SLO summary view. ## Budget Burndown **Budget Burndown** shows the cumulative error against the SLO budget and projects how much budget remains over a given period of time. The Budget Burndown starts at `100%` and decreases as the budget reduces. This value is computed as a rolling window, so every moment is based on the preceding time. To receive alerts on this measurement under certain conditions, use [Burn Alerts](/notify/slos/monitor/). ## Burn Rate **Burn Rate** gives the ratio of actual failures in the SLO to expected failures in the given time window. The burn rate, located below the Budget Burndown chart, tells the current burn rate in the last `X` hour(s). The time window defaults to `4` hours, but you can input a different value to recalculate the current burn rate for your situation. SLO Historical Burn Rate Select the caret to expand the display and view a chart for **Historical Burn Rate**. Given the input of `X` hours in the time window, the Historical Burn Rate chart displays the burn rate over `X` hours for the SLO. Use the current Burn Rate to understand the **severity** of recent errors in the SLO. Use the Historical Burn Rate chart to understand how **consistently** the SLO burns and if specific points of time impacted the SLO budget. It is expected and acceptable for an SLO to sometimes burn at a higher rate than budgeted, and to sometimes burn at a lower rate than budgeted. Over time, you will know if you meet your specific SLO budget; the burn rate, however, informs on your SLO budget's recent behavior. ### Interpreting a Burn Rate A burn rate of `1.0` means that the SLO budget is reducing as expected and as budgeted, given the parameters of the SLO. This means the SLO experienced the expected number of failed events. A burn rate of less than `1.0` means that less failures occurred than what was budgeted in the SLO. If this burn rate is consistently below `1.0`, this could be a signal of an SLO that you should revisit. Is the SLO underambitious? Is the SLO capturing the signal you care about? A burn rate of greater than `1.0` means that more failures than expected occurred, given the budget of the SLO. The higher the multiplier, the more likely the SLO is impacted by the high count of failures. This may indicate that something is clearly wrong with your service and that you need to investigate. For example, for an SLO with a 30 day period, the following multipliers correlate to the amount of time until the SLO budget reaches zero: * 1x = 30 days * 2x = 15 days * 4x = 7.5 days * 8x = 3.25 days * 16x = 39 hours * 32x = 19 hours and 30 minutes * 64x = 9 hours and 45 minutes * 128x = almost 5 hours To receive alerts on this measurement under certain conditions, use [Burn Alerts](/notify/slos/monitor/). ## Historical SLO Compliance **Historical SLO Compliance** shows how often the SLI has succeeded for each day over the preceding SLO Time Period, such as 14 days. ## Heatmap This [Heatmap](/investigate/analyze/visualize-events/) display shows events that succeed the SLI and events that failed the SLI on two heatmaps of duration. The time axis runs over a much shorter period than the full SLO period, which allows you to focus on individual events and times that set off the SLO. You can modify the heatmap using the following controls: 1. Selected Column 2. Time Range 3. Linear or Log Scale **Selected Column** controls what field is visualized in the heatmap. Modify which field by using the "Distribution of Events failing SLI by" dropdown above the heatmap. In the example above, `duration_ms` is the selected column and displays `duration_ms` over time and how frequently each duration - time period combination occurs. In many cases, you do not need to change the selected column, or field. If your SLI consists of multiple fields like duration, status codes, and other measures, you may want to explore seeing successful and failed events across different fields. **Time Range** specifies the start and end time for data in your heatmap and BubbleUp display. Modify the time range using the time picker in the upper right corner above the heatmap. This time range appears as an orange range within the Budget Burndown and Historical Compliance charts. Adjust the time range if you seek more information on your SLO, such as a sudden drop in SLO Budget. View the heatmap in **log scale** or **linear scale**. By default, SLO heatmaps display in log scale. Log scale displays a heatmap with a `LOG()` transformation applied to your data, which helps visualize duration times and large outliers. Linear scale displays a heatmap with a linear axis, which helps with less extreme outliers such as status codes. Select the Settings icon () above the heatmap to change this setting. This setting is locally saved to the browser and does not save to the SLO. SLO Heatmap Timerange on a drop in budget. ## BubbleUp The [BubbleUp](/investigate/analyze/identify-outliers/) series at the bottom of the screen shows the dimensions where the events that pass the SLI (in blue) and those that fail it (yellow) are most different. This information can provide insight into the causes for current burndown activity. The BubbleUp looks at the same time period as the heatmap. ## Reset Your Remaining SLO Budget Burn Alerts will only activate if a SLO budget remains above zero. If the error budget was depleted due to some issue and then you fixed the problem, it is worth resetting your error budget so Burn Alerts will start working again. Resetting your budget erases all errors that occurred in the current SLO time period, up to and including the current hour, depending on your selection. For example, when resetting an SLO with a 30 day period, the SLO budget will be back to 100% for that 30 days. This reset will affect both your Budget Burndown and Historical SLO Compliance graphs on the SLO detailed view, as well as the Current Percentage displayed in the SLO lists. SLO Reset in charts In the image above, the reset is noted by a gray dashed line on the SLO Budget Burndown and SLO Historical Compliance charts. * The SLO Budget Burndown chart starts at 100% compliance to the left of the dashed line because all errors before that reset and after the start of the compliance period were erased. * The Historical SLO Compliance chart increase over time in the time period before the reset and after the start of the compliance period when the SLO was reset. Reset your budget back to 100% by: 1. Go to the target SLO's SLO detail view. 2. Locate the Budget Burndown chart. 3. Select the **Reset Budget** button in the Budget Burndown chart. SLO Reset button 4. In the confirmation window that appears, select when Honeycomb starts counting new failures after resetting the SLO. Choose between: * **before the current hour**: ignores prior failures up to the current hour. For example, if the SLO budget is reset at 8:15, then Honeycomb starts counting new failures from 8:00 onwards. Use if you want to continue to catch issues on your SLO for the current hour. * **after the current hour**: ignores prior failures up to and including the current hour. For example, if the SLO budget is reset at 8:15, then Honeycomb starts counting new failures from 9:00 onwards. Use if you no longer want to be alerted about errors for the current hour. If you are confident that no more issues will occur on your SLO, choose this option to fully reset your alerts and ignore events up to the hour. 5. Select **Reset** to reset your SLO budget. ## Ignore Past Budget Resets If you used [**Budget Reset**](#reset-your-remaining-slo-budget) to reset your SLO's budget, then **Ignore Budget Resets** gives the ability to view the SLO Budget Burndown and SLO Historical Compliance charts without accounting for past resets. This setting does not permanently remove past resets and allows you to toggle between two perspectives. To modify the charts' view and ignore previous budget resets, select the **Ignore Budget Resets** checkbox above the SLO Historical Compliance chart. SLO ignore budget reset ## Tasks * Configure Burn Alerts * Delete * Edit SLO * Use Ignore Budget Resets to modify charts' view # Burn Alerts for SLO Source: https://docs.honeycomb.io/reference/honeycomb-ui/slos/slo-detail-view/burn-alerts-for-SLO Reference for the Burn Alerts for SLO page in the Honeycomb UI, which lists configured burn alerts. EntPro This feature is available as part of the [Honeycomb Enterprise and Pro plans](https://www.honeycomb.io/pricing/). Burn Alerts for SLO displays a list of Burn Alerts for your SLO. ## Displayed Fields Fields for each listed Burn Alert include: * Alert Type * Time Window * Budget Decrease * Status * Notify * Created By Only Alert Type, Time Window, and Status fields are sortable. ## Tasks * Create New Burn Alert by selecting **New Burn Alert** * Delete Burn Alert by selecting Delete button * Test Burn Alert by selecting Test button * Edit Burn Alert by selecting Edit button # Triggers Source: https://docs.honeycomb.io/reference/honeycomb-ui/triggers Reference for the Triggers page in the Honeycomb UI, which lists your configured Triggers. Triggers displays a list of your configured Triggers within Honeycomb. If no Triggers exist, then a prompt to create your first trigger appears instead. ## Displayed Fields Fields for each listed Trigger include: * Trigger Name with selectable name, description and selectable defined query * Status * Recipients * Dataset * Frequency * Duration * Last Edited All fields are sortable. ## Filter by Tags Filter by Tags searches for assigned key:value pairs in Triggers. The results appear as a filtered list of your Triggers in the Trigger list display. For example, filter your Triggers based on tags, such as: * team name (`team:sre`) * environment (`env:prod`) * service (`service:payments`) Assign Tags to Triggers during [Trigger Creation](/notify/triggers/create/#creating-triggers), or while modifying existing Triggers. ## Tasks * Search by Trigger Name * Create New Trigger * Edit Trigger by selecting Trigger Name * Test Trigger by selecting Test button * Delete Trigger by selecting Delete button * Pagination navigation # Usage Source: https://docs.honeycomb.io/reference/honeycomb-ui/usage Reference for the Usage page in the Honeycomb UI, which displays event throughput, warning and danger states, and your team's usage against plan limits. In the left navigation menu, any usage warning state appears on the usage radial in the left navigation menu. Honeycomb surfaces a warning (yellow) state and a danger (red) state based on historical event throughput for a team. The colors are shown on the usage radial on the left navigation menu. | Status | Icon | | ------- | ----------- | | OK | | | Warning | | | Danger | | The usage radial will be completely green when event throughput is trending below the team's monthly event limit. A warning state is triggered when a team is trending toward an overage based on event throughput in the current calendar month, or when the team has exceeded their EPM limit for one month as described above in the Overages section. A danger state is triggered when a team has been over its EPM limit for two consecutive months. ## Tasks * Select Usage to navigate to the [Usage tab in Team Settings](/reference/honeycomb-ui/account/team-settings/). # Reference: Query Specification Source: https://docs.honeycomb.io/reference/query-specification Define Honeycomb queries in JSON to use with the Query API, Boards API, Triggers API, and query template links. Reference for supported syntax and structure. We support defining queries via JSON. You can use defined queries in Honeycomb with: * [Query Template Links](/investigate/collaborate/share-query/) * the [Query API](/api/queries/) * the [Boards API](/api/boards/) * the [Triggers API](/api/triggers/) To convert query JSON into a sharable query URL, refer to [Query Template Links](/investigate/collaborate/share-query/#creating-a-query-template-link-manually) documentation. ## Fields on a Query Specification All fields are optional, but a query without any `calculations` values will have `COUNT` applied automatically. * `breakdowns`: a list of strings describing the columns by which to break events down into groups * `calculations`: a list of objects describing the calculations to return as a time series and summary table. Each calculation consists of an `op` and a `column` (except for `COUNT` or `CONCURRENCY`, which need no column). If no `calculations` are provided, `COUNT` is applied. [See below for a list of valid `op`s](#calculation-operators). * `filters`: a list of objects describing the filters with which to restrict the considered events. Each filter consists of a `column`, `op`, and (sometimes) `value`. [See below for a list of valid `op`s](#filter-operators). * `filter_combination`: either `"AND"` or `"OR"`. If multiple filters are specified, `filter_combination` determines how they are applied; set to `"OR"` to match ANY filter in the filter list. Defaults to `"AND"`. * `granularity`: an integer describing the time resolution of the query's graph, in seconds. Valid values are the query's time range /10 at maximum, and /1000 at minimum. * `orders`: a list of objects describing the terms on which to order the query results. Each term must appear in either the `breakdowns` field or the `calculations` field. * `limit`: an integer describing the maximum number of query results. * `havings`: a list of objects describing filters with which to restrict returned groups. Each `having` consists of a `calculate_op` (the same set used for `op` in `calculations`, but excluding `HEATMAP`), a `column` (except for `COUNT`, which needs no column), an op (`=`, `>`, `>=`, `<`, `<=`), and a `value` (currently assumed to be numeric). Each `column`/`calculate_op` pair must appear in the `calculations` field. There can be multiple `havings` for the same `column`/`calculate_op` pair. * `time_range`: an integer describing the time range of query in seconds, for relative-time queries. Cannot be combined with both `start_time` and `end_time` ([See caveat below](#how-to-specify-an-absolute-time-range).) Defaults to two hours. * `start_time`: an integer describing the UNIX timestamp of the absolute start time of the query. * `end_time`: an integer describing the UNIX timestamp of the absolute end time of the query. * `calculated_fields`: a list of objects defining the [calculated fields](/investigate/query/build/calculated-fields/) that are computed from your data using expressions. Each calculated field consists of a `name` (used to reference it in calculations, filters, or ordering) and an `expression` (a formula that derives its value from existing fields). * `formulas`: a list of objects that combine named calculations into an expression ([Query Math](/investigate/query/math/)). Each formula consists of a `name` and an `expression` that references calculations by name, such as `$errors / $total`. To reference a calculation in a formula, give that calculation a `name` in the `calculations` field (each calculation may also carry its own `filters`). ## How to Specify an Absolute Time Range To specify an absolute time range, use `start_time` and `end_time` (both UNIX timestamps) to describe the desired range: ```json theme={} { "start_time": 1727755200, "end_time": 1728964800 } ``` `start_time` or `end_time` can also be used in combination with `time_range` to specify a fixed time plus a range. Specifying values for all three fields, however, will result in an error. The following describes "the one-hour period leading up to the absolute time 2024-05-01 00:00 UTC": ```json theme={} { "end_time": 1714536000, "time_range": 3600 } ``` Without a `start_time` or `end_time`, a single `time_range` argument will default to an `end_time` of "now." The following describes "the last hour" relative to the time of invocation: ```json theme={} { "time_range": 3600 } ``` ## Examples ### Top Ten Unique `user_agents` by Volume This query specification calculates the top 10 (by volume, or `COUNT`) unique `user_agents` for the hour leading up to the absolute time 2024-01-01 00:00 UTC: #### Query Builder Query | VISUALIZE | WHERE | GROUP BY | | --------- | ----- | ------------ | | COUNT | | `user_agent` | Use the [time picker](/investigate/query/build/#change-and-compare-query-time-ranges) to apply "Last 1 Hour". #### JSON ```json theme={} { "breakdowns": ["user_agent"], "calculations": [{ "op": "COUNT" }], "orders": [{ "op": "COUNT", "order": "descending" }], "limit": 10, "time_range": 3600, "end_time": 1704085200 } ``` ### Average Content Length of Events This query specification calculates the `AVG(content_length)` of events from the last hour matching `kafka_partition = 3` or `kafka_partition = 6`: #### Query Builder Query | VISUALIZE | WHERE | | --------------------- | --------------------------------------------------- | | AVG (content\_length) | kafka\_partition = 3 OR
kafka\_partition = 6 | ```json theme={} { "calculations": [{ "column": "content_length", "op": "AVG" }], "filters": [ { "column": "kafka_partition", "op": "=", "value": 3 }, { "column": "kafka_partition", "op": "=", "value": 6 } ], "filter_combination": "OR", "time_range": 3600 } ``` ### Filter Events Based on Length of Duration and Service Name This query specification matches events with `duration_ms > 500` and `service.name != "fraud"`, then calculates a `HEATMAP(match_quality)` (where the graph spans the last 3 hours, drawn at 15-minute intervals): #### Query Builder Query | VISUALIZE | WHERE | | ----------------------- | ------------------------------------------------- | | HEATMAP(match\_quality) | duration\_ms > 500
service.name != "fraud" | #### JSON ```json theme={} { "calculations": [{ "column": "match_quality", "op": "HEATMAP" }], "filters": [ { "column": "duration_ms", "op": ">", "value": 500 }, { "column": "service.name", "op": "!=", "value": "fraud" } ], "granularity": 900, "time_range": 10800 } ``` ### Top 100 Results for Average Duration and 99th Percentile of Event Duration Ranked by Duration and User This query specification describes an absolute-time query which matches events with `result = 200`, then calculates the `AVG(duration_ms)` and `P99(duration_ms)` broken down into unique (`user_id`, `build_id`) pairs. It then returns the first 100 results, ordered first by `P99(duration_ms)` values, then `user_id`. #### Query Builder Query | VISUALIZE | WHERE | GROUP BY | | ------------------------------------------ | ------------ | --------------------------- | | AVG(duration\_ms)
P99(duration\_ms) | result = 200 | `user_id`
`build_id` | | ORDER BY | LIMIT | | ------------------------------------------- | ----- | | P99(duration\_ms) desc
user\_id desc | 100 | #### JSON ```json theme={} { "breakdowns": ["user_id", "build_id"], "calculations": [ { "column": "duration_ms", "op": "AVG" }, { "column": "duration_ms", "op": "P99" } ], "filters": [{ "column": "result", "op": "=", "value": 200 }], "orders": [ { "column": "duration_ms", "op": "P99", "order": "descending" }, { "column": "user_id" } ], "limit": 100, "start_time": 1515542451, "end_time": 1515546051 } ``` ### Top 100 Results for Events with a Duration With Longer Than 10000 Milliseconds This query specification describes a query over the last hour that matches events with `result = 200`, then calculates the `AVG(duration_ms)` and `P99(duration_ms)` broken down into unique (`user_id`, `build_id`) pairs. It then returns the first 100 results that have a `P99(duration_ms) > 10000`, ordered first by `P99(duration_ms)` values, then `user_id`. #### Query Builder Query | VISUALIZE | WHERE | GROUP BY | | ------------------------------------------ | ------------ | ------------------------- | | AVG(duration\_ms)
P99(duration\_ms) | result = 200 | user\_id
build\_id | | ORDER BY | LIMIT | HAVING | | -------------------------------------- | ----- | ------------------------- | | P99(duration\_ms) desc
user\_id | 100 | P99(duration\_ms) > 10000 | #### JSON ```json theme={} { "breakdowns": ["user_id", "build_id"], "calculations": [ { "column": "duration_ms", "op": "AVG" }, { "column": "duration_ms", "op": "P99" } ], "filters": [{ "column": "result", "op": "=", "value": 200 }], "orders": [ { "column": "duration_ms", "op": "P99", "order": "descending" }, { "column": "user_id" } ], "havings": [ { "calculate_op": "P99", "column": "duration_ms", "op": ">", "value": 10000 } ], "limit": 100, "time_range": 3600 } ``` ### Match Specific Users and Identify Experienced Errors This query specification describes a query that filters for specific users based on their email address who are experiencing errors broken down by error code. #### Query Builder Query | VISUALIZE | WHERE | GROUP BY | | --------- | -------------------------------------------------------------------------------------------------------------------------- | ---------- | | COUNT | app.user.email in [foo@example.com](mailto:foo@example.com), [bar@example.com](mailto:bar@example.com)
error exists | error.code | #### JSON ```json theme={} { "breakdowns": [ "error.code" ], "calculations": [ { "op": "COUNT" } ], "filters": [ { "column": "app.email", "op": "in", "value": ["foo@example.com", "bar@example.com"]}, { "column": "error", "op": "exists"} ], "filter_combination": "AND" } ``` ## Calculation Operators Calculation operators are consistent between the API and the UI. The available calculation `"op"` values are: * `COUNT` (optionally expects an accompanying `"column"` value) * `CONCURRENCY` (does not expect an accompanying `"column"` value) * `SUM` * `AVG` * `COUNT_DISTINCT` * `MAX` * `MIN` * `P001` * `P01` * `P05` * `P10` * `P20` * `P25` * `P50` * `P75` * `P80` * `P90` * `P95` * `P99` * `P999` * `HEATMAP` * `RATE_AVG` * `RATE_SUM` * `RATE_MAX` * `COUNT_DATAPOINTS` (time series metrics datasets only; counts datapoints ingested across all metric fields, or for a single metric when given a `"column"`) * `HISTOGRAM_COUNT` (time series metrics datasets only; expects a histogram `"column"` and counts the observations recorded in it) On time series metrics datasets, temporal aggregation (`LAST`, `SUMMARIZE`, `INCREASE`, and the per-second `RATE`) is applied automatically based on each metric's type, so it is not selected as a calculation `op`. Choose a spatial calculation such as `SUM`, `AVG`, `MAX`, a percentile, or `HISTOGRAM_COUNT` on the metric column, and Honeycomb applies the matching temporal function underneath (for example, `INCREASE` for a cumulative counter). To learn more, visit [Temporal Aggregation Concepts](/investigate/query/temporal-aggregation). `RATE_AVG`, `RATE_SUM`, `RATE_MAX`, `CONCURRENCY`, and bare `COUNT` (without a `column`) are not available on time series metrics datasets. ## Filter Operators Filter operators are consistent between the API and the UI. The available filter `"op"` values are: * `=` * `!=` * `>` * `>=` * `<` * `<=` * `starts-with` * `does-not-start-with` * `ends-with` * `does-not-end-with` * `exists` (does not expect an accompanying `"value"`) * `does-not-exist` (does not expect an accompanying `"value"`) * `contains` * `does-not-contain` * `in` (filter `"value"` must be present and be an array - [example](#match-specific-users-and-identify-experienced-errors)) * `not-in` (filter `"value"` must be present and be an array) # Query Specification Reference Source: https://docs.honeycomb.io/reference/query-specification-reference # Security & Compliance: Overview Source: https://docs.honeycomb.io/security-compliance Find out how Honeycomb secures its infrastructure, protects your data, maintains compliance certifications, and approaches AI features responsibly. Honeycomb is committed to maintaining best practices for ensuring security, availability, and confidentiality. Explore more about how we protect your data and our systems, and how we use regulatory and compliance frameworks to safeguard your data privacy. Understand how Honeycomb protects your data and secures its infrastructure, integrations, and connections. Report security vulnerabilities to Honeycomb through our bug bounty program. Learn what's in scope, how to submit a report, and how rewards are determined. Understand how Honeycomb keeps your data private and complies with regulatory and compliance frameworks. Learn how Honeycomb approaches AI feature development, what data Honeycomb Intelligence features use, and how to control AI features for your team. # Honeycomb AI Policies Source: https://docs.honeycomb.io/security-compliance/ai-policies Learn how Honeycomb approaches AI feature development, what data Honeycomb Intelligence features use, and how to control AI features for your team. **Last updated:** March 16, 2026 ## Overview Honeycomb provides this notice to describe our approach to developing artificial intelligence (AI) features and to answer frequently asked questions about [Honeycomb Intelligence](/get-started/honeycomb/honeycomb-intelligence), a suite of AI features available through our service. ## Our AI principles We believe AI can meaningfully improve our services and customer experience. As we develop and deploy AI-based features, we are committed to the following principles: * **Use AI where it makes sense**: We develop AI features to enhance our products and services in places where AI can uniquely benefit them. * **Be transparent**: We scope AI features to their purpose and disclose their limitations. We do not claim capabilities that are impossible or unreasonable to perform. We make it clear when you are interacting with an AI feature and how it is being used. * **Ensure fairness and inclusivity**: We design AI features to avoid bias and discrimination, and to be useful and accessible to all. * **Maintain reliability and safety**: We design AI features to function reliably and safely. We monitor and address unreliable behaviors when they arise, including potentially removing a feature if it is deemed too problematic. * **Protect privacy and security**: We design AI features to meet the same privacy and security standards as our other product functionality, so you can trust us with your data. * **Be accountable**: We monitor AI features on an ongoing basis to ensure goals are met. We track and remediate issues when they arise. ## Honeycomb Intelligence features The following table describes the current Honeycomb Intelligence features, the model providers each feature uses, and how each feature interacts with your data. | Feature | Description | Model Providers | Data Interaction | | ----------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | Honeycomb Canvas | AI-guided workspace inside Honeycomb that combines an AI assistant with an interactive notebook for visualizing query results and traces. | OpenAI, AWS Bedrock | Uses user-provided text, dataset/environment schema information, and sample telemetry values to create, read, and update Honeycomb queries and any entity within Honeycomb. | | Honeycomb MCP | Interface for your Honeycomb telemetry in any client application that connects to the Honeycomb MCP. | Client-dependent/user-controlled model provider | Uses user-provided text, dataset/environment schema information, and sample telemetry values to create, read, and update Honeycomb queries and any entity within Honeycomb. | | Query Assistant | Textual interface that helps users create runnable Honeycomb queries. | OpenAI, AWS Bedrock | Uses user input, dataset/environment schema information, and sample telemetry values to produce runnable Honeycomb queries. | | AI Assisted Calculated Fields | Text-to-expression UI that helps users create valid Calculated Field expressions. | OpenAI, AWS Bedrock | Uses user input, dataset/environment schema information, and sample telemetry values to produce valid Calculated Fields. | | BubbleUp Insights | Surfaces a plain-language summary and ranked list of fields that differ most between a BubbleUp selection and the baseline. | AWS Bedrock | Uses query results, dataset/environment schema information, and sample telemetry values to compare a BubbleUp selection against the baseline and produce a plain-language summary and ranked table of fields with insights and severity ratings. | ## FAQ ### Is the use of Honeycomb Intelligence optional? Yes. Team Owners can enable or disable Honeycomb Intelligence at the Team level at any time. To learn how to enable or disable Honeycomb Intelligence for your Team, visit [Manage Team Behavior](/configure/teams/manage-behavior). ### Are any AI features activated even if I have Honeycomb Intelligence disabled? No. While some AI features may activate passively to surface insights proactively, all AI features are governed by the Team-level AI settings. ### Are there limits on use of Honeycomb Intelligence? Not at the moment. We may place limits in the future for some Honeycomb Intelligence features to mitigate costs or prevent misuse and abuse. These limits may change over time. ### Do Honeycomb Intelligence features use generative AI exclusively? No. Honeycomb also uses statistical and deterministic models to power some features, such as Anomaly Detection. ### Will the data I input to Honeycomb Intelligence be used to train machine learning models? Honeycomb does not use any AI model providers that train foundation models based on input. We may fine-tune pre-trained models to provide a better product offering. Other machine learning systems may require training a different kind of machine learning model on a per-Team basis, or performing a fit operation (training a model on your Team's data specifically) for a statistical model. ### Are any Honeycomb Intelligence features able to process protected health information or other sensitive data? Yes. Teams with a Business Associate Agreement (BAA) are eligible for Honeycomb Intelligence. For more information, contact your Account Manager and review our [Supplemental Terms](https://www.honeycomb.io/ai-terms). ### Do all Honeycomb Intelligence model providers process personal data as a subprocessor? In some cases, we use offline models, where the underlying model provider does not process or otherwise have access to any input data. In other cases, we may use online models, where the AI model provider may serve as a subprocessor. Where an AI model provider used by Honeycomb may receive personal data on a subprocessor basis, Honeycomb adds that provider to its [subprocessor list](https://www.honeycomb.io/subprocessors). ### What offline models are you using? The offline models we use are self-hosted through AWS Bedrock, so the underlying model provider does not have access to your data. ### Does Honeycomb Intelligence use multiple models at the same time? Yes. We regularly test newly released models from our model providers to evaluate their efficacy. A given Honeycomb Intelligence feature may call multiple different models, sometimes from different model providers. ### Does Honeycomb Intelligence support multi-modality (image, audio) inputs and outputs? Not currently. We may add support for multi-modality inputs and outputs in the future. # Bug Bounty & Vulnerability Research Program Source: https://docs.honeycomb.io/security-compliance/bug-bounty-program Report security vulnerabilities to Honeycomb through our bug bounty program. ## Overview Honeycomb welcomes responsible disclosure of security vulnerabilities. This page covers the core terms of our bug bounty program. Where the circumstances require interpretation or judgment, we apply our discretion based on the situation and your conduct. ## In scope This program covers security vulnerabilities affecting services provided by us at `ui.honeycomb.io` and `api.honeycomb.io`, including: * Web application vulnerabilities, such as XSS, CSRF, SQLi * Authentication issues * Authorization issues * Remote code execution ## Out of scope The following are not covered by this program, regardless of any in-scope coverage indicated above: * Any issues related to `www.honeycomb.io`, `docs.honeycomb.io`, or `info.honeycomb.io` * Social engineering * Out-of-date browsers and plugins * Vulnerabilities in third-party applications that don't directly affect Honeycomb's data or services * Issues already known to us or previously reported by others * Issues we've determined to be of acceptable risk ## Ineligible activities The following activities are out of scope, ineligible for a reward, and may result in an IP ban from our services and removal from the program: * Denial of service (DoS) attacks, or any action that generates excessive traffic * Testing rate limiting * Using automated tooling in a way that generates excessive traffic * Spam of any kind * Engaging with our support team as part of your report ## Non-qualifying vulnerabilities We don't award rewards for vulnerabilities that are trivial or broadly applicable across services, including: * Lack of password length restrictions * Demonstrating that a page can be iFramed without identifying a clickjackable link on that page * Self-XSS * Vulnerabilities that require privileged access to the victim's device, such as a rooted phone * User existence or enumeration vulnerabilities * Password complexity requirements * Insecure cookie settings for non-sensitive cookies * Bugs that require highly unlikely user interaction to exploit * Reports from automated tools or scans without an accompanying demonstration of exploitability * Text-only injection in error pages * Automatic hyperlink construction by third-party email providers * Using email mutations (`+`, `.`, etc.) to create multiple accounts from a single email address ## Researcher responsibilities We work with researchers who follow responsible disclosure practices. To participate, you must: * Allow us reasonable time to investigate and mitigate an issue before disclosing or sharing it with others. * Not interact with other users or accounts without their explicit, informed consent. * Avoid all privacy violations and any disruption of service to other users and accounts. * Not exploit any security risk you discover, including through additional demonstrations of the same risk. * Comply with all applicable laws and regulations. * Submit reports that clearly demonstrate applicability to Honeycomb's tools, systems, or infrastructure. * Provide your real name, proof of identity if requested, and a non-cash payment method. ## Submitting a report Send your report to `security@honeycomb.io`. Reports submitted via **BCC** are not accepted. Include the substance of your report directly in your email body. We don't accept reports that provide vulnerability details in a PDF or other attached document. Attach only supporting evidence, such as screenshots or screen recordings. ## Rewards All rewards are at our discretion. We aim to align reward amounts with the severity of the reported vulnerability and appreciate the time and effort responsible researchers invest. # Compliance & Data Privacy Source: https://docs.honeycomb.io/security-compliance/compliance-data-privacy Find out which compliance frameworks and certifications Honeycomb maintains, how your data stays private, and how to access Honeycomb's Trust Center. ## Overview Honeycomb is committed to maintaining best practices for ensuring security, availability, and confidentiality, so we maintain and meet the requirements for multiple compliance frameworks and certifications. Our product and services are vetted by independent security professionals, and we give our customers the right to audit. To learn more, visit our [Terms of Service on honeycomb.io](https://www.honeycomb.io/terms). For enterprise customers, we also provide [activity logging](/configure/teams/investigate-activity/), which allows you to see who or what caused changes to specific resource configurations. To view a full list of certifications and compliance, visit our [Honeycomb Trust Center](https://trust.honeycomb.io/). ## Regulatory frameworks Honeycomb complies with various regulatory frameworks that exist on national and international levels. ### GDPR Honeycomb is GDPR compliant, and we offer a standard data processing agreement through our Terms of Service. For enterprise customers who have compliance requirements under GDPR, we will also enter into a more comprehensive data processing agreement. Customers may choose a US-based or an EU-based location where Honeycomb will store the data they send. Customers can access the US data location via `https://ui.honeycomb.io` (for the UI) and `https://api.honeycomb.io` (for the API). Customers can access the EU location at `https://ui.eu1.honeycomb.io` (for the UI) and `https://api.eu1.honeycomb.io` (for the API). Unlike some other vendors, Honeycomb only has access to the telemetry data that customers send. To learn how to avoid sending PII via OpenTelemetry, visit [Scrubbing Sensitive Information](/send-data/opentelemetry/collector/#scrubbing-sensitive-information). To learn how to mask PII using the OpenTelemetry Collector, visit [Securing the OpenTelemetry Collector](/send-data/opentelemetry/collector/handle-sensitive-information/). If you would like to learn more about what type of data we collect, why we collect data, and how we use the data we collect, visit the [Honeycomb Privacy Policy on honeycomb.io](https://www.honeycomb.io/privacy). To learn about our subprocessors, visit [Honeycomb Subprocessors on honeycomb.io](https://www.honeycomb.io/subprocessors/). To make a GDPR rights request, email [support@honeycomb.io](mailto:support@honeycomb.io). To learn more about GDPR, visit [General Data Protection Regulation on gdpr-info.eu](https://gdpr-info.eu/). ### HIPAA/HITECH As defined by the US HIPAA and HITECH legislation, Honeycomb is considered a Business Associate. We will sign a Business Associate Agreement (BAA) with Pro/Enterprise customers who have compliance requirements under HIPAA/HITECH. Honeycomb security controls are specifically designed for customers dealing with sensitive data like PHI. To reduce PHI transfer, we also strongly encourage customers to replace names and emails with an obfuscated external ID number. To learn more about HIPAA, visit [Health Information Privacy on hhs.gov](https://www.hhs.gov/hipaa/index.html). To learn more about HITECH, visit [HITECH Act Enforcement Final Rules on hhs.gov](https://www.hhs.gov/hipaa/for-professionals/special-topics/hitech-act-enforcement-interim-final-rule/index.html). ### PCI DSS Honeycomb is PCI DSS compliant as a merchant. We process customer payments securely through a well-known payment processor and complete a Self Assessment Questionnaire (SAQ) and Attestation of Compliance (AOC) annually. Honeycomb as a service is not intended to process payment card information for customers. If you need to send payment card data to Honeycomb, contact your account team to discuss your use case. ## Compliance Frameworks Honeycomb voluntarily conforms to additional compliance frameworks to ensure we evolve robust processes and establish a strong security posture. ### SOC 2 Type II Every year, Honeycomb undergoes an independent audit for our SOC 2 Type II report, which verifies our consistent application of the AICPA trust principles. We can provide a copy of our SOC 2 report upon request to customers who have agreed to our Terms of Service. As part of our SOC 2 program, we regularly undergo penetration testing by an independent security firm and can provide a summary to customers as required. To learn more about SOC 2 Type II, visit [SOC 2® - SOC for Service Organizations: Trust Services Criteria on aicpa-cima.com](https://www.aicpa-cima.com/topic/audit-assurance/audit-and-assurance-greater-than-soc-2). ### CSA STAR Level 1 Honeycomb completes a CSA Consensus Assessments Initiative Questionnaire (CAIQ) annually and can provide a copy of our CAIQ to Pro/Enterprise users upon request. To learn more about CSA Star, visit [Security, Trust, Assurance and Risk (STAR) at cloudsecurityalliance.org](https://cloudsecurityalliance.org/star/). ### ISO/IEC 27001 Honeycomb provides its services in ISO/IEC 27001 certified environments, including Amazon Web Services (AWS) and Google Cloud Platform (GCP). Honeycomb reviews Amazon and GCP on an annual basis to confirm their ongoing adherence to ISO/IEC 27001 controls. To see details of AWS's ISO/IEC 27001 certification, visit [ISO/IEC 27001:2013 on aws.amazon.com](https://aws.amazon.com/compliance/iso-27001-faqs/). To see details about GCP's ISO/IEC 27001 certification, visit [ISO/IEC 27001 at cloud.google.com](https://cloud.google.com/security/compliance/iso-27001). To learn more about ISO 27001, visit [ISO/IEC 27001 on iso.org](https://www.iso.org/standard/27001). ### Amazon Web Services (AWS) Foundational Technical Review As an Amazon Web Services (AWS) Partner, Honeycomb conducts a self-service review every three years to guarantee that we reduce risks around security, reliability, and operational excellence by following AWS best practices specific to our product. ## Ethics and whistleblower hotline Honeycomb uses Safe Hotline, Inc for its ethics and whistleblower hotline. To raise an issue or concern anonymously: * Call the toll-free phone number 1-855-662-SAFE (1-855-662-7233), or * Submit a report at [SAFEHOTLINE.COM](https://safehotline.com/). Include Honeycomb's Company ID number **8108427380** in your report. # Security & Data Protection Source: https://docs.honeycomb.io/security-compliance/security-data-protection Find out how Honeycomb encrypts data at rest and in transit, manages access controls, handles deletions, and secures its infrastructure and integrations. ## Overview Honeycomb is a secure product. To learn more about our certifications and compliance, visit our [Honeycomb Trust Center](https://trust.honeycomb.io/). ## How we secure your data * All data is encrypted at rest and in transit. * We delete data as it exceeds your retention window (60 days for most customers). * You can delete datasets at any time. For more fine-grained deletion (a single column, for instance) contact Support via [support.honeycomb.io](https://support.honeycomb.io/), or email at [support@honeycomb.io](mailto:support@honeycomb.io). * Your API Keys authenticate data ingestion. * A team owner can create, enable, and disable API keys for each environment in their team. * There is a limit of 100 API keys per team. This can be increased by request through Support via [support.honeycomb.io](https://support.honeycomb.io/), or email at [support@honeycomb.io](mailto:support@honeycomb.io). * If you send data using a disabled or invalid API Key, our API server will reject your events. ## How we secure our infrastructure * The Honeycomb network is architected using modern best practices for tunneling, separate VPCs, encryption at rest and in transit. * All storage nodes are unreachable from the internet. * Only web services (API, UI) are reachable from the internet at all, and then only through ELB TLS ports. * Nothing is transmitted unencrypted over public networks. * Our entire infrastructure is auto-scalable, which lets us roll our entire infrastructure in \~60 minutes (\~10 minutes for our forward-facing web nodes) when critical security patches are released. ## How we secure our integrations * Our various integrations (agents and SDKs) do not run as root and cannot be controlled remotely. * [OpenTelemetry](/send-data/opentelemetry/) sends encrypted traffic by default. * All our integrations are 100% open-source so you can examine them to your heart's content. ## AWS PrivateLink For [Honeycomb Enterprise](https://www.honeycomb.io/try-honeycomb-enterprise-for-free/) users with services hosted on AWS, we provide an [AWS PrivateLink connection](/integrations/aws-privatelink/) to the Honeycomb API. This may help limit data egress and make network security configuration more straightforward. # Send Data to Honeycomb: Overview Source: https://docs.honeycomb.io/send-data Instrument your applications or infrastructure and send telemetry to Honeycomb. Start with OpenTelemetry or connect a pre-instrumented system. To send data to Honeycomb, you will need to instrument your applications or infrastructure. If you are instrumenting code for the first time, we recommend using OpenTelemetry. Honeycomb supports receiving telemetry data via OpenTelemetry's native protocol, [OTLP](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/otlp.md), over gRPC, HTTP/protobuf, and HTTP/JSON. The minimum supported versions of OTLP [protobuf definitions](https://github.com/open-telemetry/opentelemetry-proto) are 1.0 for traces, metrics, and logs. ## Pre-Instrumented Systems If your system is instrumented with OpenTelemetry, you can send OpenTelemetry Protocol (OTLP) data directly to Honeycomb: [Set the OTLP exporter to point to Honeycomb](/send-data/opentelemetry/#using-the-honeycomb-opentelemetry-endpoint). If a system is already instrumented with OpenTracing, Zipkin, or Jaeger, you can convert your data and export it using the [OpenTelemetry Collector](/send-data/opentelemetry/collector/). ## Instrument Your Infrastructure Get visibility into your infrastructure by sending its telemetry to Honeycomb. * [Kubernetes](/send-data/kubernetes/) * [AWS integrations](/send-data/aws/) for logs and metrics * [AWS Cloudwatch](/integrations/metrics/aws-cloudwatch/) * [AWS Lambda](/send-data/aws/lambda/) * [Fastly](/integrations/logs/fastly/) logs * [Fluentd](/integrations/logs/fluentd/) logs * [Logstash](/integrations/logs/logstash/) logs * [Prometheus](/integrations/metrics/prometheus/) client metrics * [HashiCorp Consul](/integrations/metrics/hashicorp-consul/) metrics * [HashiCorp Nomad](/integrations/metrics/hashicorp-nomad/) metrics * [HashiCorp Vault](/integrations/metrics/hashicorp-vault/) metrics ### CI/CD [Instrument your build pipelines with Honeycomb `buildevents`](/integrations/build-pipelines/), a small binary you can integrate into continuous integration/continuous delivery services. `buildevents` supports these platforms: * Travis CI * CircleCI * GitLab CI * Buildkite * Jenkins X * Google Cloud Build * GitHub Actions * Bitbucket Pipelines ### Service Meshes and API Gateways Use an OpenTelemetry Collector to collect traces from Ambassador, AWS App Mesh, Istio, or Kong and export them to Honeycomb. * [Send Data from Service Meshes and API Gateways](/integrations/traces/service-meshes-api-gateways/) ## Instrument Your Application Instrument your application with OpenTelemetry by following the tutorials listed below. * [Browser (JavaScript)](/send-data/android/) * [Android](/send-data/android/) * [iOS](/send-data/ios) * [React Native](/send-data/react-native/) * [Go](/send-data/go/opentelemetry-sdk/) * [Java](/send-data/java/opentelemetry-agent/) * [.NET](/send-data/dotnet/) * [Node.js](/send-data/javascript-nodejs/opentelemetry-sdk/) * [Python](/send-data/python/opentelemetry-sdk/) * [Ruby](/send-data/ruby/opentelemetry-sdk/) If your programming language is not listed above, you can [set the OTLP exporter to point to Honeycomb](/send-data/opentelemetry/#using-the-honeycomb-opentelemetry-endpoint) in your language's SDK. You can browse the available OpenTelemetry instrumentation SDKs on the [OpenTelemetry Registry](https://opentelemetry.io/registry/). ## OpenTelemetry Alternatives Although we highly recommend using OpenTelemetry for instrumentation and export to Honeycomb, sometimes this is not possible. ### Libhoney The Honeycomb API has an [Events endpoint](/api/events/) for sending events as JSON objects to Honeycomb. The Events API is unrelated to OpenTelemetry and the OTLP format. Libhoney, a suite of helper libraries for sending your events to Honeycomb via the Events API, is available for the following languages: * [Go](/send-data/go/libhoney/) * [Java](/send-data/java/libhoney/) * [JavaScript](/send-data/javascript-nodejs/libhoney/) * [Python](/send-data/python/libhoney/) * [Ruby](/send-data/ruby/libhoney/) For other languages, [see our community contribution repository](https://github.com/honeycombio/third-party-contrib). ### Honeytail Honeytail is an agent for ingesting log data into Honeycomb. It has built-in parsers for logs generated by ArangoDB, MongoDB, MySQL, PostgreSQL, and nginx. It also supports parsing common formats such as JSON, CSV, syslog, and keyval as well as parsing logs with custom regular expressions. * [Send Structured Logs with Honeytail](/send-data/logs/structured/honeytail/) * [Honeytail Github Repo](https://github.com/honeycombio/honeytail) # Send Android Data to Honeycomb Source: https://docs.honeycomb.io/send-data/android Instrument your Android application with the Honeycomb OpenTelemetry Android SDK and send telemetry to Honeycomb to monitor real device performance. The [Honeycomb OpenTelemetry Android SDK](https://github.com/honeycombio/honeycomb-opentelemetry-android) is Honeycomb's [OpenTelemetry Android](https://github.com/open-telemetry/opentelemetry-android) distribution. It simplifies adding instrumentation to your Android applications and sending telemetry to Honeycomb. This page briefly covers usage of the SDK. If you just want to see some code, check out the [examples on GitHub](https://github.com/honeycombio/honeycomb-opentelemetry-android/tree/main/example). ## Before You Begin Before you can add instrumentation to your Android application, you will need to do a few things. ### Get Your Honeycomb API Key To send data to Honeycomb, you need to: 1. Sign up for a Honeycomb account. To sign up, decide whether you would like Honeycomb to store your data in a US-based or EU-based location, then [create a Honeycomb account in the US](https://ui.honeycomb.io/signup) or [create a Honeycomb account in the EU](https://ui.eu1.honeycomb.io/signup). 2. [Create a Honeycomb Ingest API Key](/configure/environments/manage-api-keys/#create-api-key). To get started, you can create a key that you expect to swap out when you deploy to production. Name it something helpful, perhaps noting that it's a Getting Started key. Make note of your API key; for security reasons, you will not be able to see the key again, and you will need it later! For setup, make sure you select the "Can create datasets" checkbox so that your data will show up in Honeycomb. Later, when you replace this key with a permanent one, you can uncheck that box. ### Install the Honeycomb Android SDK Add the Honeycomb and OpenTelemetry Android SDKs to your application's `build.gradle.kts`. When adding OpenTelemetry dependencies, make sure [the library is compatible with the Honeycomb Android SDK](https://github.com/honeycombio/honeycomb-opentelemetry-android/?tab=readme-ov-file#honeycomb-opentelemetry-android). ```kotlin theme={} dependencies { implementation("io.opentelemetry.android:android-agent:0.11.0-alpha") implementation("io.honeycomb.android:honeycomb-opentelemetry-android:0.0.20") } ``` If your application's `minSDK` is lower than 26, enable [corelib desugaring](https://developer.android.com/studio/write/java8-support#library-desugaring): ```kotlin theme={} android { // ... compileOptions { isCoreLibraryDesugaringEnabled = true sourceCompatibility = JavaVersion.VERSION_1_8 targetCompatibility = JavaVersion.VERSION_1_8 } kotlinOptions { jvmTarget = "1.8" } } dependencies { coreLibraryDesugaring(libs.desugar.jdk.libs) } ``` If your application's `minSdk` is lower than 24, running instrumentation tests or debug application builds requires that you: * Use [Android Gradle Plugin (AGP) 8.3.0+](https://developer.android.com/build/releases/gradle-plugin#updating-plugin) * Add `android.useFullClasspathForDexingTransform=true` to your `gradle.properties`. ## Configuration | Option | Description | | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | apiKey | `String`
Your [Honeycomb Ingest API Key](/configure/environments/manage-api-keys/#create-api-key).
**Required** if sending telemetry directly to Honeycomb. | | tracesApiKey | `String`
Ingest API Key to use when sending traces. Overrides `apiKey` for traces. | | metricsApiKey | `String`
Ingest API Key to use when sending metrics. Overrides `apiKey` for metrics. | | logsApiKey | `String`
Ingest API Key to use when sending logs. Overrides `apiKey` for logs. | | dataset | `String`
Name of the [dataset](/configure/datasets/manage/) to send telemetry data to.
**Required** if using Honeycomb Classic. | | metricsDataset | `String`
Name of the dataset to send metrics to. Overrides `dataset` for metrics. | | apiEndpoint | `String`
Telemetry is sent to this URL. For Honeycomb EU instances, set this to `https://api.eu1.honeycomb.io:443`. If you're using an OpenTelemetry Collector, provide your collector URL instead.
Default: `https://api.honeycomb.io:443` (US instance) | | tracesEndpoint | `String`
API endpoint to send traces to. | | metricsEndpoint | `String`
API endpoint to send metrics to. | | logsEndpoint | `String`
API endpoint to send logs to. | | spanProcessor | `io.opentelemetry.sdk.trace.SpanProcessor`
Additional span processor to use. | | sampleRate | `Int`
Sample rate to apply. For example, a `sampleRate` of `40` means 1 in 40 traces will be exported.
Default: `1` | | debug | `Boolean`
Whether to enable debug logging.
Default: `false`. | | serviceName | `String`
The name of your application. Used as the value for `service.name` resource attribute.
Default: `"unknown_service"` | | serviceVersion | `String`
Current version of your application. Used as the value for `service.version` resource attribute. | | resourceAttributes | `Map`
Attributes to attach to outgoing resources. | | headers | `Map`
Headers to add to exported telemetry data. | | tracesHeaders | `Map`
Headers to add to exported trace data. | | metricsHeaders | `Map`
Headers to add to exported metrics data. | | logsHeaders | `Map`
Headers to add to exported logs data. | | timeout | `Duration`
Timeout used by exporter when sending data.
Default: `Duration = 10.seconds` | | tracesTimeout | `Duration`
Timeout used by traces exporter. Overrides `timeout` for trace data. | | metricsTimeout | `Duration`
Timeout used by metrics exporter. Overrides `timeout` for metrics data. | | logsTimeout | `Duration`
Timeout used by logs exporter. Overrides `timeout` for logs data. | | protocol | `OtlpProtocol`
Protocol to use when sending data.
Can be one of: `OtlpProtocol.GRPC`, `OtlpProtocol.HTTP_PROTOBUF`, `OtlpProtocol.HTTP_JSON`.
Default: `OtlpProtocol.HTTP_PROTOBUF` | | tracesProtocol | `OtlpProtocol`
Overrides `protocol` for trace data. | | metricsProtocol | `OtlpProtocol`
Overrides `protocol` for metrics data. | | logsProtocol | `OtlpProtocol`
Overrides `protocol` for logs data. | | offlineCachingEnabled | `Boolean`
Enable offline caching for telemetry. When offline caching is enabled, telemetry is cached during network failures. The SDK will retry exporting telemetry for up to 18 hours. Offline caching also adds a minimum delay of 30 seconds to telemetry exports.
**Offline caching is an alpha feature and may be unstable.**
Default: `false` | ### Sending to OpenTelemetry Collector In production, we recommend running an [OpenTelemetry Collector](/send-data/opentelemetry/collector/). Your application sends telemetry to your Collector instead of directly to Honeycomb. Your Collector then forwards the telemetry data to Honeycomb, keeping your API key stored securely in the Collector's configuration. Call `setApiEndpoint()` with your Collector's URL when initializing the SDK: ```kotlin theme={} import io.honeycomb.opentelemetry.android.Honeycomb import io.honeycomb.opentelemetry.android.HoneycombOptions import io.opentelemetry.android.OpenTelemetryRum class ExampleApp: Application() { var otelRum: OpenTelemetryRum? = null override fun onCreate() { super.onCreate() val options = HoneycombOptions.builder(this) .setApiEndpoint("http(s)://YOUR-COLLECTOR-URL") .setServiceName("YOUR-SERVICE-NAME") .setServiceVersion("0.0.1") .build() otelRum = Honeycomb.configure(this, options) } } ``` ### Sending to Honeycomb To send telemetry data directly to Honeycomb, call `setApiKey()` with your [Ingest API Key](/configure/environments/manage-api-keys/#create-api-key) value. ```kotlin theme={} import io.honeycomb.opentelemetry.android.Honeycomb import io.honeycomb.opentelemetry.android.HoneycombOptions import io.opentelemetry.android.OpenTelemetryRum class ExampleApp: Application() { var otelRum: OpenTelemetryRum? = null override fun onCreate() { super.onCreate() val options = HoneycombOptions.builder(this) // Uncomment the line below to send to EU instance. Defaults to US. // .setApiEndpoint("https://api.eu1.honeycomb.io:443") .setApiKey("YOUR-API-KEY") .setServiceName("YOUR-SERVICE-NAME") .setServiceVersion("0.0.1") .build() otelRum = Honeycomb.configure(this, options) } } ``` ### Add Resource Attributes Resource attributes are available on every span your instrumentation emits. Adding custom, application-specific attributes makes it easier to correlate your data to important business information. You can add extra resource attributes during SDK configuration with the `.setResourceAttributes()` method. ```kotlin theme={} import android.app.Application import io.honeycomb.opentelemetry.android.Honeycomb import io.honeycomb.opentelemetry.android.HoneycombOptions import io.opentelemetry.android.OpenTelemetryRum class ExampleApp: Application() { var otelRum: OpenTelemetryRum? = null override fun onCreate() { super.onCreate() val options = HoneycombOptions.builder(this) .setApiKey("YOUR-API-KEY") .setServiceName("YOUR-SERVICE-NAME") .setServiceVersion("0.0.1") .setResourceAttributes(mapOf("app.ab_test" to "test c")) .setDebug(true) .build() otelRum = Honeycomb.configure(this, options) } } ``` ### Enable Sampling The Honeycomb Android SDK includes optional [deterministic head sampling](/manage-data-volume/sample/). To enable sampling, call `.setSampleRate()` with your desired sample rate as an `Int` value. The sample rate is `1` by default, meaning every trace is exported. The example below sets a `sampleRate` of `40`, meaning 1 in 40 traces will be exported. ```kotlin theme={} // ... val options = HoneycombOptions.Builder(this) .setApiKey("YOUR-API-KEY") .setServiceName("YOUR-SERVICE-NAME") .setServiceVersion("0.0.1") .setSampleRate(40) .setDebug(true) .build() // ... ``` ## Add Automatic Instrumentation Enable all OpenTelemetry auto-instrumentations by including the OpenTelemetry [android-agent](https://github.com/open-telemetry/opentelemetry-android): ```kotlin theme={} dependencies { implementation("io.opentelemetry.android:android-agent:0.11.0-alpha") implementation("io.honeycomb.android:honeycomb-opentelemetry-android:0.0.20") } ``` If you don't need all of them, you can instead add dependencies for each instrumentation you want to include: * [Activity navigation](https://github.com/open-telemetry/opentelemetry-android/tree/main/instrumentation/activity): `io.opentelemetry.android:instrumentation-activity` * [Application Not Responding (ANR)](https://github.com/open-telemetry/opentelemetry-android/tree/main/instrumentation/anr): `io.opentelemetry.android:instrumentation-anr` * [Crash (uncaught exception)](https://github.com/open-telemetry/opentelemetry-android/tree/main/instrumentation/crash): `io.opentelemetry.android:instrumentation-crash` * [Fragment navigation](https://github.com/open-telemetry/opentelemetry-android/tree/main/instrumentation/fragment): `io.opentelemetry.android:instrumentation-fragment` * [Slow Rendering](https://github.com/open-telemetry/opentelemetry-android/tree/main/instrumentation/slowrendering): `io.opentelemetry.android:instrumentation-slowrendering` * [UI interactions](https://github.com/honeycombio/honeycomb-opentelemetry-android/tree/main/interaction): `io.honeycomb.android:honeycomb-opentelemetry-android-interaction` ## Custom Instrumentation Automatic instrumentation is a fast way to instrument your code, but you get more insight into your application by adding custom, or manual, instrumentation. To add your own custom instrumentation, import the OpenTelemetry API in to your application. ```kotlin theme={} import io.opentelemetry.api.OpenTelemetry ``` ### Add Attributes to an Active Span You can retrieve the currently active span in a trace and add attributes to it. This lets you add more context to traces and gives you more ways to group or filter traces in your queries: ```kotlin theme={} import io.opentelemetry.api.OpenTelemetry import io.opentelemetry.api.trace.Span import io.opentelemetry.api.common.Attributes fun applyDiscountCode(discountCode: String) { val currentSpan = Span.current() currentSpan.setAttribute("app.cart.discount_code", discountCode) } ``` In the above example, we add an `app.cart.discount_code` attribute to the current span. This lets us use the `app.cart.discount_code` field in `WHERE` or `GROUP BY` clauses in the Honeycomb query builder. ### Acquire a Tracer To create custom spans, you need to acquire a tracer: ```kotlin theme={} import io.opentelemetry.api.OpenTelemetry import io.opentelemetry.android.OpenTelemetryRum // ... val otelRum = app.otelRum as OpenTelemetryRum val tracer = otelRum.tracerProvider.tracerBuilder("my-application-tracer").build() ``` ### Create Spans Create custom spans to get a clear view of the critical parts in your application. ```kotlin theme={} import io.opentelemetry.api.OpenTelemetry import io.opentelemetry.api.common.Attributes import io.opentelemetry.android.OpenTelemetryRum // ... val otelRum = app.otelRum as OpenTelemetryRum val tracer = otelRum.tracerProvider.tracerBuilder("my-application-tracer").build() fun generateNewLevel() { val span = tracer.spanBuilder("newLevel").startSpan() // do some work span.end() } ``` ## Custom Span Processing Span processors provide hooks for when a span starts and when it ends. This lets you mutate spans after they have been created by automatic or manual instrumentation. Here's a basic example of a span processor that adds an attribute to spans when they start: ```kotlin theme={} import io.opentelemetry.context.Context import io.opentelemetry.sdk.trace.ReadWriteSpan import io.opentelemetry.sdk.trace.ReadableSpan import io.opentelemetry.sdk.trace.SpanProcessor class BasicSpanProcessor : SpanProcessor { override fun onStart( parentContext: Context, span: ReadWriteSpan, ) { span.setAttribute("app.metadata", "extra metadata") } override fun isStartRequired(): Boolean { return true } override fun onEnd(span: ReadableSpan) {} override fun isEndRequired(): Boolean { return false } } ``` Add the span processor as part of your SDK configuration to use it: ```kotlin theme={} // ... val options = HoneycombOptions.builder(this) .setApiKey("YOUR-API-KEY") .setServiceName("YOUR-SERVICE-NAME") .setSpanProcessor(BasicSpanProcessor()) .setServiceVersion("0.0.1") .setDebug(true) .build() // ... ``` ## Manual Context Propagation Kotlin Coroutines may operate across multiple threads, and do not automatically inherit the correct OpenTelemetry context. Instead, context must be propagated manually with the [OpenTelemetry Kotlin Extensions](https://github.com/open-telemetry/opentelemetry-java/tree/main/extensions/kotlin). ```kotlin theme={} dependencies { implementation("io.opentelemetry:opentelemetry-extension-kotlin:1.47.0") } ``` Once these are installed, replace any `launch` calls with ```kotlin theme={} launch(Span.current().asContextElement()) { // ... } ``` ## Troubleshooting To explore common issues when sending data, visit [Common Issues with Sending Data in Honeycomb](/troubleshoot/common-issues/sending-data/#opentelemetry-sdks-and-honeycomb-distributions). # Attributes in the Honeycomb OpenTelemetry Android SDK Source: https://docs.honeycomb.io/send-data/android/attributes Reference the standard attributes the Honeycomb OpenTelemetry Android SDK automatically adds to spans, covering environment, runtime, device, and SDK version data. When you instrument your application using the Honeycomb OpenTelemetry Android SDK, spans automatically include a standard set of attributes. These attributes provide essential context about the environment, runtime, device, and SDK versions--helping you understand where and how telemetry is being generated. ## Core Span Attributes Every span includes these attributes: * `device.manufacturer`: Device manufacturer, reported by [`android.os.Build.MANUFACTURER`](https://developer.android.com/reference/android/os/Build#MANUFACTURER). * `device.model.identifier`: Model of the device, reported by [`android.os.Build.MODEL`](https://developer.android.com/reference/android/os/Build#MODEL). * `device.model.name`: See `device.model.identifier`. * `honeycomb.distro.runtime_version`: Operating system version on the device. See also `os.version`. * `honeycomb.distro.version`: Version of the Honeycomb SDK in use. * `os.description`: String describing the Android version, build ID, and SDK level. * `os.name`: OS name. Always `android` for Android devices. * `os.type`: OS type. Always `linux` on Linux platforms. * `os.version`: Value of [`android.os.Build.VERSION.RELEASE`](https://developer.android.com/reference/android/os/Build.VERSION#RELEASE) * `rum.sdk.version`: Version of the OpenTelemetry Android SDK in use. * `screen.name`: Name of the current Activity or Fragment. * `service.name`: Name of your application. Set via `setServiceName()`. Defaults to `unknown_service`. * `service.version`: Version of your application. Set via `setServiceVersion()`. * `telemetry.sdk.language`: Coding language for the Honeycomb SDK in use. Always `android` for the Honeycomb OpenTelemetry Android SDK. * `telemetry.sdk.name`: Name of the telemetry SDK used to generate telemetry data. Always `opentelemetry` for the Honeycomb OpenTelemetry Android SDK. * `telemetry.sdk.version`: Version of the base OpenTelemetry SDK in use. ## Application Not Responding Attributes If you include the [application not responding instrumentation](https://github.com/open-telemetry/opentelemetry-android/tree/main/instrumentation/anr), then a span is created when the application becomes unresponsive. The span is named `ANR` and has this attribute: * `exception.stacktrace`: (String) A representation of the call stack of the main thread at the time of the application not responding. ## Crash Attributes If you include [crash instrumentation](https://github.com/open-telemetry/opentelemetry-android/tree/main/instrumentation/crash), a trace is emitted when an uncaught exception will terminate the application. The trace will be named `UncaughtException` and have these attributes: * `exception.name`: (String) Name of the exception that triggered the crash. * `exception.message`: (String) The exception message. * `exception.stacktrace`: (String) A representation of the call stack of the main thread at the time of the application crash. * `exception.escaped`: (Boolean) Indicates that the exception is escaping the scope of the span. * `thread.name`: (String) The current thread name. * `thread.id`: (Int) The current thread ID. ## Slow Rendering Attributes If you include [slow rendering instrumentation](https://github.com/open-telemetry/opentelemetry-android/tree/main/instrumentation/slowrendering), then a trace is emitted for slow or frozen renders. Slow renders are renders greater than 16ms and frozen renders are greater than 700ms. The traces will be named either `slowRenders` or `frozenRenders` and have this attribute: * `activity.name`: (String) Fully-qualified name of the Activity. For example: `"my.application.example/MainActivity"` ## Navigation Attributes If you include [activity instrumentation](https://github.com/open-telemetry/opentelemetry-android/tree/main/instrumentation/activity) or [fragment instrumentation](https://github.com/open-telemetry/opentelemetry-android/tree/main/instrumentation/fragment), then navigation between Activities and Fragments is tracked through the `screen.name` attribute added to spans. * `screen.name`: (String) Name of the current Activity or Fragment the user is viewing. # Symbolicate Android Stack Traces with the OpenTelemetry Collector Source: https://docs.honeycomb.io/send-data/android/symbolicate Use the Proguard processor in the OpenTelemetry Collector to replace obfuscated names in Android stack traces with readable symbols for easier debugging. Use the proguard processor in your OpenTelemetry Collector to symbolicate Android stack traces. The [proguard processor](https://github.com/honeycombio/opentelemetry-collector-symbolicator?tab=readme-ov-file#proguard-symbolication) replaces obfuscated names and addresses in your Android stack traces with symbols from provided Proguard files. ## Before You Start The proguard processor is compatible with [Honeycomb OpenTelemetry Android SDK](https://github.com/honeycombio/honeycomb-opentelemetry-android) version `0.0.20` and later. To use the proguard processor, you need: * OpenTelemetry Collector built with `CGO` enabled. * An environment or container image with `glibc` support. We recommend `gcr.io/distroless/cc`, a secure and lightweight container image with CGO and `glibc` support. If you're not using the Honeycomb OpenTelemetry Android SDK, make sure your exception data is in [the format the processor expects](https://github.com/honeycombio/opentelemetry-collector-symbolicator/blob/main/README.md#exception-information-format-2). ## Install By default, the [Honeycomb OpenTelemetry Collector distribution](https://github.com/honeycombio/honeycomb-collector-distro) includes the proguard processor, so you can skip to the next section if you're using it. If you use another collector distribution or build your own, it must be built with CGO enabled. You can install the proguard processor by adding it to your OpenTelemetry Collector build configuration file. ```yaml theme={} processors: - gomod: github.com/honeycombio/opentelemetry-collector-symbolicator/proguardprocessor v0.0.7 ``` You can find the latest proguard processor version on the [releases page](https://github.com/honeycombio/opentelemetry-collector-symbolicator/releases) in the GitHub repo. ## Proguard Files The proguard processor requires access to the Proguard file generated by your build process. This file can be stored in your local file system, Amazon S3, or Google Cloud Storage. To support symbolication, your Proguard file must be versioned with the generated build UUID in the file name. For example: `6A8CB813-45F6-3652-AD33-778FD1EAB196.txt`. You can use the [Honeycomb ProGuard UUID Plugin](https://github.com/honeycombio/honeycomb-opentelemetry-android/tree/main/honeycomb-proguard-uuid-plugin) to generate UUIDs in your build process. ## Configure a File Store Add the `proguard_symbolicator` as a processor in your OpenTelemetry Collector configuration: ```yaml theme={} processors: proguard_symbolicator: ``` You can then configure where your Proguard files are stored. By default, the proguard processor loads Proguard files from a local directory. You can set the file path in your collector configuration: ```yaml theme={} processors: proguard_symbolicator: # proguard_store is sets which store to use, in this case local disk proguard_store: file_store local_store: # (optional) path sets the base path of the files, defaults to `.` path: /tmp/proguards ``` Make sure your collector can access the `path` directory you set, and that file paths in stack traces match the structure of your configured file store. Optionally, you can load Proguard files from an Amazon S3 bucket. Add to your OpenTelemetry Collector configuration: ```yaml theme={} processors: proguard_symbolicator: # proguard_store sets which store to use, in this case S3 proguard_store: s3_store s3_store: # name of the bucket the files are stored in bucket: proguards-bucket # (optional) the bucket's region region: us-east-1 # (optional) prefix is used to nest the files in a sub key of the bucket prefix: proguards ``` Make sure your collector has permission to access the S3 bucket. Also, ensure the file paths in stack traces match the structure used in your file store. #### Private AWS S3 bucket authentication To use a private Amazon S3 bucket as your file store, set the `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` [environment variables](https://docs.aws.amazon.com/sdkref/latest/guide/environment-variables.html). Optionally, you can load Proguard files from a Google Cloud Storage (GCS) bucket. Add to your OpenTelemetry Collector configuration: ```yaml theme={} processors: proguard_symbolicator: # proguard_store sets which store to use, in this case GCS proguard_store: gcs_store gcs_store: # the name of the bucket the files are stored in bucket: proguards-bucket # (optional) prefix is used to nest the files in a sub key of the bucket prefix: proguards ``` Make sure your collector has permission to access the GCS bucket. Also, ensure the file paths in stack traces match the structure used in your file store. #### Private GCS bucket authentication To use a private Google Cloud Storage bucket as your file store, set the `GOOGLE_APPLICATION_CREDENTIALS` [environment variable](https://cloud.google.com/docs/authentication/application-default-credentials). ## Advanced Configuration In addition to basic setup, you can customize how the symbolicator processor handles stack traces by configuring attribute mappings and additional processing options. After updating the configuration file, restart the OpenTelemetry Collector to apply the changes. ### Mapping Attributes Use these configuration options to specify which attributes the processor should read from and write to when handling stack traces: | Config Key | Description | Default Value | | ------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | | `symbolicator_failure_attribute_key` | Signals if the the symbolicator fails to fully symbolicate the stack trace | `exception.symbolicator.failed` | | `symbolicator_error_attribute_key` | Stores the error message that caused the symbolication to fail | `exception.symbolicator.error` | | `symbolicator_parsing_method_attribute_key` | Indicates which parsing method was used: `"structured_stacktrace_attributes"` (SDK-provided structured attributes) or `"processor_parsed"` (collector-side parsing of raw stack trace) | `exception.symbolicator.parsing_method` | | `classes_attribute_key` | Which attribute should the classes of the stack trace be sourced from (structured route only) | `exception.structured_stacktrace.classes` | | `methods_attribute_key` | Which attribute should the methods of the stack trace be sourced from (structured route only) | `exception.structured_stacktrace.methods`. | | `lines_attribute_key` | Which attribute should the lines of the stack trace be sourced from (structured route only) | `exception.structured_stacktrace.lines` | | `source_files_attribute_key` | Which attribute should the source files of the stack trace be sourced from (structured route only) | `exception.structured_stacktrace.source_files` | | `stack_trace_attribute_key` | Which attribute should the raw stack trace be sourced from (collector-parsed route) and where the symbolicated stack trace will be written to (both routes) | `exception.stacktrace` | | `exception_type_attribute_key` | Which attribute should the exception type be sourced from. If using collector-side parsing, this will be populated from the parsed stack trace | `exception.type` | | `exception_message_attribute_key` | Which attribute should the exception message be sourced from. If using collector-side parsing, this will be populated from the parsed stack trace | `exception.message` | | `preserve_stack_trace` | After the stack trace has been symbolicated should the original values be preserved as attributes. Applies to both structured and collector-parsed routes | `true` | | `original_stack_trace_attribute_key` | If the stack trace is being preserved which key should the original raw stack trace be copied to (both routes) | `exception.stacktrace.original` | | `original_classes_attribute_key` | If the stack trace is being preserved which key should the classes be copied to (structured route only) | `exception.structured_stacktrace.classes.original` | | `original_methods_attribute_key` | If the stack trace is being preserved which key should the methods be copied to (structured route only) | `exception.structured_stacktrace.methods.original` | | `original_lines_attribute_key` | If the stack trace is being preserved which key should the lines be copied to (structured route only) | `exception.structured_stacktrace.lines.original` | | `original_source_files_attribute_key` | If the stack trace is being preserved which key should the source files be copied to (structured route only) | `exception.structured_stacktrace.source_files.original` | | `proguard_uuid_attribute_key` | Which resource or log attribute should the proguard UUID be sourced from. Required for both routes | `app.debug.proguard_uuid` | ### Additional Processing Options Use these configuration options to control how stack traces are processed and managed: | Config Key | Description | Example Value | | --------------------- | -------------------------------------------------------------------------------------------------------------------- | ------------- | | `timeout` | Max duration to wait to symbolicate a stack trace in seconds. | `5` | | `proguard_cache_size` | The maximum number of proguard files to cache. Reduce this if you are running into memory issues with the collector. | `128` | ### Language-Based Routing The Proguard processor supports language-based routing to ensure it only processes signals from Android/Java/Kotlin applications. This prevents the processor from running on signals from other platforms (like iOS or JavaScript), improving performance and avoiding unnecessary processing. | Config Key | Description | Default Value | Example Values | | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------- | ------------------------ | | `language_attribute_key` | The attribute key that contains the programming language or SDK language of the telemetry signal. | `telemetry.sdk.language` | `telemetry.sdk.language` | | `allowed_languages` | A list of language values that this processor will handle. If the signal's language attribute matches any value in this list, the processor will run. If empty (default), the processor will process all signals regardless of language. **Important:** When `allowed_languages` is configured, signals without a language attribute will be skipped. | `[]` (empty, processes all) | `["java", "kotlin"]` | **Example configuration:** ```yaml theme={} processors: proguard_symbolicator: allowed_languages: ["java", "android"] ``` `allowed_languages` configuration behavior: * Empty `allowed_languages` (default): Processes all signals, regardless of language attribute. * With `allowed_languages` configured: Only processes signals where the language attribute matches one of the allowed values (case-insensitive). * Missing language attribute: Skips processing when `allowed_languages` is configured. # Send Data from Amazon Web Services (AWS) Source: https://docs.honeycomb.io/send-data/aws Collect telemetry from AWS workloads, including Lambda, ECS, and other services, and send it to Honeycomb for analysis. Honeycomb AWS Integrations collect logs and metrics from AWS services. Send this data to Honeycomb and identify service impacts to your application's performance. To get started, use either AWS CloudFormation or HashiCorp Terraform to install your Honeycomb AWS Integrations. Set Up Honeycomb AWS Integrations with AWS CloudFormation. Set Up Honeycomb AWS Integrations with HashiCorp Terraform. ## Supported AWS Services Honeycomb AWS Integrations work with **all** services that send metrics or logs to AWS CloudWatch. For a full list of possible data sources, visit AWS documentation for services that [publish logs to CloudWatch Logs](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/aws-services-sending-logs.html) and [publish metrics to CloudWatch Metrics](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/aws-services-cloudwatch-metrics.html). The table below lists a selection of supported AWS services, and the types of data Honeycomb can collect from them. | Supported AWS Service | Logs | Metrics | | ---------------------------------------- | ---- | ------- | | Amazon API Gateway | ✔ | ✔ | | Amazon Athena | | ✔ | | Amazon AppSync | | ✔ | | Amazon Aurora | ✔ | ✔ | | AWS Autoscaling | | ✔ | | AWS Certificate Manager | | ✔ | | AWS CloudFront | ✔ | ✔ | | AWS CloudHSM | ✔ | ✔ | | AWS CloudTrail | ✔ | ✔ | | AWS CloudWatch | ✔ | ✔ | | AWS CodeBuild | ✔ | ✔ | | AWS CodeDeploy | ✔ | ✔ | | Amazon Cognito | ✔ | ✔ | | AWS Distro for OpenTelemetry | | | | Amazon DocumentDB | | ✔ | | Amazon DynamoDB | | ✔ | | AWS Elastic Beanstalk | ✔ | ✔ | | Amazon Elastic Block Store (EBS) | | ✔ | | Amazon Elastic Cloud Compute (EC2) | | ✔ | | Amazon Elastic Container Service (ECS) | ✔ | ✔ | | Amazon Elastic File System (EFS) | | ✔ | | Amazon Elastic Kubernetes Service (EKS) | ✔ | ✔ | | Elastic Load Balancing (ELB) | ✔ | ✔ | | Amazon ElastiCache | ✔ | ✔ | | Amazon Elastic Map Reduce (EMR) | | ✔ | | Amazon EventBridge | | ✔ | | AWS Fargate | ✔ | | | AWS Global Accelerator | | ✔ | | Amazon Key Management Service (KMS) | | ✔ | | Amazon Keyspaces | ✔ | ✔ | | Amazon Kinesis | | ✔ | | AWS Lambda | ✔ | ✔ | | Amazon Managed Streaming for Kafka | ✔ | ✔ | | Amazon MQ | ✔ | ✔ | | Amazon Neptune | | ✔ | | AWS Network Firewall | ✔ | ✔ | | AWS OpsWorks | ✔ | ✔ | | AWS PrivateLink | | ✔ | | AWS Redshift | | ✔ | | Amazon Relational Database Service (RDS) | ✔ | ✔ | | Amazon Route 53 | ✔ | ✔ | | AWS Secrets Manager | | ✔ | | Amazon Simple Email Service (SES) | | ✔ | | Amazon Simple Notification Service (SNS) | ✔ | ✔ | | Amazon Simple Queue Service (SQS) | | ✔ | | Amazon Simple Storage Service (S3) | ✔ | ✔ | | Amazon Simple Workflow Service (SWF) | | ✔ | | AWS Step Functions | ✔ | ✔ | | Amazon Timestream | | ✔ | | Amazon Virtual Private Cloud (VPC) | ✔ | ✔ | | AWS Web Application Firewall (WAF) | | ✔ | ## Other Way to Send Data from AWS Some additional ways of sending AWS data to Honeycomb include: * **AWS Distro for OpenTelemetry (ADOT)** - Because Honeycomb supports native OTLP ingest, you can send tracing data directly to Honeycomb. To learn more, visit the [ADOT Docs](https://aws-otel.github.io/docs/components/otlp-exporter#honeycomb). * **AWS Lambda** - Honeycomb supports receiving data from instrumented Lambda Layers. To learn more, visit [AWS Lambda](/send-data/aws/lambda/). * **AWS PrivateLink** - Honeycomb supports sending data through AWS PrivateLink. To learn more, visit [AWS PrivateLink](/integrations/aws-privatelink/). AWS PrivateLink connections are only available for [Honeycomb Enterprise plans](https://www.honeycomb.io/pricing/). * **AWS CloudWatch, Amazon S3, Amazon Kinesis, and AWS Lambda** - Honeycomb AWS integrations use a combination of these services to stream metrics and log data to Honeycomb. To learn more about Honeycomb's AWS integrations, visit [How AWS Integrations work](/send-data/aws/how-aws-integrations-work/). # Send Data from AWS via AWS CloudFormation Source: https://docs.honeycomb.io/send-data/aws/aws-cloudformation Set up Honeycomb's AWS integrations using AWS CloudFormation as your IaC method to provision the resources needed to send data to Honeycomb. Honeycomb AWS Integrations can be set up with [AWS CloudFormation](https://docs.aws.amazon.com/cloudformation/index.html) as your preferred Infrastructure-as-Code (IaC) method and deployment process. Honeycomb AWS Integrations utilize AWS CloudWatch, Amazon Kinesis, and AWS Lambda to send data to Honeycomb. Refer to [How AWS Integrations Work](/send-data/aws/how-aws-integrations-work/) to reference which AWS services use which methods. Note that standard AWS charges apply. Please refer to Amazon for specifics on associated egress costs. ## AWS CloudFormation Honeycomb provides a [CloudFormation template](https://github.com/honeycombio/cloudformation-integrations) to automate configuration of various AWS services to Honeycomb. Each integration has an independently deployable stack that the template deploys all together with the ability to turn functionality on and off as needed. Supported CloudFormation Integrations: * CloudWatch Logs * CloudWatch Metrics * RDS CloudWatch Logs * Amazon S3 Bucket Logs ### AWS CloudFormation Setup Choose from the available AWS [CloudFormation templates](https://github.com/honeycombio/cloudformation-integrations). Each integration option features a **Launch Stack** button and a list of required parameters or inputs during installation. We also offer a "quick start" AWS CloudFormation template that provides a streamlined path to integrate your AWS environments with Honeycomb. The quick start template uses all of the per-integration templates below to offer the configuration of many integrations in a single CloudFormation stack. The quick start template may be suitable for many production purposes, but we encourage you to use per-integration templates in a way that suits your AWS environment. If a misconfiguration happens during AWS CloudFormation installation, it is better to completely delete the CloudFormation stack and re-create it using the quick-create links. This AWS CloudFormation template allows the configuration of **multiple integrations** from a single CloudFormation Template. Select **Launch Stack** to start the install: Launch Stack #### Required Inputs Enter a value for the required input in the UI, or if using the CLI or API, ensure the inclusion of the required input and its value. * `HoneycombAPIKey`: Your Honeycomb Team's API Key. All other parameters are optional. If you provide no additional parameters, the template only creates an S3 Bucket. This AWS CloudFormation template integrates up to six **CloudWatch Log Groups** and ships them to a Honeycomb dataset. Select **Launch Stack** to start the install. Launch Stack #### Required Inputs Enter a value for each required input in the UI, or if using the CLI or API, ensure the inclusion of each required input and its value. * `HoneycombAPIKey`: Your Honeycomb Team's API Key. * `HoneycombDataset`: The target Honeycomb dataset for the Stream to publish to. * `LogGroupName`: A CloudWatch Log Group name. Additional Log Groups can be added with the `LogGroupNameX` parameters. * `S3FailureBucketArn`: The ARN of the S3 Bucket that will store any logs that failed to be sent to Honeycomb. This AWS CloudFormation template integrates all metrics flowing to **CloudWatch Metrics** and ships them to a Honeycomb dataset. Select **Launch Stack** to start the install. Launch Stack #### Required Inputs Enter a value for each required input in the UI, or if using the CLI or API, ensure the inclusion of each required input and its value. * `HoneycombAPIKey`: Your Honeycomb Team's API Key. * `S3FailureBucketArn`: The ARN of the S3 Bucket that will store any logs that failed to be sent to Honeycomb. This AWS CloudFormation template streams **RDS logs from CloudWatch** to a Kinesis Firehose that includes a data transform to **structure** the logs before it sends them to Honeycomb. Select **Launch Stack** to start the install. Launch Stack #### Required Inputs Enter a value for each required input in the UI, or if using the CLI or API, ensure the inclusion of each required input and its value. * `HoneycombAPIKey`: Your Honeycomb Team's API Key. * `HoneycombDataset`: The target Honeycomb dataset for the Stream to publish to. * `DBEngineType`: The Engine type of your RDS database. One of `aurora-mysql`, `aurora-postgresql` `mariadb`, `sqlserver`,`mysql`, `oracle`, or `postgresql`. * `LogGroupName`: A CloudWatch Log Group name for RDS logs. Additional Log Groups can be added with the `LogGroupNameX` parameters. * `S3FailureBucketArn`: The ARN of the S3 Bucket that will store any logs that failed to be sent to Honeycomb. This AWS CloudFormation template supports **sending logs from a S3 bucket** to Honeycomb. Select **Launch Stack** to start the install. Launch Stack #### Required Inputs Enter a value for each required input in the UI, or if you are using the CLI or API, make sure to include each required input and its value: * `HoneycombAPIKey`: Your Honeycomb Team's API Key. * `HoneycombDataset`: Target Honeycomb dataset to which you will publish. * `ParserType`: Type of log file to parse. Options include: `alb`, `elb`, `cloudfront`, `keyval`, `json`, `s3-access`, or `vpc-flow`. * `S3BucketArn`: ARN of the S3 Bucket storing the logs. # Send Data from AWS via HashiCorp Terraform Source: https://docs.honeycomb.io/send-data/aws/hashicorp-terraform Set up Honeycomb's AWS integrations using HashiCorp Terraform as your IaC method to provision the resources needed to send data to Honeycomb. Honeycomb AWS Integrations can be set up with [HashiCorp Terraform](https://developer.hashicorp.com/terraform/intro) as your preferred Infrastructure-as-Code (IaC) method and deployment process. Honeycomb AWS Integrations utilize AWS CloudWatch, Amazon Kinesis, and AWS Lambda to send data to Honeycomb. Refer to [How AWS Integrations Work](/send-data/aws/how-aws-integrations-work/) to reference which AWS services use which methods. Note that standard AWS charges apply. Please refer to Amazon for specifics on associated egress costs. ## HashiCorp Terraform Honeycomb provides a [Terraform module](https://github.com/honeycombio/terraform-aws-integrations) to automate configuration of various AWS services to Honeycomb. Each integration has an independently deployable submodule that the top-level module deploys all together with the ability to turn functionality on and off as needed. Supported Terraform Integrations: * CloudWatch Logs * CloudWatch Metrics * RDS Logs * Amazon S3 Bucket Logs ### Terraform Setup Implement all of the Terraform submodules at once, or choose among the available Terraform submodules. To configure for **all** supported Terraform integrations: 1. Add the minimal Terraform configuration, which includes the required fields for all supported Terraform integrations: ```hcl theme={} module "honeycomb-aws-integrations" { source = "honeycombio/integrations/aws" # aws cloudwatch logs integration cloudwatch_log_groups = [module.log_group.cloudwatch_log_group_name] // CloudWatch Log Group names to stream to Honeycomb. # aws rds logs integration enable_rds_logs = true rds_db_name = var.db_name rds_db_engine = "mysql" rds_db_log_types = ["slowquery"] // valid types include general, slowquery, error, and audit (audit will be unstructured) # aws metrics integration - pro/enterprise Honeycomb teams only # enable_cloudwatch_metrics = true # s3 logfile - alb access logs s3_bucket_arn = var.s3_bucket_arn s3_parser_type = "alb" // valid types are alb, elb, cloudfront, vpc-flow-log, s3-access, json, and keyval #honeycomb honeycomb_api_key = var.honeycomb_api_key // Honeycomb API key. honeycomb_dataset = "terraform-aws-integrations-test" // Your Honeycomb dataset name that will receive the logs. # Users generally do not need to set this, but it may be necessary when working with a proxy like Honeycomb's Refinery. honeycomb_api_host = var.honeycomb_api_host } ``` 2. Set the `TF_VAR_HONEYCOMB_API_KEY` environment variable to your team's Honeycomb API Key. ```shell theme={} export TF_VAR_HONEYCOMB_API_KEY=$HONEYCOMB_API_KEY ``` 3. Set the environment variables with your AWS credentials. ```shell theme={} export AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID export AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY export AWS_DEFAULT_REGION=$AWS_DEFAULT_REGION ``` For more details and options, visit [Terraform documentation](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#authentication-and-configuration). 4. Run `terraform plan/apply` in sequence. For more configuration options, refer to [USAGE.md](https://github.com/honeycombio/terraform-aws-integrations/blob/main/USAGE.md). To configure for **CloudWatch Logs**: 1. Add the minimal Terraform configuration, which includes the required fields: ```hcl theme={} module "honeycomb-aws-cloudwatch-logs-integration" { source = "honeycombio/integrations/aws//modules/cloudwatch-logs" name = var.cloudwatch_logs_integration_name // A name for the Integration. #aws cloudwatch integration cloudwatch_log_groups = ["/aws/lambda/S3LambdaHandler-test"] // CloudWatch Log Group names to stream to Honeycomb. s3_failure_bucket_arn = var.s3_bucket_name // S3 bucket ARN that will store any logs that failed to be sent to Honeycomb. #honeycomb honeycomb_api_key = var.HONEYCOMB_API_KEY // Honeycomb API key. honeycomb_dataset_name = "cloudwatch-logs" // Your Honeycomb dataset name that will receive the logs. } ``` 2. Set the `TF_VAR_HONEYCOMB_API_KEY` environment variable to your team's Honeycomb API Key. ```shell theme={} export TF_VAR_HONEYCOMB_API_KEY=$HONEYCOMB_API_KEY ``` 3. Set the environment variables with your AWS credentials. ```shell theme={} export AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID export AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY export AWS_DEFAULT_REGION=$AWS_DEFAULT_REGION ``` For more details and options, visit [Terraform documentation](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#authentication-and-configuration). 4. Run `terraform plan/apply` in sequence. For more configuration options, refer to [USAGE.md](https://github.com/honeycombio/terraform-aws-integrations/blob/main/USAGE.md). To configure for **CloudWatch Metrics**: 1. Add the minimal Terraform configuration, which includes the required fields: ```hcl theme={} module "honeycomb-aws-cloudwatch-metrics-integration" { source = "honeycombio/integrations/aws//modules/cloudwatch-metrics" name = var.cloudwatch_metrics_integration_name // A name for the Integration. honeycomb_api_key = var.HONEYCOMB_API_KEY // Honeycomb API key. honeycomb_dataset_name = "cloudwatch-metrics" // Your Honeycomb dataset name that will receive the metrics. s3_failure_bucket_arn = var.s3_bucket_arn // A S3 bucket that will store any metrics that failed to be sent to Honeycomb. } ``` 2. Set the `TF_VAR_HONEYCOMB_API_KEY` environment variable to your team's Honeycomb API Key. ```shell theme={} export TF_VAR_HONEYCOMB_API_KEY=$HONEYCOMB_API_KEY ``` 3. Set the environment variables with your AWS credentials. ```shell theme={} export AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID export AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY export AWS_DEFAULT_REGION=$AWS_DEFAULT_REGION ``` For more details and options, visit [Terraform documentation](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#authentication-and-configuration). 4. Run `terraform plan/apply` in sequence. For more configuration options, refer to [USAGE.md](https://github.com/honeycombio/terraform-aws-integrations/blob/main/USAGE.md). To configure for **RDS Logs**: 1. Add the minimal Terraform configuration, which includes the required fields: ```hcl theme={} module "honeycomb-aws-rds-logs-integration" { source = "honeycombio/integrations/aws//modules/rds-logs" name = "rds-logs-integration" db_engine = "mysql" db_name = "mysql-db-name" db_log_types = ["slowquery"] honeycomb_api_key = var.honeycomb_api_key // Your Honeycomb team's API key honeycomb_dataset_name = "rds-mysql-logs" s3_failure_bucket_arn = var.s3_bucket_arn // The full ARN of the bucket storing Kinesis Firehose failure logs. } ``` 2. Set the `TF_VAR_HONEYCOMB_API_KEY` environment variable to your team's Honeycomb API Key. ```shell theme={} export TF_VAR_HONEYCOMB_API_KEY=$HONEYCOMB_API_KEY ``` 3. Set the environment variables with your AWS credentials. ```shell theme={} export AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID export AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY export AWS_DEFAULT_REGION=$AWS_DEFAULT_REGION ``` For more details and options, visit [Terraform documentation](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#authentication-and-configuration). 4. Run `terraform plan/apply` in sequence. For more configuration options, refer to [USAGE.md](https://github.com/honeycombio/terraform-aws-integrations/blob/main/USAGE.md). To configure for **Amazon S3 Logs from a bucket**: 1. Add the minimal Terraform configuration, which includes the required fields: ```hcl theme={} module "logs_from_a_bucket_integrations" { source = "honeycombio/integrations/aws//modules/s3-logfile" name = var.logs_integration_name parser_type = var.parser_type // valid types are alb, elb, cloudfront, vpc-flow-log, s3-access, json, and keyval s3_bucket_arn = var.s3_bucket_arn // The full ARN of the bucket storing the logs. honeycomb_api_key = var.honeycomb_api_key // Your Honeycomb team's API key. honeycomb_dataset_name = "alb-logs" // Your Honeycomb dataset name that will receive the metrics. } ``` 2. Set the `TF_VAR_HONEYCOMB_API_KEY` environment variable to your team's Honeycomb API Key. ```shell theme={} export TF_VAR_HONEYCOMB_API_KEY=$HONEYCOMB_API_KEY ``` 3. Set the environment variables with your AWS credentials. ```shell theme={} export AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID export AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY export AWS_DEFAULT_REGION=$AWS_DEFAULT_REGION ``` For more details and options, visit [Terraform documentation](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#authentication-and-configuration). 4. Run `terraform plan/apply` in sequence. For more configuration options, refer to [USAGE.md](https://github.com/honeycombio/terraform-aws-integrations/blob/main/USAGE.md). ## Troubleshooting ### Kinesis Firehose Kinesis Firehose sends failed data to the configured S3 bucket. Depending on the stage of the flow when the error occurred, the error log ends up in a different subdirectory. For example, if our HTTP endpoint sends a non-`2xx` error code back, the error log will be located in the `http-endpoint-failed` directory with the exact status code and error message. ### RDS A pre-requisite to using both the [RDS logs Terraform module](https://github.com/honeycombio/terraform-aws-integrations/tree/main/modules/rds-logs) and the [RDS logs CloudFormation stack](https://us-east-1.console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks/create?stackName=rds-logs\&templateURL=https://honeycomb-builds.s3.amazonaws.com/cloudformation-templates/latest/rds-logs.yml) is enabling RDS log exports to CloudWatch. Refer to [Publishing database logs to Amazon CloudWatch](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_LogAccess.Procedural.UploadtoCloudWatch.html) for instructions. Once enabled, the module can scoop logs from those CloudWatch log groups and begin streaming them to Honeycomb. When enabling log exports for RDS Postgresql, ensure the `log_statement` attribute on the parameter group is not set to `ALL`. Currently, structured logs are supported for the following: * MySQL general logs * MySQL slow query logs * MySQL error logs * Postgresql slow query logs For any RDS log types not listed above, the integration will still deliver them to Honeycomb but they will be unstructured logs. # How Honeycomb's AWS Integrations Work Source: https://docs.honeycomb.io/send-data/aws/how-aws-integrations-work Find out how Honeycomb's AWS integrations collect logs and metrics, which AWS services use which collection methods, and how the data flows to Honeycomb. This section describes the mechanics of Honeycomb AWS Integrations that collect logs and metrics. It describes various collection methods and documents which AWS services use those methods. For more details, visit the Honeycomb AWS Integrations GitHub repository for [Terraform](https://github.com/honeycombio/terraform-aws-integrations) or [CloudFormation](https://github.com/honeycombio/cloudformation-integrations). ## AWS CloudWatch Logs Many AWS services publish logs to CloudWatch Logs. By default, most AWS services send unstructured logs to CloudWatch. Because Honeycomb is designed to work best with [structured events](/get-started/honeycomb/traces-metrics-logs/), Honeycomb AWS Integrations convert some of those CloudWatch log streams into structured data. Deploy the Honeycomb CloudWatch Logs integration with either [Terraform](https://github.com/honeycombio/terraform-aws-integrations/tree/main/modules/cloudwatch-logs) or [CloudFormation](https://us-east-1.console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks/create?stackName=cloudwatch-logs\&templateURL=https://honeycomb-builds.s3.amazonaws.com/cloudformation-templates/latest/cloudwatch-logs.yml). ### How AWS CloudWatch Logs Integrations Work AWS CloudWatch provides [Subscription Filters](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/SubscriptionFilters.html), which can be configured to forward all logs in a log group to a Kinesis Firehose destination that can then stream the logs to our Honeycomb Kinesis endpoint. AWS services listed in the unstructured data column of the table below use a workflow, as shown by the diagram below, to send AWS CloudWatch logs to Honeycomb. ```mermaid actions={false} theme={} flowchart LR D("Kinesis Data Transformation Lambda") <--> B A("AWS CloudWatch Log Group") --> B("AWS Kinesis Data Firehose") --> C("Honeycomb") ``` 1. AWS CloudWatch log groups point at AWS Kinesis Firehose. 2. Firehose forwards data to Honeycomb. Kinesis Data Firehose can invoke Lambda functions to transform incoming source data before delivering the transformed data to its destination. Supported AWS services listed in the structured data column of the table below are either JSON-formatted by default or use an additional step in their workflow, as shown by the diagram above, to structure their log data before sending it to Honeycomb. ### Supported AWS Services Through CloudWatch Logs Honeycomb AWS Integrations are designed to work with **all** services that logs to CloudWatch. For a full list of possible data sources, refer to AWS documentation for [services that publish logs to CloudWatch Logs](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/aws-services-sending-logs.html). This list is a selection of supported AWS services that publish logs through CloudWatch Logs and the type of log data Honeycomb can collect from them. | AWS Services supported through CloudWatch Logs | Structured | Unstructured | | ---------------------------------------------- | ---------- | ------------ | | Amazon API Gateway | | ✔ | | Amazon Aurora | | ✔ | | AWS CloudHSM | | ✔ | | AWS CloudWatch | ✔ | | | AWS CodeBuild | | ✔ | | AWS CodeDeploy | | ✔ | | Amazon Cognito | | ✔ | | AWS Elastic Beanstalk | | ✔ | | Amazon Elastic Container Service (ECS) | ✔ | | | Amazon Elastic Kubernetes Service (EKS) | ✔ | | | Elastic Load Balancing (ELB) | ✔ | | | Amazon ElastiCache | | ✔ | | AWS Fargate | | | | Amazon Keyspaces | | ✔ | | AWS Lambda | ✔ | | | Amazon Managed Streaming for Kafka | | ✔ | | Amazon MQ | | ✔ | | AWS Network Firewall | | ✔ | | AWS OpsWorks | | ✔ | | Amazon Relational Database Service (RDS) | ✔ | | | Amazon Route 53 | | ✔ | | Amazon Simple Notification Service (SNS) | ✔ | | | Amazon Simple Storage Service (S3) | ✔ | | | AWS Step Functions | | ✔ | | Amazon Virtual Private Cloud (VPC) | ✔ | | ### Working With Unstructured AWS Logs Each field in a structured log (or event) is queryable with Honeycomb. This makes working with structured AWS log data similar to working with other types of data in Honeycomb. Unstructured logs are received by Honeycomb as events with a verbose `message` attribute. All unstructured log data is contained within this single attribute. For tips on working with unstructured AWS logs, refer to [Work with Your AWS Data](/investigate/debug/aws-data-in-honeycomb/). ### Advanced Use The CloudWatch Logs integration is a great way to get started and gain insights across a variety of AWS services. If you want to customize the structure of the logs, you might want to write your own data transformation Lambda to be used with the Kinesis Data Firehose. Source code for our RDS data transformations can be viewed in the [Agentless Integrations GitHub repository](https://github.com/honeycombio/agentless-integrations-for-aws/tree/main/rds-mysql-kfh-transform) as an example. ## AWS CloudWatch Metrics Honeycomb AWS Integrations support all AWS services that send metrics to CloudWatch. AWS CloudWatch provides [Metric Streams](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/CloudWatch-Metric-Streams.html), which forward all metrics captured by Amazon during normal use of AWS offerings to third-party destinations, including Honeycomb. Deploy the Honeycomb Cloudwatch Metrics integration with either [Terraform](https://github.com/honeycombio/terraform-aws-integrations/tree/main/modules/cloudwatch-metrics) or [CloudFormation](https://us-east-2.console.aws.amazon.com/cloudformation/home?region=us-east-2#/stacks/new?stackName=cloudwatch-metrics\&templateURL=https://honeycomb-builds.s3.amazonaws.com/cloudformation-templates/latest/cloudwatch-metrics.yml). AWS charges its customers to use the Cloudwatch Metrics API. Please refer to Amazon for specifics on associated egress costs. ### How AWS CloudWatch Metrics Integrations work Metrics stored in AWS CloudWatch can be streamed to other systems using AWS Kinesis Data Firehose. Honeycomb provides an endpoint that is compatible with CloudWatch Metric Streams, and stores the data it receives in a dataset for easy querying. ```mermaid actions={false} theme={} flowchart LR A("AWS Cloudwatch") -->|"Metrics Streams"| B("AWS Kinesis") -->|"Data Firehose (OTLP)"| C("Honeycomb") ``` 1. AWS Cloudwatch with Metric Streams pointed at AWS Kinesis. 2. Kinesis forwards data to Honeycomb over Data Firehose, which is configured to format data with OpenTelemetry Line Protocol (OTLP). ### Supported AWS Services Through CloudWatch Metrics For a full list of possible data sources, refer to AWS documentation for services that [publish metrics to CloudWatch Metrics](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/aws-services-cloudwatch-metrics.html). ## Amazon S3 Logs Honeycomb provides an agentless integration for ingesting [S3](https://docs.aws.amazon.com/AmazonS3/latest/dev/Welcome.html) logfiles and sending them to Honeycomb as structured events. Deploy the Honeycomb S3 Logs integration with either [Terraform](https://github.com/honeycombio/terraform-aws-integrations/tree/main/modules/s3-logfile) or [CloudFormation](https://us-east-1.console.aws.amazon.com/cloudformation/home?region=us-east-1#/stacks/create?stackName=s3-logfile\&templateURL=https://honeycomb-builds.s3.amazonaws.com/cloudformation-templates/latest/s3-logfile.yml). ### How Amazon S3 Logs Integrations Work AWS services listed in the the table below use a workflow, as shown by the diagram below, to send Amazon S3 logs to Honeycomb. The integration uses a [Lambda](https://docs.aws.amazon.com/lambda/latest/dg/welcome.html) function, which is subscribed to `PutObject` events on your bucket. The Lambda source code is available [on GitHub](https://github.com/honeycombio/agentless-integrations-for-aws/blob/main/s3-handler/main.go). ```mermaid actions={false} theme={} flowchart LR A("S3 Bucket with Logs") --> B("Lambda") --> C("Honeycomb") ``` 1. S3 logs point at a Lambda. 2. Lambda delivers structured logs to Honeycomb. ### Supported AWS Services Through Amazon S3 Logs This is a complete list of AWS services logging to S3 that are supported by Honeycomb AWS Integrations. | AWS Services supported via S3 Logs | Structured | Unstructured | | ---------------------------------------- | ---------- | ------------ | | AWS CloudFront | ✔ | | | AWS CloudTrail | ✔ | | | Elastic Load Balancing (ELB) Access Logs | ✔ | | | Amazon S3 Access Logs | ✔ | | | Amazon Virtual Private Cloud (VPC) | ✔ | | # Send Data from AWS Lambda Source: https://docs.honeycomb.io/send-data/aws/lambda Choose how to instrument your AWS Lambda functions and send telemetry to Honeycomb: the OpenTelemetry Lambda Layer or the Honeycomb Lambda Extension. For serverless apps based on Lambda and similar platforms, observability can be challenging. With no server to log into, clunky logging interfaces, and short, event-driven process runtimes, making sense of what is going on is often difficult. To help with this, we recommend the following methods for sending data to Honeycomb. AWS maintains an official OpenTelemetry Lambda Layer that lets you use OpenTelemetry in your Lambda Functions and export data asynchronously from those functions. If you are not ready to use OpenTelemetry, Honeycomb provides the Honeycomb Lambda Extension, which can run as a Lambda Layer or inside a container alongside your lambda function. # Export Data with AWS Lambda + Honeycomb Lambda Extension Source: https://docs.honeycomb.io/send-data/aws/lambda/honeycomb-lambda-extension Receive log messages from your Lambda function and send them to Honeycomb as events using the Honeycomb Lambda Extension, available as a layer or container. If not yet ready to use OpenTelemetry, you can use the [Honeycomb Lambda Extension](https://github.com/honeycombio/honeycomb-lambda-extension). This extension is designed to run alongside your Lambda Function. It integrates with the [Lambda Logs API](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-logs-api.html) and receives log messages from your lambda function, which are then sent to Honeycomb as events. Structured log messages sent to `stdout` or `stderr` from your lambda function will be sent to Honeycomb as events. The extension can be run inside a container or added as a Lambda Layer. Overview of Lambda Extension ### How It Works [AWS Lambda Extensions](https://aws.amazon.com/blogs/compute/introducing-aws-lambda-extensions-in-preview/) allow you to extend the functionality of Lambda functions through configuration as Lambda Layers or run inside a container image. Extensions run alongside the Lambda Runtime and can read data environment variables from the environment. Once the Honeycomb Lambda Extension is configured, any structured logs emitted to `stdout` or `stderr` by your Lambda function will be parsed by the extension and sent to a dataset that you specify in Honeycomb. Logs emitted in a Lambda invocation will be parsed during the following invocation, and any remaining logs will be parsed whenever the Lambda runtime shuts down. This means that you may experience some delay in seeing events arrive in Honeycomb, especially if your Lambda function receives low traffic. ### Architectures The [Honeycomb Lambda Extension](https://github.com/honeycombio/honeycomb-lambda-extension) is available as an [external extension](https://docs.aws.amazon.com/lambda/latest/dg/using-extensions.html) pre-built in a lambda layer for either `x86_64` or `arm64` architectures. Graviton2 `arm64` is supported in most, but not all regions. See [AWS Lambda Pricing](https://aws.amazon.com/lambda/pricing/) for which regions are supported. ### Installing as a Lambda Layer To start using the [Honeycomb Lambda Extension](https://github.com/honeycombio/honeycomb-lambda-extension), add the extension to your function as a [Lambda Layer](https://docs.aws.amazon.com/lambda/latest/dg/configuration-layers.html). Add the following environment variables to your Lambda function configuration: * `LIBHONEY_DATASET` - The Honeycomb [dataset](/get-started/best-practices/organizing-data/#datasets-group-data-together) you would like events to be sent to. This could be the service name representing the function or a generic dataset name representing the data. * `LIBHONEY_API_KEY` - Your Honeycomb API Key (also called Write Key). As well as the following optional environment variable: * `LIBHONEY_API_HOST` - Mostly used for testing purposes, or to be compatible with proxies. Defaults to ``. * `LOGS_API_DISABLE_PLATFORM_MSGS` - Optional. Set to "true" in order to disable "platform" messages from the logs API. * `HONEYCOMB_DEBUG` - Optional. Set to "true" to enable debug statements and troubleshoot issues. Enabling this will subscribe to Libhoney's [response queue](/send-data/go/libhoney/#handling-responses) and log the success or failure of sending events to Honeycomb. * `HONEYCOMB_BATCH_SEND_TIMEOUT` - Optional. Default: "15s" (15 seconds; refer to note below about timeout durations). The timeout for the complete HTTP request/response cycle for sending a batch of events Honeycomb. A batch send that times out has a single built-in retry; total time a lambda invocation may spend waiting is double this value. A very low duration may result in duplicate events, if Honeycomb data ingest is successful but slower than this timeout (rare, but possible). * `HONEYCOMB_CONNECT_TIMEOUT` - Optional. Default: 3s (3 seconds; refer to note below about timeout durations). The timeout for establishing a TCP connection to Honeycomb. This is useful when there are connectivity issues between your Lambda environment and Honeycomb, allowing upload requests to fail faster and avoid waiting for the longer batch send timeout to elapse. TIMEOUT options should be given a value in a format parseable as a duration, such as "1m", "15s", or "750ms". There are other valid time units ("ns", "us"/"µs", "h"), but their use does not fit a timeout for HTTP connections made in the AWS Lambda compute environment. ### Installing in a Container Image AWS Lambda functions can now be packaged and deployed as [container images](https://docs.aws.amazon.com/lambda/latest/dg/images-create.html). This allows developers to leverage the flexibility and familiarity of container tooling, workflows and dependencies. AWS Lambda provides a number of [base images](https://docs.aws.amazon.com/lambda/latest/dg/runtimes-images.html#runtimes-images-lp) you can use. You can also use a custom base image, and adjust the examples accordingly. ### Performance Implications The Honeycomb Lambda Extension runs independently of your Lambda Function and does not add to your Lambda Function's execution time or add any additional latency. However, it does increase your Lambda Function's size in proportion with the size of the Honeycomb Lambda Extension binary. ## Examples Below are some structured logging examples using some libraries we are familiar with at Honeycomb. Feel free to use your own! ### Go ```go theme={} import ( log "github.com/sirupsen/logrus" ) log.SetFormatter(&log.JSONFormatter{}) func Handler(ctx context.Context) error { // Measure execution time startTime := time.Now() // ... // Get the Lambda context object lc, _ := lambdacontext.FromContext(ctx) log.WithFields(log.Fields{ "function_name": lambdacontext.FunctionName, "function_version": lambdacontext.FunctionVersion, "request_id": lc.AwsRequestID, "duration_ms": time.Since(startTime).Milliseconds(), // The sample rate on the event is forwarded to honeycomb - we // assume the event has already been properly sampled. "samplerate": 10, // other fields of interest }).Info("Hello World from Lambda!") } ``` ### Python ```python theme={} import structlog structlog.configure(processors=[structlog.processors.JSONRenderer()]) log = structlog.get_logger() def handler(event, context): # measure execution time start_time = datetime.datetime.now() # ... log.msg( "Hello World from Lambda!", function_name=context.function_name, function_version=context.function_version, request_id=context.aws_request_id, duration_ms=(datetime.datetime.now() - start_time).total_seconds() * 1000, # other fields of interest ) ``` ### JavaScript ```javascript theme={} var bunyan = require('bunyan'); var log = bunyan.createLogger(); module.exports.handler = (event, context, callback) => { // Measure execution time let startTime = Date.now(); // ... log.info({ functionName: context.functionName, functionVersion: context.functionVersion, requestId: context.awsRequestId, // Example fields - send anything that seems relevant! userId: event.UserId, userAction: event.UserAction, latencyMs: Date.now() - startTime, }, 'Hello World from Lambda!'); } ``` Do not use `console.log` to write structured log lines in Lambda. Lambda uses a patched version of `console.log`, injecting extra information with each line that does not work correctly with the Honeycomb Extension Lambda Logs integration. # Export Data with AWS Lambda Layer + OpenTelemetry Source: https://docs.honeycomb.io/send-data/aws/lambda/opentelemetry Instrument your Lambda functions with the AWS-managed OpenTelemetry Lambda Layer and export trace data asynchronously to Honeycomb without blocking function execution. ## Overview If you use OpenTelemetry, AWS manages an official OpenTelemetry Lambda layer called AWS Distro for OpenTelemetry (ADOT) Lambda, which lets you use OpenTelemetry in your Lambda functions and export data asynchronously from those functions. **Using Legacy ADOT Lambda Layers for Honeycomb** This guide uses the **legacy ADOT Lambda layers** that include an embedded OpenTelemetry Collector. AWS now offers newer optimized layers without a collector, but these are designed to export only to AWS CloudWatch and X-Ray. To send telemetry to Honeycomb (a non-AWS endpoint), you need the legacy layers with the embedded collector. AWS acknowledges this use case, stating: *"Unless you want to export the telemetry data to a non CloudWatch endpoint, the approach below is not recommended."* The legacy ADOT Lambda Layer works by embedding a stripped-down version of the [OpenTelemetry (OTel) Collector](/send-data/opentelemetry/collector/) inside an AWS Lambda extension layer. To use it, configure an OTLP exporter to send to the OTel Collector in the Lambda layer. The instructions in this guide clarify and expand on the steps provided in AWS's documentation for the [legacy ADOT Lambda layers with embedded collector](https://aws-otel.github.io/docs/getting-started/lambda#not-recommended-using-the-legacy-adot-lambda-layers-with-embedded-collector). ## Languages AWS maintains pre-configured Lambda layers that provide automatic instrumentation and do not require you to modify code. These exist for several languages, including: * Java * Python * JavaScript Two instrumentation paths exist for ADOT Lambda for Java: the [Java SDK](https://aws-otel.github.io/docs/getting-started/lambda/lambda-java) or the [Java Auto-Instrumentation Agent](https://aws-otel.github.io/docs/getting-started/lambda/lambda-java-auto-instr). Tradeoffs exist between these paths, requiring you to choose either convenience or reduced overhead and cold start latency. Using the Java Auto-Instrumentation Agent simplifies implementation, but adds overhead and increases cold start latency. Using the Java SDK reduces runtime and cold start latency, but requires you to manually instrument and modify your code to get a similar level of observability data. AWS offers additional Lambda layers that require you to modify your code to add instrumentation. You must import the OpenTelemetry packages directly into your Lambda function and configure them. These layers are available for the following languages: * .NET * Go If you are using another language or want to manually build and configure a layer, visit AWS's documentation on [Manual Steps for Private Lambda Layers](https://aws-otel.github.io/docs/getting-started/lambda#manual-steps-for-private-lambda-layers). ## Before You Begin Before you begin, you'll need: * an AWS account with permissions to: * Create AWS Lambda functions * Access AWS X-Ray * Create AWS Identity and Access Management (IAM) policies * a [Honeycomb Ingest API Key](/configure/environments/manage-api-keys/#create-api-key) ## Create a Lambda Function in AWS Lambda Begin by creating a Lambda function, which is a serverless compute service that lets you run code in response to events without managing servers. 1. In the [AWS Management Console](https://aws.amazon.com/console/), navigate to the [Lambda console](https://console.aws.amazon.com/lambda/home), and select **Functions** from the nav. 2. Select **Create function**. 3. Choose **Author from Scratch** as the method of creating your function. 4. Locate the **Basic Information** section, and enter details for your Lambda function: | Field | Description | | ----------------- | ---------------------------------------------------------------------------------------------------- | | **Function name** | Name that describes the purpose of your function. | | **Runtime** | Language to use to write your function. | | **Architecture** | Instruction set architecture you want for your function code. We recommend that you choose `x86-64`. | 5. Locate the **Permissions** section, and expand it. 6. For **Execution role**, select **Create a new role with basic Lambda permissions**. 7. Select **Create function** 8. In the Lambda code editor window that opens, enter your Lambda function. For example, for JavaScript: ```javascript theme={} exports.lambdaHandler = async (event, context) => { response = { 'statusCode': 200, 'body': json.stringify('Hello, World!') } return response; }; ``` 9. Press \[`Ctrl`] + \[`s`] on your keyboard to save your file. 10. Select **Deploy**. Remember to select **Deploy** any time you make a change to your Lambda function. ## Add the AWS Distro for OpenTelemetry Lambda Layer If you are using .NET or Go, you must instrument your code before you complete this step. Refer to AWS instructions on [.NET instrumentation](https://aws-otel.github.io/docs/getting-started/lambda/lambda-dotnet#instrumentation) or [Go instrumentation](https://aws-otel.github.io/docs/getting-started/lambda/lambda-go#instrumentation). If you are using Java, JavaScript, and Python, your code will be instrumented in a later step. After you have entered the details and code for your Lambda function, add the ADOT Lambda layer to it. 1. Locate the **Layers** section, and select **Add a layer**. 2. In the **Add layer** window, locate **Layer source**, and select **Specify an ARN**. 3. Locate the **Specify an ARN** section, and copy and paste the example ARN from the AWS legacy layer documentation for your language: * [Java SDK](https://aws-otel.github.io/docs/getting-started/lambda/lambda-java#add-the-arn-of-the-lambda-layer) * [Java Auto-instrumentation Agent](https://aws-otel.github.io/docs/getting-started/lambda/lambda-java-auto-instr#add-the-arn-of-the-lambda-layer) * [JavaScript](https://aws-otel.github.io/docs/getting-started/lambda/lambda-js#add-the-arn-of-the-lambda-layer) * [Python](https://aws-otel.github.io/docs/getting-started/lambda/lambda-python#add-the-arn-of-the-lambda-layer) * [.NET](https://aws-otel.github.io/docs/getting-started/lambda/lambda-dotnet#lambda-layer) * [Go](https://aws-otel.github.io/docs/getting-started/lambda/lambda-go#lambda-layer) 4. Modify your ARN: * Replace the `` placeholder in your ARN with the appropriate value. For x86-based processors, use `amd64`. * Replace the `` placeholder in your ARN with the appropriate value from the supported region values listed in the AWS documentation linked in the previous step. Lambda layers can be used only in the region in which they are published, so make sure to use the layer in the same region as your Lambda function. 5. Select **Add**. ## Disable Active Tracing We recommend disabling the Active Tracing setting for AWS X-Ray because: * If you are visualizing your data with Honeycomb, then exporting data to AWS X-Ray is unnecessary. * Active Tracing adds extra spans, which cannot be exported outside of AWS, to traces by default. * Disabling Active Tracing provides some data savings and avoids conflicts with other tracing instrumentation you may have. To disable Active Tracing: 1. In the **Configuration** tab, select **Monitoring and operations tools**, and then select **Edit**. 2. Locate the **AWS X-Ray** section, and toggle off **Active tracing**. 3. Select **Save**. ## Configure OpenTelemetry Packages If you are using .NET or Go, skip this step and proceed to [Customize the ADOT Collector to Send Telemetry Data to Honeycomb](#customize-the-adot-collector-to-send-telemetry-data-to-honeycomb). Import the OpenTelemetry packages directly into your Lambda function and configure them using the reserved `AWS_LAMBDA_EXEC_WRAPPER` environment variable. The environment variable points to a script that performs the configuration directly in each layer, so you can avoid modifying code. 1. In the **Configuration** tab of the Lambda console, select **Environment variables**, and then select **Edit**. 2. For **Key**, enter `AWS_LAMBDA_EXEC_WRAPPER`. `AWS_LAMBDA_EXEC_WRAPPER` is a reserved environment variable AWS Lambda uses to identify a custom wrapper script to run before your function's main handler. 3. For **Value**, enter `/opt/otel-handler`. This script will invoke your Lambda application with the automatic instrumentation applied. For Java, you can instrument using either the [Java SDK](https://aws-otel.github.io/docs/getting-started/lambda/lambda-java) or the [Java Auto-Instrumentation Agent](https://aws-otel.github.io/docs/getting-started/lambda/lambda-java-auto-instr). When using the Java SDK, [scripts for several other handler types](https://aws-otel.github.io/docs/getting-started/lambda/lambda-java#enable-auto-instrumentation-for-your-lambda-function) exist. 4. Select **Add environment variable**. 1. In the **Configuration** tab of the Lambda console, select **Environment variables**, and then select **Edit**. 2. For **Key**, enter `AWS_LAMBDA_EXEC_WRAPPER`. `AWS_LAMBDA_EXEC_WRAPPER` is a reserved environment variable AWS Lambda uses to identify a custom wrapper script to run before your function's main handler. 3. For **Value**, enter `/opt/otel-instrument`. This script will invoke your Lambda application with the automatic instrumentation applied. 4. Select **Add environment variable**. 1. In the **Configuration** tab of the Lambda console, select **Environment variables**, and then select **Edit**. 2. For **Key**, enter `AWS_LAMBDA_EXEC_WRAPPER`. `AWS_LAMBDA_EXEC_WRAPPER` is a reserved environment variable AWS Lambda uses to identify a custom wrapper script to run before your function's main handler. 3. For **Value**, enter `/opt/otel-handler`. This script will invoke your Lambda application with the automatic instrumentation applied. 4. Select **Add environment variable**. ## Customize the ADOT Collector to Send Telemetry Data to Honeycomb To send your telemetry data to Honeycomb, you must customize the embedded ADOT Collector configuration in the legacy Lambda layer. The ADOT Lambda Layers support a variety of [confmap providers](https://aws-otel.github.io/docs/components/confmap-providers#confmap-providers-supported-by-the-adot-collector), which are types of OpenTelemetry Collector components responsible for fetching configuration from a URI. In this example, we use a `file` confmap provider. 1. In the **Code** tab of the Lambda console, add a new file named `otel-collector-config.yaml` alongside your Lambda function (`index.js`). 2. Enter the following code, which configures the Collector to send traces to Honeycomb: ```yaml theme={} #otel-collector-config.yaml in the root directory #Set an environment variable 'OPENTELEMETRY_COLLECTOR_CONFIG_FILE' to '/var/task/otel-collector-config.yaml' receivers: otlp: protocols: grpc: endpoint: 0.0.0.0:4317 http: endpoint: 0.0.0.0:4318 exporters: otlp_http: endpoint: "https://api.honeycomb.io:443" # US instance #endpoint: "https://api.eu1.honeycomb.io:443" # EU instance headers: "x-honeycomb-team": "YOUR_HONEYCOMB_INGEST_API_KEY" #"x-honeycomb-dataset": "YOUR_DATASET" #If you are a Honeycomb Classic user, you must also specify the Dataset for traces. service: pipelines: traces: receivers: [otlp] exporters: [otlp_http] metrics: receivers: [otlp] exporters: [otlp_http] logs: receivers: [otlp] exporters: [otlp_http] ``` Remember to replace the `YOUR_HONEYCOMB_INGEST_API_KEY` placeholder with your [Honeycomb Ingest API Key](/configure/environments/manage-api-keys/#create-api-key). To explore additional Collector configurations customized for Honeycomb, visit [Send Data with the OpenTelemetry Collector](/send-data/opentelemetry/collector/). This configuration file uses batch processing, which is our recommended processing method. Ideally, you would also [apply filtering](/send-data/opentelemetry/collector/#filtering-span-events-and-other-data) in this file. Alternatively, you could send single events to a second gateway Collector and have it perform filtering and batching. 3. Press \[`Ctrl`] + \[`s`] on your keyboard to save your file. 4. Select **Deploy**. Remember to select **Deploy** any time you make a change to your Collector configuration file. ## Configure the ADOT Collector to Find Your Custom Configuration After you have customized your Collector configuration file, you must tell the embedded ADOT Collector where to find your custom configuration using the reserved `OPENTELEMETRY_COLLECTOR_CONFIG_FILE` environment variable. 1. In the **Configuration** tab, select **Environment variables**, and then select **Edit**. 2. For **Key**, enter `OPENTELEMETRY_COLLECTOR_CONFIG_FILE`. `OPENTELEMETRY_COLLECTOR_CONFIG_FILE` is a reserved environment variable AWS Lambda uses to identify a custom configuration file for the OpenTelemetry Collector. 3. For **Value**, enter `/var/task/otel-collector-config.yaml`. You add the `/var/task/` prefix to your file path because you used a `file` configmap provider. 4. Select **Add environment variable**. ## Instrument Your Lambda Function If you are using [.NET](https://aws-otel.github.io/docs/getting-started/lambda/lambda-dotnet#instrumentation) or [Go](https://aws-otel.github.io/docs/getting-started/lambda/lambda-go#instrumentation), skip this step. You should have already added instrumentation to your code (before [adding the AWS Distro for OpenTelemetry Lambda Layer](#add-the-aws-distro-for-opentelemetry-lambda-layer)). Languages with automatic instrumentation, which lets data flow automatically into Honeycomb, include: * Java * Python * JavaScript Automatic instrumentation works only if you use an automatic instrumentation library. In this example, we use `https.get`. 1. Import the `https` library and configure it to use Honeycomb. For this JavaScript example, add the following code in a location above the `exports.lambdaHandler` line in the Lambda function you created in the first step of this guide: ```javascript theme={} import https from `https`; var options = { hostname: 'honeycomb.io' , path: '/' , method: 'GET' }; ``` 2. Instruct the library to return data. Add the following code in a location directly above the `return response` line in the Lambda function you created in the first step of this guide: ```javascript theme={} var req = https.request( options, function(res) { res.on('data', function(d) { // }); } ); req.end(); ``` The full code should look similar to: ```javascript theme={} import https from `https`; var options = { hostname: 'honeycomb.io' , path: '/' , method: 'GET' }; exports.lambdaHandler = async (event, context) => { response = { 'statusCode': 200, 'body': json.stringify('Hello, World!') } var req = https.request( options, function(res) { res.on('data', function(d) { // }); } ); req.end(); return response; }; ``` 3. Press \[`Ctrl`] + \[`s`] on your keyboard to save. 4. Select **Deploy**. ## Test Your Implementation It's time to test your implementation and see data in Honeycomb! 1. In the **Code** tab, select **Test**. 2. Open Honeycomb and look for a Dataset with the same name as the Lambda function you created in the first step of this guide. If you see the Dataset, then your data is flowing to Honeycomb! To learn how to explore your AWS data, visit [Investigate AWS Data in Honeycomb](/investigate/debug/aws-data-in-honeycomb/). ### Creating a Function URL To test your Lambda function more easily, you can use a function URL, which is a dedicated HTTP(S) endpoint that you can enable for your Lambda function. You can use the function URL to automate testing. To create a function URL: 1. In the [Lambda console](https://console.aws.amazon.com/lambda/home), select **Functions** from the nav. 2. Locate and select the name of the function for which you you want to create a function URL. 3. Select the **Configuration** tab, and then select **Function URL**. 4. Select **Create function URL**. 5. For **Auth type**, choose **AWS\_IAM** or **NONE**, depending on who you would like to have access to your function URL. 6. Select **Save**. ## Propagating Trace Context Trace context plays a critical role in linking together individual services into a cohesive trace. In AWS Lambda, ensuring that trace context is correctly passed across multiple Lambda functions is essential for accurate, end-to-end tracing. ### Disabling AWS Context Propagation By default, AWS Lambda automatically propagates trace context between services. If you need to disable automatic context propagation, you can use either an environment variable or a configuration file. #### Disabling Context Propagation Using an Environment Variable Set the `OTEL_LAMBDA_DISABLE_CONTEXT_PROPAGATION` reserved environment variable to `true`: ```sh theme={} OTEL_LAMBDA_DISABLE_AWS_CONTEXT_PROPAGATION=true ``` #### Disabling Context Propagation Using a Configuration File Using a configuration file gives you more control over how trace context is managed in your Lambda functions. To disable context propagation using a configuration file: 1. Create a configuration file (in this example, named `lambda-config.js`), and add the following code: ```javascript theme={} // lambda-config.js global.configureLambdaInstrumentation = (config) => { return { ...config, disableAwsContextPropagation: true } } ``` 2. Include this configuration file when starting your Lambda function, either as part of the start command or when using the `NODE_OPTIONS` reserved environment variable: ```sh theme={} NODE_OPTIONS=--require ./lambda-config.js ``` ### Propagating Context Using Lambda Event Arguments When invoking a Lambda function outside of an HTTP context, the trace context may not be included automatically. In these cases, you can use Lambda event arguments to propagate the context manually. For example, in Node.js: ```javascript theme={} const { trace, context, TraceFlags } = require('@opentelemetry/api'); let tracer = trace.getTracer("aws-lambda-tracer"); exports.handler = async function (event, ctx) { let newContext = trace.setSpanContext(context.active(), { traceId: event.traceId, spanId: event.spanId, traceFlags: TraceFlags.SAMPLED, isRemote: true }); context.with(newContext, () => { const span = tracer.startSpan('handler function', newContext); span.end(); }); return context.logStreamName; }; ``` ## Troubleshooting If you need to troubleshoot, explore these solutions to common issues. ### Missing root spans in traces If you are using AWS Lambda with API Gateway (or another service that governs traffic), missing root spans for your traces in Honeycomb are likely. This is because API Gateway often generates the initial request but may not propagate tracing headers correctly to your Lambda function. Some solutions you can try to ensure your traces include root spans include: * Disable Active Tracing on your Lambda function (in the AWS Console under **Configuration** > **Monitoring**). If you are using Terraform to launch your Lambda function, you can turn off tracing by assigning the `Passthrough` value to the `tracing_config` argument. Learn more about the `tracing_config` argument in [Terraform's documentation for Lambda Function resources](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function#tracing_config). * To ensure consistent trace context, add the `OTEL_PROPAGATORS` reserved environment variable to your Lambda function (in the AWS Console under **Configuration** > **Environment variables**) and set its value to `tracecontext`. * If you call your Lambda function directly from code, make sure the `traceparent` header is present. With the `traceparent` header, OpenTelemetry can recognize the request as part of a larger trace and will create a root span. If the `traceparent` header is missing, add a code block to wrap your entrypoint function in a span. For example, in JavaScript: ```javascript theme={} // index.js const { trace, context, SpanStatusCode, propagation } = require('@opentelemetry/api'); let tracer = trace.getTracer('tracer.name.here'); exports.handler = async (event) => { let span = null; if (!event.headers.traceparent) { span = tracer.startActiveSpan('something.different', { root: true }); } const response = { statusCode: 200, body: createTrackingId(event.body || 'salt'), }; if (span) { span.end(); } return response; }; ``` * Ensure your OpenTelemetry Collector is [correctly configured to send data to Honeycomb](/send-data/opentelemetry/collector/). * Make sure you have selected an appropriate `service.name`. By default, the AWS Lambda layer sets `service.name` to the Lambda function's name. Because Honeycomb creates a dataset for each `service.name`, the default AWS Lambda behavior can cause traces from related Lambda functions to be split across different datasets. To keep datasets together, override the default `service.name` by explicitly setting the `OTEL_SERVICE_NAME` reserved environment variable for each Lambda function. ### Missing non-root spans in traces Although the AWS Lambda Setup documentation includes [a step that enables Active Tracing](https://aws-otel.github.io/docs/getting-started/lambda/lambda-js#enable-auto-instrumentation-for-your-lambda-function), we recommend [disabling Active Tracing](#disable-active-tracing). When Active Tracing is enabled, Lambda uses a ParentBased sampler with a sample rate of 5%. The [AWS Propagator code](https://github.com/open-telemetry/opentelemetry-js-contrib/blob/main/packages/propagator-aws-xray/src/AWSXRayPropagator.ts) always creates a new context, which can cause some spans to be dropped when using a ParentBased sampler. With this sampler, if spans are dropped and `DEBUG` mode is enabled, you might see the following error in the logs: ```sh theme={} DEBUG Recording is off, propagating context in a non-recording span ``` To resolve this, use an AlwaysOn sampler by setting the `OTEL_TRACES_SAMPLER` reserved environment variable to `always_on`: ```sh theme={} OTEL_TRACES_SAMPLER=always_on ``` To confirm the sampler configuration in use, output details to the console: ```javascript theme={} let tracer = trace.getTracer(''); console.log(`Tracer sampler information: ${tracer['_sampler'].toString()}`) ``` ### Lambda layer not instrumenting code Ensure that you have [created the `AWS_LAMBDA_EXEC_WRAPPER` reserved environment variable](#configure-opentelemetry-packages), which is essential for initializing OpenTelemetry instrumentation, and have set it to use the OpenTelemetry handler: ```sh theme={} AWS_LAMBDA_EXEC_WRAPPER=/opt/otel-handler ``` # Collect Telemetry from Azure Source: https://docs.honeycomb.io/send-data/azure Send Azure telemetry to Honeycomb using an OpenTelemetry Collector. Deploy an OpenTelemetry (OTel) Collector to ingest telemetry from Azure services and send it to Honeycomb. Analyzing your Azure telemetry with Honeycomb lets you answer questions like: * Which App Services are experiencing the highest latency? * How are my Function Apps performing across different regions? * What is the error rate for my Service Bus queues? * Are there any performance bottlenecks in my Cosmos DB operations? ## Before you begin Before you begin, make sure you have: * An Azure subscription with the services you want to monitor * Access to configure Azure Monitor and Event Hub * A [Honeycomb Ingest API Key](/configure/environments/manage-api-keys/#create-api-key) ## Choosing a collector distribution Your first decision is which collector distribution to use: * **[OpenTelemetry Collector Contrib](https://github.com/open-telemetry/opentelemetry-collector-releases/releases):** The community-maintained distribution that includes Azure [receivers](https://opentelemetry.io/docs/collector/components/receiver/). This is the recommended starting point if you are already using OpenTelemetry across your stack or want a single collector for multiple environments. * **[Custom collector](https://opentelemetry.io/docs/collector/extend/ocb/):** Build your own binary with only the components you need. Include only the components that match the Azure services you want to monitor: * [Azure Blob Receiver](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/azureblobreceiver) * [Azure Event Hub Receiver](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/azureeventhubreceiver) * [Azure Monitor Receiver](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/azuremonitorreceiver) * [Azure Encoding Extension](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/extension/encoding/azureencodingextension) * [Azure Auth Extension](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/extension/azureauthextension) Use the following `builder-config.yaml` to build a custom collector with the Azure components: ```yaml theme={} extensions: - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/azureauthextension v0.149.0 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/encoding/azureencodingextension v0.149.0 receivers: - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/azureblobreceiver v0.149.0 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/azureeventhubreceiver v0.149.0 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/azuremonitorreceiver v0.149.0 ``` ## Collecting traces, logs, and metrics from an Azure Event Hub Azure Event Hub acts as a central hub for telemetry from across your Azure environment. [Configure Azure Monitor](https://learn.microsoft.com/en-us/azure/azure-monitor/platform/diagnostic-settings?tabs=portal) to route diagnostic logs and metrics to an Event Hub, then configure the [Azure Event Hub Receiver](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/azureeventhubreceiver) to collect that telemetry and forward it to Honeycomb. To learn about this approach, visit [Stream Azure monitoring data to an event hub and external partner](https://learn.microsoft.com/en-us/azure/azure-monitor/platform/stream-monitoring-data-event-hubs). This example configuration uses the [Azure Authenticator Extension](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/extension/azureauthextension) to authenticate using a service principal: ```yaml theme={} receivers: azure_event_hub: event_hub: name: hubName namespace: namespace.servicebus.windows.net auth: azure_auth extensions: azure_auth: service_principal: client_id: ${env:AZURE_CLIENT_ID} client_secret: ${env:AZURE_CLIENT_SECRET} tenant_id: ${env:AZURE_TENANT_ID} ``` ## Collecting resource metrics from the Azure Monitor API The Azure Monitor API provides resource-level metrics for your Azure services, such as CPU usage, memory consumption, and request counts. Use the [Azure Monitor Receiver](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/azuremonitorreceiver) to pull these metrics from the Azure Monitor API on a schedule and forward them to Honeycomb. This example configuration uses [Azure Authenticator Extension](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/extension/azureauthextension) to authenticate: ```yaml theme={} receivers: azure_monitor: subscription_ids: ["${subscription_id}"] auth: authenticator: azure_auth resource_groups: - ${resource_groups} services: - Microsoft.EventHub/namespaces - Microsoft.AAD/DomainServices metrics: "microsoft.eventhub/namespaces": # fetch only the metrics listed below: IncomingMessages: [total] # metric IncomingMessages with aggregation "Total" NamespaceCpuUsage: [*] # metric NamespaceCpuUsage with all known aggregations ActiveConnections: [] # metric ActiveConnections with all known aggregations (same as [*]) extensions: azure_auth: managed_identity: client_id: ${client_id} ``` To explore other authentication methods, visit the [Azure Monitor Receiver README](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/azuremonitorreceiver#example-configurations). ## Exporting telemetry to Honeycomb Once your receivers are configured, add an OTLP exporter to send your Azure telemetry to Honeycomb. Use the endpoint that matches the region where your Honeycomb data is stored. Configure an OTLP exporter with your [Honeycomb Ingest API Key](/configure/environments/manage-api-keys/#create-api-key) as a header: ```yaml theme={} exporters: otlp/honeycomb: endpoint: "api.honeycomb.io:443" # US instance #endpoint: "api.eu1.honeycomb.io:443" # EU instance headers: "x-honeycomb-team": "YOUR_API_KEY" ``` By default, Honeycomb routes telemetry to datasets based on the service name in your data. If you want to send specific signal types, such as metrics, to a dedicated dataset, add a second exporter with the `x-honeycomb-dataset` header: ```yaml theme={} exporters: otlp/honeycomb: endpoint: "api.honeycomb.io:443" # US instance #endpoint: "api.eu1.honeycomb.io:443" # EU instance headers: "x-honeycomb-team": "YOUR_API_KEY" otlp/honeycomb_metrics: endpoint: "api.honeycomb.io:443" # US instance #endpoint: "api.eu1.honeycomb.io:443" # EU instance headers: "x-honeycomb-team": "YOUR_API_KEY" "x-honeycomb-dataset": "YOUR_METRICS_DATASET" ``` ## Getting help To ask questions and learn more, join our [Pollinators Community Slack](/troubleshoot/community/#join-pollinators-community-slack). # Send Data with the OpenTelemetry .NET SDK Source: https://docs.honeycomb.io/send-data/dotnet Instrument your .NET application with the OpenTelemetry .NET SDK and send traces, logs, and metrics to Honeycomb. Use the OpenTelemetry .NET SDK to instrument .NET applications in a standard, vendor-agnostic, and future-proof way and send telemetry data to Honeycomb. In this guide, we will walk you through instrumenting with OpenTelemetry for .NET, which will include adding automatic instrumentation to your application. ## Before You Begin Before you can set up automatic instrumentation for your .NET application, you will need to do a few things. ### Prepare Your Development Environment To complete the required steps, you will need: * A working .NET environment * An application written in .NET ### Get Your Honeycomb API Key To send data to Honeycomb, you'll need to [sign up for a free Honeycomb account](https://ui.honeycomb.io/signup) and [create a Honeycomb Ingest API Key](/configure/environments/manage-api-keys/#create-api-key). To get started, you can create a key that you expect to swap out when you deploy to production. Name it something helpful, perhaps noting that it's a getting started key. Make note of your API key; for security reasons, you will not be able to see the key again, and you will need it later! For setup, make sure you check the "Can create datasets" checkbox so that your data will show up in Honeycomb. Later, when you replace this key with a permanent one, you can uncheck that box. If you want to use an API key you previously stored in a secure location, you can also [look up details for Honeycomb API Keys](/configure/environments/manage-api-keys/#find-api-keys) any time in your Environment Settings, and use them to retrieve keys from your storage location. ## Add Automatic Instrumentation Automatic instrumentation is enabled by adding [instrumentation packages](https://www.nuget.org/packages?q=opentelemetry.instrumentation). Add custom, or manual, instrumentation using the OpenTelemetry API. ### Acquire Dependencies Install the OpenTelemetry .NET packages. For example, with the .NET CLI, use: ```shell theme={} dotnet add package OpenTelemetry dotnet add package OpenTelemetry.Extensions.Hosting dotnet add package OpenTelemetry.Instrumentation.AspNetCore dotnet add package OpenTelemetry.Instrumentation.Http ``` ### Initialize Initialize the TracerProvider during application setup. ```csharp theme={} services.AddOpenTelemetry().WithTracing(builder => builder .AddAspNetCoreInstrumentation() .AddHttpClientInstrumentation() .AddOtlpExporter()); ``` ### Configure Use environment variables to configure the OpenTelemetry SDK: ```shell theme={} export OTEL_SERVICE_NAME="your-service-name" export OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf" export OTEL_EXPORTER_OTLP_ENDPOINT="https://api.honeycomb.io:443" # US instance #export OTEL_EXPORTER_OTLP_ENDPOINT="https://api.eu1.honeycomb.io:443" # EU instance export OTEL_EXPORTER_OTLP_HEADERS="x-honeycomb-team=" ``` | Variable | Description | | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `OTEL_SERVICE_NAME` | Service name. When you send data, Honeycomb creates a dataset in which to store your data and uses this as the name. Can be any string. | | `OTEL_EXPORTER_OTLP_PROTOCOL` | The data format that the SDK uses to send telemetry to Honeycomb. For more on data format configuration options, read [Choosing between gRPC and HTTP](/send-data/dotnet/#choosing-between-grpc-and-http). | | `OTEL_EXPORTER_OTLP_ENDPOINT` | Honeycomb endpoint to which you want to send your data. | | `OTEL_EXPORTER_OTLP_HEADERS` | Adds your Honeycomb API Key to the exported telemetry headers for authorization. [Learn how to find your Honeycomb API Key](/configure/environments/manage-api-keys/#find-api-keys). | ### Run Run your application. You will see the incoming requests and outgoing HTTP calls generate traces. ```shell theme={} dotnet run ``` In Honeycomb's UI, you should now see your application's incoming requests and outgoing HTTP calls generate traces. ## Add Custom Instrumentation Automatic instrumentation is the easiest way to get started with instrumenting your code. To get additional insight into your system, you should also add custom, or manual, instrumentation where appropriate. Follow the instructions below to add custom instrumentation to your code. To learn more about custom, or manual, instrumentation, visit the comprehensive set of topics covered by [Manual Instrumentation for .NET](https://opentelemetry.io/docs/languages/net/instrumentation/) in OpenTelemetry's documentation, including the [`System.Diagnostics` API](https://opentelemetry.io/docs/languages/net/manual/) and the [OpenTelemetry Shim](https://opentelemetry.io/docs/languages/net/shim/). ### Add Attributes to Spans Adding attributes to a currently executing span in a trace can be useful. For example, you may have an application or service that handles users and you want to associate the user with the span when querying your dataset in Honeycomb. To do this, get the current span from the context and set an attribute with the user ID: ```csharp theme={} using OpenTelemetry.Trace; //... var currentSpan = Tracer.CurrentSpan; currentSpan.SetAttribute("user.id", User.GetUserId()) ``` This configuration will add a `user.id` attribute to the current span, so you can use the field in `WHERE`, `GROUP BY`, or `ORDER` clauses in the Honeycomb query builder. ### Acquire a Tracer To create spans, you need to acquire a `Tracer`. ```csharp theme={} using OpenTelemetry.Trace; //... var tracer = TracerProvider.Default.GetTracer("tracer.name.here"); ``` Then, inject the `Tracer` instance with ASP.NET Core dependency injection or manage its lifecycle manually. When you create a `Tracer`, OpenTelemetry requires you to give it a name as a string. This string is the only required parameter. When traces are sent to Honeycomb, the name of the `Tracer` is turned into the `library.name` field, which can be used to show all spans created from a particular tracer. In general, pick a name that matches the appropriate scope for your traces. If you have one tracer for each service, then use the service name. If you have multiple tracers that live in different "layers" of your application, then use the name that corresponds to that "layer". The `library.name` field is also used with traces created from instrumentation libraries. ### Create New Spans To get the full picture of what is happening, you can leverage manual instrumentation to create custom spans that describe what is happening in your application. To do this, grab your tracer instance and use it to create a span: ```csharp theme={} using OpenTelemetry.Trace; //... using var span = TracerProvider.Default.GetTracer("my-service").StartActiveSpan("expensive-query") // ... do cool stuff ``` ### Add Multi-Span Attributes Sometimes you want to add the same attribute to many spans within the same trace. This attribute may include variables calculated during your program, or other useful values for correlation or debugging purposes. To add this attribute to multiple spans, leverage the OpenTelemetry concept of [baggage](https://opentelemetry.io/docs/concepts/signals/baggage/). Baggage allows you to add a `key` with a `value` as an attribute to every subsequent child span of the current application context. 1. Install the OpenTelemetry.Extensions package with the .NET CLI: ```shell theme={} dotnet add package OpenTelemetry.Extensions --prerelease ``` 2. When configuring the OpenTelemetry SDK tracer provider, add the `BaggageActivityProcessor`: ```csharp theme={} services.AddOpenTelemetry().WithTracing(builder => builder .SetResourceBuilder(ResourceBuilder.CreateDefault().AddService(serviceName)) .AddBaggageActivityProcessor() .AddOtlpExporter(option => { option.Endpoint = new Uri("https://api.honeycomb.io"); // US instance //option.Endpoint = new Uri("https://api.eu1.honeycomb.io"); // EU instance option.Headers = $"x-honeycomb-team={honeycombApiKey}"; })); ``` 3. Add a baggage entry for the current trace and replace `key` and `value` with your desired key-value pair: ```csharp theme={} Baggage.Current.SetBaggage("key", "value"); ``` Any Baggage attributes that you set in your application will be attached to outgoing network requests as a header. If your service communicates to a third party API, do **NOT** put sensitive information in the Baggage attributes. ## Sampling You can configure the OpenTelemetry SDK to [sample the data](/manage-data-volume/sample/guidelines/) it generates. Honeycomb [weights sampled data based on sample rate](/manage-data-volume/sample/sampled-data-in-honeycomb/), so you must set a resource attribute containing the sample rate. Use a [`TraceIdRatioBased` sampler](https://opentelemetry.io//docs/specs/otel/trace/sdk/#traceidratiobased), with a ratio expressed as `1/N`. Then, also create a resource attribute called `SampleRate` with the value of `N`. This allows Honeycomb to reweigh scalar values, like counts, so that they are accurate even with sampled data. In the example below, our goal is to keep approximately half (1/2) of the data volume. The resource attribute contains the denominator (2), while the OpenTelemetry sampler argument contains the decimal value (0.5). ```csharp theme={} services.AddOpenTelemetry().WithTracing((builder) => builder .SetResourceBuilder(ResourceBuilder.CreateDefault() .AddService(serviceName) // IMPORTANT: add a SampleRate of 2 as a resource attribute .AddAttributes(new[] { new KeyValuePair("SampleRate", 2) }) ) .SetSampler(new TraceIdRatioBasedSampler(0.5)) // sampler .AddAspNetCoreInstrumentation() .AddHttpClientInstrumentation() .AddOtlpExporter(option => { option.Endpoint = new Uri("https://api.honeycomb.io"); // US instance //option.Endpoint = new Uri("https://api.eu1.honeycomb.io"); // EU instance option.Headers = $"x-honeycomb-team={honeycombApiKey}"; })); ``` ## Choosing between gRPC and HTTP Most OpenTelemetry SDKs have an option to export telemetry as OTLP either over gRPC or HTTP/protobuf, with some also offering HTTP/JSON. If you are trying to choose between gRPC and HTTP, keep in mind: * Some SDKs default to using gRPC, and it may be easiest to start with the default option. * Some firewall policies are not set up to handle gRPC and require using HTTP. * gRPC may improve performance, but its long-lived connections may cause problems with load balancing, especially when using Refinery. gRPC default export uses port 4317, whereas HTTP default export uses port 4318. ## Endpoint URLs for OTLP/HTTP When using the `OTEL_EXPORTER_OTLP_ENDPOINT` environment variable with an SDK and an HTTP exporter, the final path of the endpoint is modified by the SDK to represent the specific signal being sent. For example, when exporting trace data, the endpoint is updated to append `v1/traces`. When exporting metrics data, the endpoint is updated to append `v1/metrics`. So, if you were to set the `OTEL_EXPORTER_OTLP_ENDPOINT` to `https://api.honeycomb.io`, traces would be sent to `https://api.honeycomb.io/v1/traces` and metrics would be sent to `https://api.honeycomb.io/v1/metrics`. The same modification is not necessary for gRPC. ```shell theme={} export OTEL_EXPORTER_OTLP_ENDPOINT=https://api.honeycomb.io # US instance #export OTEL_EXPORTER_OTLP_ENDPOINT=https://api.eu1.honeycomb.io # EU instance ``` If the desired outcome is to send data to a different endpoint depending on the signal, use `OTEL_EXPORTER_OTLP__ENDPOINT` instead of the more generic `OTEL_EXPORTER_OTLP_ENDPOINT`. When using a signal-specific environment variable, these paths must be appended manually. Set `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` for traces, appending the endpoint with `v1/traces`, and `OTEL_EXPORTER_OTLP_METRICS_ENDPOINT` for metrics, appending the endpoint with `v1/metrics`. Send both traces and metrics to Honeycomb using this method by setting the following variables: ```shell theme={} export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://api.honeycomb.io/v1/traces # US instance #export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://api.eu1.honeycomb.io/v1/traces # EU instance export OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=https://api.honeycomb.io/v1/metrics # US instance #export OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=https://api.eu1.honeycomb.io/v1/metrics # EU instance ``` More details about endpoints and signals can be found in the [OpenTelemetry Specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md). ## URL Query String Parameter Value Redaction The [Instrumentation.AspNetCore-1.8.1](https://github.com/open-telemetry/opentelemetry-dotnet/releases/tag/Instrumentation.AspNetCore-1.8.1) and [Instrumentation.Http-1.8.1](https://github.com/open-telemetry/opentelemetry-dotnet/releases/tag/Instrumentation.Http-1.8.1) instrumentation packages redact query string parameter values by default. For example, a query string parameter of `key=value` would be added as a span attribute with a name of `url.query` and a value of `key=Redacted`. You can disable this redaction by setting the environment variable `OTEL_DOTNET_EXPERIMENTAL_HTTPCLIENT_DISABLE_URL_QUERY_REDACTION` to `true`. ## Troubleshooting To explore common issues when sending data, visit [Common Issues with Sending Data in Honeycomb](/troubleshoot/common-issues/sending-data/#opentelemetry-sdks-and-honeycomb-distributions). # Collect Telemetry from Google Cloud Platform Source: https://docs.honeycomb.io/send-data/gcp Send Google Cloud Platform telemetry to Honeycomb using an OpenTelemetry Collector. Deploy an OpenTelemetry (OTel) Collector to ingest telemetry from Google Cloud Platform (GCP) services and send it to Honeycomb. Analyzing your GCP telemetry with Honeycomb lets you answer questions like: * How did response time change after scaling up my Cloud Run services? * What is the error rate for my Pub/Sub topics? * How does application performance vary across GCP regions? * Are application errors happening in specific services, or across the entire environment? * Are there any performance bottlenecks in my Cloud SQL or Firestore operations? ## Before you begin Before you begin, make sure you have: * A [Google Cloud account](https://docs.cloud.google.com/docs/get-started) with appropriate admin privileges * Access to a GCP project you want to monitor * A [Honeycomb Ingest API Key](/configure/environments/manage-api-keys/#create-api-key) ## Choosing a collector distribution Your first decision is which collector distribution to use: * **[OpenTelemetry Collector Contrib](https://github.com/open-telemetry/opentelemetry-collector-releases/releases):** The community-maintained distribution that includes GCP receivers. This is the recommended starting point if you are already using OpenTelemetry across your stack or want a single collector for multiple environments. * **[Google's collector distribution](https://github.com/GoogleCloudPlatform/opentelemetry-operations-collector/tree/v0.144.0/google-built-opentelemetry-collector):** Google's own build, optimized for GCP environments. Consider this if you are running entirely on GCP and want tighter integration with Google's deployment tooling. * **[Custom collector](https://opentelemetry.io/docs/collector/extend/ocb/):** Build your own binary with only the components you need. Include only the components that match the GCP services you want to monitor: * [Google Cloud Monitoring Receiver](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/googlecloudmonitoringreceiver) * [Google Pub/Sub Receiver](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/googlecloudpubsubreceiver) * [Google Cloud Spanner Receiver](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/googlecloudspannerreceiver) * [Google Cloud LogEntry Encoding Extension](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/extension/encoding/googlecloudlogentryencodingextension) * [Google Client Auth Extension](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/extension/googleclientauthextension) * [Google Secrets Provider](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/confmap/provider/googlesecretmanagerprovider) Use the following `builder-config.yaml` to build a custom collector with the GCP components you need: ```yaml theme={} extensions: - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/encoding/googlecloudlogentryencodingextension v0.149.0 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/extension/googleclientauthextension v0.149.0 receivers: - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/googlecloudmonitoringreceiver v0.149.0 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/googlecloudpubsubreceiver v0.149.0 - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/receiver/googlecloudspannerreceiver v0.149.0 providers: - gomod: github.com/open-telemetry/opentelemetry-collector-contrib/confmap/provider/googlesecretmanagerprovider v0.149.0 ``` ## Deploying an OpenTelemetry Collector Deploy your collector in the same GCP environment as the services you want to monitor. This minimizes network latency and simplifies authentication using GCP's built-in identity mechanisms. Google Cloud offers deployment guides for several environments. These guides focus on the Google-built OpenTelemetry Collector, but you can adapt them for other distributions. Follow the guide for your environment: * [Deploy on Google Kubernetes Engine](https://docs.cloud.google.com/stackdriver/docs/instrumentation/opentelemetry-collector-gke) * [Deploy on Container-Optimized OS](https://docs.cloud.google.com/stackdriver/docs/instrumentation/opentelemetry-collector-cos) * [Deploy on Cloud Run](https://docs.cloud.google.com/stackdriver/docs/instrumentation/opentelemetry-collector-cloud-run) * [Deploy on Compute Engine](https://docs.cloud.google.com/stackdriver/docs/instrumentation/opentelemetry-collector-gce) ## Collecting Google Cloud Run function metrics The [Google Cloud Monitoring Receiver](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/v0.147.0/receiver/googlecloudmonitoringreceiver) pulls metrics from the Cloud Monitoring API on a schedule, making it useful for infrastructure-level data like instance counts, execution times, and memory usage. The receiver accepts a list of metric names; to explore available metrics, visit [Google's Cloud Monitoring documentation](https://docs.cloud.google.com/monitoring/api/metrics). This example configuration collects [Google Cloud Run function metrics](https://docs.cloud.google.com/monitoring/api/metrics_gcp_c#gcp-cloudfunctions): ```yaml theme={} receivers: googlecloudmonitoring: collection_interval: 2m project_id: your-gcp-project-id metrics_list: - metric_name: "cloudfunctions.googleapis.com/function/active_instances" - metric_name: "cloudfunctions.googleapis.com/function/execution_count" - metric_name: "cloudfunctions.googleapis.com/function/execution_times" - metric_name: "cloudfunctions.googleapis.com/function/instance_count" - metric_name: "cloudfunctions.googleapis.com/function/network_egress" - metric_name: "cloudfunctions.googleapis.com/function/user_memory_bytes" - metric_name: "cloudfunctions.googleapis.com/pending_queue/pending_requests" processors: batch: {} exporters: otlp/honeycomb_metrics: endpoint: "api.honeycomb.io:443" # US instance #endpoint: "api.eu1.honeycomb.io:443" # EU instance headers: "x-honeycomb-team": "YOUR_API_KEY" # your Honeycomb Ingest API key # "x-honeycomb-dataset": "YOUR_DATASET_NAME" # optional service: pipelines: metrics: receivers: [googlecloudmonitoring] processors: [batch] exporters: [otlp/honeycomb_metrics] ``` ## Collecting traces, logs, and metrics from Google Pub/Sub Pub/Sub is a natural integration point for telemetry in GCP because many services can publish to a topic, and the receiver handles consuming and forwarding that data without additional configuration overhead. Use the [Google Pub/Sub Receiver](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/googlecloudpubsubreceiver) to collect telemetry from a Google Pub/Sub subscription. The following example configuration collects telemetry from a Pub/Sub subscription: ```yaml theme={} receivers: googlecloudpubsub: project: your-project subscription: projects/your-project/subscriptions/otlp-logs ``` ## Collecting database metrics from Google Cloud Spanner The Spanner Receiver collects query and transaction metrics directly from Spanner's built-in statistics tables, giving you visibility into slow queries, lock contention, and data volume without requiring application-level instrumentation. Use the [Google Cloud Spanner Receiver](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/googlecloudspannerreceiver) to collect query, transaction, and other metrics from your databases. The following example configuration collects metrics from two Spanner instances across a single project: ```yaml theme={} receivers: googlecloudspanner: collection_interval: 60s initial_delay: 1s top_metrics_query_max_rows: 100 backfill_enabled: true cardinality_total_limit: 200000 hide_topn_lockstats_rowrangestartkey: false truncate_text: false projects: - project_id: "spanner project 1" service_account_key: "path to spanner project 1 service account json key" instances: - instance_id: "id1" databases: - "db11" - "db12" - instance_id: "id2" databases: - "db21" - "db22" ``` ## Exporting telemetry to Honeycomb Once your receivers are configured, add an OTLP exporter to send your GCP telemetry to Honeycomb. Use the endpoint that matches the region where your Honeycomb data is stored. Configure an OTLP exporter with your [Honeycomb Ingest API Key](/configure/environments/manage-api-keys/#create-api-key) as a header: ```yaml theme={} exporters: otlp/honeycomb: endpoint: "api.honeycomb.io:443" # US instance #endpoint: "api.eu1.honeycomb.io:443" # EU instance headers: "x-honeycomb-team": "YOUR_API_KEY" ``` By default, Honeycomb routes telemetry to datasets based on the service name in your data. If you want to send specific signal types, such as metrics, to a dedicated dataset, add a second exporter with the `x-honeycomb-dataset` header: ```yaml theme={} exporters: otlp/honeycomb: endpoint: "api.honeycomb.io:443" # US instance #endpoint: "api.eu1.honeycomb.io:443" # EU instance headers: "x-honeycomb-team": "YOUR_API_KEY" otlp/honeycomb_metrics: endpoint: "api.honeycomb.io:443" # US instance #endpoint: "api.eu1.honeycomb.io:443" # EU instance headers: "x-honeycomb-team": "YOUR_API_KEY" "x-honeycomb-dataset": "YOUR_METRICS_DATASET" ``` ## Getting help To ask questions and learn more, join our [Pollinators Community Slack](/troubleshoot/community/#join-pollinators-community-slack). # Send Data to Honeycomb with Go Source: https://docs.honeycomb.io/send-data/go Explore available methods for sending telemetry from your Go application to Honeycomb. When you are working with Go, we recommend these methods of sending data to Honeycomb. When you want to instrument Go applications in a standard, vendor-agnostic, and future-proof way, we recommend using the OpenTelemetry Go SDK to send telemetry data to Honeycomb. The OpenTelemetry Go SDK allows you to send traces and metrics. Logs is in development. When you need to create and send structured logs to Honeycomb, use Libhoney for Go, our structured logging library for Go applications. # Send Logs with Libhoney for Go Source: https://docs.honeycomb.io/send-data/go/libhoney Send structured events to Honeycomb from your Go application using Libhoney, Honeycomb's low-level structured logging library for the Events API. Libhoney for Go is Honeycomb's structured logging library for Go applications. It is a low-level library that helps you send structured events to Honeycomb's [Events API](/api/events/). If you are instrumenting a new application for tracing, we recommend that you use [OpenTelemetry](/send-data/opentelemetry/) instead. ## Installation ```shell theme={} go get -v github.com/honeycombio/libhoney-go ``` ## Links * [API Reference](https://godoc.org/github.com/honeycombio/libhoney-go) * [Source Code](https://github.com/honeycombio/libhoney-go) * [Examples](https://github.com/honeycombio/libhoney-go/tree/main/examples) ## Initialization Initialize the library by passing in your Team API key and the default dataset name to which it should send events. When you call the library's initialization routine, it spins up background threads to handle sending all the events. You must shut down these background threads on shutdown by calling `libhoney.Close()`. ```go theme={} libhoney.Init(libhoney.Config{ WriteKey: "YOUR_API_KEY", Dataset: "honeycomb-golang-example", }) defer libhoney.Close() // Flush any pending calls to Honeycomb ``` Further configuration options can be found [in the API reference](https://godoc.org/github.com/honeycombio/libhoney-go#Config). `libhoney.Config` also contains an `APIHost` key, which defaults to Honeycomb's API server. Overriding this with an empty string is a good way to drop events in a test environment. ## Building and Sending Events Once initialized, `libhoney` is ready to send events. Events go through three phases: * Creation `event := builder.NewEvent()` * Adding fields `event.AddField("key", "val")`, `event.Add(dataMap)` * Transmission `event.Send()` Upon calling `.Send()`, the event is dispatched to be sent to Honeycomb. All libraries set defaults that will allow your application to function as smoothly as possible during error conditions. When creating events faster than they can be sent, overflowed events will be dropped instead of backing up and slowing down your application. In its simplest form, you can add a single attribute to an event with the `.AddField(k, v)` method. If you add the same key multiple times, only the last value added will be kept. More complex structures (maps and structs—things that can be serialized into a JSON object) can be added to an event with the `.Add(data)` method. Events can have metadata associated with them that is not sent to Honeycomb. This metadata is used to identify the event when processing the response. More detail about metadata is below in the Response section. ## Handling Responses Sending an event is an asynchronous action and will avoid blocking by default. `.Send()` will enqueue the event to be sent as soon as possible (thus, the return value does not indicate that the event was successfully sent). Use the `chan` returned by `.Responses()` to check whether events were successfully received by Honeycomb's servers. Before sending an event, you have the option to attach metadata to that event. This metadata is not sent to Honeycomb; instead, it is used to help you match up individual responses with sent events. When sending an event, `libhoney` will take the metadata from the event and attach it to the response object for you to consume. Add metadata by populating the `.Metadata` attribute directly on an event. Responses have a number of fields describing the result of an attempted event send: * **Metadata**: the metadata you attached to the event to which this response corresponds * **StatusCode**: the HTTP status code returned by Honeycomb when trying to send the event. `2xx` indicates success. * **Duration**: the `time.Duration` it took to send the event. * **Body**: the body of the HTTP response from Honeycomb. On failures, this body contains some more information about the failure. * **Err**: when the event does not even get to create a HTTP attempt, the reason will be in this field. (For example, when sampled or dropped because of a queue overflow.) You do not have to process responses if you are not interested in them—simply ignoring them is perfectly safe. Unread responses will be dropped. ## Examples Honeycomb can calculate all sorts of statistics, so send the data you care about and let us crunch the averages, percentiles, lower/upper bounds, cardinality—whatever you want—for you. ### Simple: Send an Event ```go theme={} import "github.com/honeycombio/libhoney-go" // Call Init to configure libhoney libhoney.Init(libhoney.Config{ WriteKey: "YOUR_API_KEY", Dataset: "honeycomb-golang-example", }) defer libhoney.Close() // Flush any pending calls to Honeycomb ev := libhoney.NewEvent() ev.Add(map[string]interface{}{ "duration_ms": 153.12, "method": "get", "hostname": "appserver15", "payload_length": 27, }) ev.Send() ``` ### Intermediate: Populate an Event Over Time You do not need to know all of the fields that should be added to an event up front. In fact, it is very common to add fields to an event as circumstances change or as new information comes in. For example, you might want to indicate success or failure, and if a failure occurred, you will want to submit the associated error message. ```go theme={} import "github.com/honeycombio/libhoney-go" func main() { // Call Init to configure libhoney libhoney.Init(libhoney.Config{ WriteKey: "YOUR_WRITE_KEY", Dataset: "honeycomb-golang-example", }) // Flush any pending calls to Honeycomb before exiting defer libhoney.Close() // Create an event, add some data ev := libhoney.NewEvent() ev.Add(map[string]interface{}{ "method": "get", "hostname": "appserver15", "payload_length": 27, })) // This event will be sent regardless of how we exit defer ev.Send() if err := myOtherFunc(); err != nil { ev.AddField("error", err.Error()) ev.AddField("success", false) return } // do some work, maybe measure some things ev.AddField("duration_ms", 153.12) ev.AddField("success", true) } ``` ### Intermediate: Override Some Attributes ```go theme={} // ... Initialization code ... params := map[string]interface{}{ "hostname": "foo.local", "built": false, "user_id": -1, } libhoney.Add(params) builder := libhoney.NewBuilder() builder.AddField("built", true) // Spawn a new event and override the timestamp event := builder.NewEvent() event.AddField("user_id", 15) event.AddField("latency_ms", time.Since(start).Milliseconds()) event.Timestamp = time.Date(2016, time.February, 29, 1, 1, 1, 0, time.UTC) event.Send() ``` Further examples can be found [on GitHub](https://github.com/honeycombio/libhoney-go). ## Advanced Usage: Utilizing Builders Builders are, at their simplest, a convenient way to avoid repeating common attributes that may not apply globally. Creating a builder for a given component allows a variety of different events to be spawned and sent within the component, without having to repeat the component name as an attribute for each. You can clone builders—the cloned builder will have a copy of all the fields and dynamic fields in the original. As your application forks down into more and more specific functionality, you can create more detailed builders. The final event creation in the leaves of your application's tree will have all the data you have added along the way in addition to the specifics of this event. The global scope is essentially a specialized builder, for capturing attributes that are likely useful to all events (for example, hostname or environment). Adding this kind of peripheral and normally unavailable information to every event gives you enormous power to identify patterns that would otherwise be invisible in the context of a single request. ## Advanced Usage: Dynamic Fields The top-level `libhoney` and Builders support `.AddDynamicField(func)`. Adding a dynamic field to a Builder or top-level `libhoney` ensures that each time an event is created, the provided function is executed and the returned key/value pair is added to the event. This may be useful for including dynamic process information such as memory used, number of threads, concurrent requests, and so on to each event. Adding this kind of dynamic data to an event makes it easy to understand the application's context when looking at an individual event or error condition. ## Troubleshooting Refer to [Common Issues with Sending Data in Honeycomb](/troubleshoot/common-issues/sending-data/#libhoney). ## Contributions Features, bug fixes and other changes to `libhoney` are gladly accepted. Please open issues or a pull request with your change. Remember to add your name to the CONTRIBUTORS file! All contributions will be released under the Apache License 2.0. # Send Data with the OpenTelemetry Go SDK Source: https://docs.honeycomb.io/send-data/go/opentelemetry-sdk Instrument your Go application with the OpenTelemetry Go SDK and send traces and metrics to Honeycomb. Use the OpenTelemetry Go SDK to instrument Go applications in a standard, vendor-agnostic, and future-proof way and send telemetry data to Honeycomb. In this guide, we will walk you through instrumenting with OpenTelemetry for Go, which will include adding automatic instrumentation to your application. ## Before You Begin Before you can set up automatic instrumentation for your Go application, you will need to do a few things. ### Prepare Your Development Environment To complete the required steps, you will need: * A working Go environment * An application written in Go ### Get Your Honeycomb API Key To send data to Honeycomb, you'll need to [sign up for a free Honeycomb account](https://ui.honeycomb.io/signup) and [create a Honeycomb Ingest API Key](/configure/environments/manage-api-keys/#create-api-key). To get started, you can create a key that you expect to swap out when you deploy to production. Name it something helpful, perhaps noting that it's a getting started key. Make note of your API key; for security reasons, you will not be able to see the key again, and you will need it later! For setup, make sure you check the "Can create datasets" checkbox so that your data will show up in Honeycomb. Later, when you replace this key with a permanent one, you can uncheck that box. If you want to use an API key you previously stored in a secure location, you can also [look up details for Honeycomb API Keys](/configure/environments/manage-api-keys/#find-api-keys) any time in your Environment Settings, and use them to retrieve keys from your storage location. ## Configure OpenTelemetry SDK To configure the OpenTelemetry SDK and enable automatic instrumentation of HTTP requests in your application, you will add the following packages to your application. ### Acquire Dependencies Install OpenTelemetry Go packages: ```shell theme={} go get \ go.opentelemetry.io/contrib/otelconf/x \ go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp ``` ### Initialize Prepare your application to send spans to Honeycomb. Open or create a file called `main.go`: ```go theme={} package main import ( "context" "fmt" "log" "net/http" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" otelconf "go.opentelemetry.io/contrib/otelconf/x" "go.opentelemetry.io/otel" ) // Implement an HTTP Handler function to be instrumented func httpHandler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hello, World") } func main() { // Use otelconf/x to set up the OpenTelemetry SDK. The `/x` package // adds support for experimental spec fields such as resource detectors. sdk, err := otelconf.NewSDK() if err != nil { log.Fatalf("error setting up OTel SDK - %e", err) } defer sdk.Shutdown(context.Background()) otel.SetTracerProvider(sdk.TracerProvider()) otel.SetTextMapPropagator(sdk.Propagator()) // Initialize HTTP handler instrumentation handler := http.HandlerFunc(httpHandler) wrappedHandler := otelhttp.NewHandler(handler, "hello") http.Handle("/hello", wrappedHandler) // Serve HTTP server log.Fatal(http.ListenAndServe(":3030", nil)) } ``` ### Configure Create an `otelconfig.yaml` file with the following content: ```yaml theme={} file_format: "1.1" resource: attributes: - name: service.name value: ${OTEL_SERVICE_NAME:-my-service} tracer_provider: processors: - batch: exporter: otlp_http: endpoint: https://api.honeycomb.io/v1/traces # Use the endpoint below for EU # endpoint: https://api.eu1.honeycomb.io/v1/traces headers: - name: x-honeycomb-team value: ${HONEYCOMB_API_KEY} propagator: composite: - tracecontext: - baggage: ``` Set the following environment variables before running your application: | Environment Variable | Value | | :------------------- | :----------------------- | | `HONEYCOMB_API_KEY` | Your Honeycomb API key | | `OTEL_SERVICE_NAME` | The name of your service | When `OTEL_CONFIG_FILE` is set, the configuration file is the single source of truth for the SDK. Other `OTEL_*` environment variables are ignored by design, so set all SDK options in the YAML file. You can still reference environment variables from inside the YAML using `${VAR_NAME}` substitution. The OpenTelemetry declarative configuration is stable at the specification level. Individual fields still under active development are marked with a `/development` suffix in the YAML (see [configuration versioning](https://github.com/open-telemetry/opentelemetry-configuration/blob/main/VERSIONING.md#experimental-features)). Check the [language support status](https://github.com/open-telemetry/opentelemetry-configuration/blob/main/language-support-status.md) for per-SDK maturity. Add `meter_provider` and `logger_provider` sections to the same file to export metrics and logs. This version also enables resource detectors, which add attributes such as `host.*` and `process.*` automatically: ```yaml theme={} file_format: "1.1" resource: attributes: - name: service.name value: ${OTEL_SERVICE_NAME:-my-service} detection/development: detectors: - host: - container: - process: - service: tracer_provider: # traces processors: - batch: exporter: otlp_http: endpoint: https://api.honeycomb.io/v1/traces headers: - name: x-honeycomb-team value: ${HONEYCOMB_API_KEY} meter_provider: # metrics readers: - periodic: exporter: otlp_http: endpoint: https://api.honeycomb.io/v1/metrics headers: - name: x-honeycomb-team value: ${HONEYCOMB_API_KEY} # Legacy metrics only; omit with the current metrics experience: # - name: x-honeycomb-dataset # value: ${HONEYCOMB_METRICS_DATASET} logger_provider: # logs processors: - batch: exporter: otlp_http: endpoint: https://api.honeycomb.io/v1/logs headers: - name: x-honeycomb-team value: ${HONEYCOMB_API_KEY} propagator: composite: - tracecontext: - baggage: ``` For the EU instance, replace `https://api.honeycomb.io` with `https://api.eu1.honeycomb.io` throughout the file. If you use [Honeycomb Classic](/troubleshoot/product-lifecycle/recommended-migrations/#migrate-from-honeycomb-classic-to-honeycomb-environments), you must also specify the Dataset for traces using the `x-honeycomb-dataset` header: ```yaml theme={} headers: - name: x-honeycomb-team value: ${HONEYCOMB_API_KEY} - name: x-honeycomb-dataset value: your-dataset ``` ### Run Point the SDK at your configuration file using the `OTEL_CONFIG_FILE` environment variable, then run your application: ```shell theme={} OTEL_CONFIG_FILE=./otelconfig.yaml go run YOUR_APPLICATION_NAME.go ``` Be sure to replace `YOUR_APPLICATION_NAME` with the name of your application's main file. In Honeycomb's UI, you should now see your application's incoming requests and outgoing HTTP calls generate traces. ## Add Custom Instrumentation Automatic instrumentation is the easiest way to get started with instrumenting your code. To get additional insight into your system, you should also add custom, or manual, instrumentation where appropriate. Follow the instructions below to add custom instrumentation to your code. To learn more about custom, or manual, instrumentation, visit the comprehensive set of topics covered by [Manual Instrumentation for Go](https://opentelemetry.io/docs/languages/go/instrumentation/) in OpenTelemetry's documentation. ### Acquire a Tracer To create spans, you need to acquire a `Tracer`. ```go theme={} import ( // ... "go.opentelemetry.io/otel" // ... ) // ... tracer := otel.Tracer("tracer.name.here") ``` When you create a `Tracer`, OpenTelemetry requires you to give it a name as a string. This string is the only required parameter. When traces are sent to Honeycomb, the name of the `Tracer` is turned into the `library.name` field, which can be used to show all spans created from a particular tracer. In general, pick a name that matches the appropriate scope for your traces. If you have one tracer for each service, then use the service name. If you have multiple tracers that live in different "layers" of your application, then use the name that corresponds to that "layer". The `library.name` field is also used with traces created from instrumentation libraries. ### Add Attributes to Spans Adding context to a currently executing span in a trace can be useful. For example, you may have an application or service that handles users, and you want to associate the user with the span when querying your dataset in Honeycomb. To do this, get the current span from the context and set an attribute with the user ID. This example assumes you are writing a web application with the `net/http` package: ```go theme={} import ( // ... "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" // ... ) // ... handler := func(w http.ResponseWriter, r *http.Request) { user := someServiceCall() // get the currently logged in user ctx := r.Context() span := trace.SpanFromContext(ctx) span.SetAttributes(attribute.Int("user.id", user.getID())) } // ... ``` This will add a `user.id` field to the current span, so you can use the field in `WHERE`, `GROUP BY`, or `ORDER` clauses in the Honeycomb query builder. ### Create Spans To get the full picture of what is happening, you can leverage manual instrumentation to create custom spans that describe what is happening in your application. To do this, grab the tracer from the OpenTelemetry API: ```go theme={} import ( // ... "go.opentelemetry.io/otel" // ... ) // ... tracer := otel.Tracer("my-app") // if not already in scope ctx, span := tracer.Start(ctx, "expensive-operation") defer span.End() // ... ``` ### Add Multi-Span Attributes Sometimes you want to add the same attribute to many spans within the same trace. This attribute may include variables calculated during your program, or other useful values for correlation or debugging purposes. To add this attribute to multiple spans, leverage the OpenTelemetry concept of [baggage](https://opentelemetry.io/docs/concepts/signals/baggage/). Baggage allows you to add a `key` with a `value` as an attribute to every subsequent child span of the current application context, as long as you configured a `BaggageSpanProcessor` when you [initialized OpenTelemetry](#configure-opentelemetry-sdk). 1. Install the `baggagetrace` package in your terminal: ```shell theme={} go get go.opentelemetry.io/contrib/processors/baggage/baggagetrace ``` 2. When configuring the OpenTelemetry SDK tracer provider, add the baggage span processor: ```golang theme={} import ( // ... "go.opentelemetry.io/contrib/processors/baggage/baggagetrace" // ... ) // Create a new tracer provider with the baggage span processor tp := trace.NewTracerProvider( baggagetrace.New() // ... ) ``` 3. Add a baggage entry for the current trace and replace `key` and `value` with your desired key-value pair: ```go theme={} import ( // ... "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" "go.opentelemetry.io/otel/baggage" // ... ) // ... handler := func(w http.ResponseWriter, r *http.Request) { ctx := r.Context() // add the user ID attribute to baggage and create new context bag := baggage.FromContext(ctx) multiSpanAttribute, _ := baggage.NewMember("key", "value") bag, _ = bag.SetMember(multiSpanAttribute) ctx = baggage.ContextWithBaggage(ctx, bag) tracer := otel.Tracer("my-app") // if not already in scope // every subsequent span created from this context, and any of its child spans, // will have the user ID attribute from baggage ctx, span := tracer.Start(ctx, "expensive-operation") defer span.End() } // ... ``` Any Baggage attributes that you set in your application will be attached to outgoing network requests as a header. If your service communicates to a third party API, do **NOT** put sensitive information in the Baggage attributes. ## Automatic Instrumentation using eBPF To instrument http and gRPC requests in Go, usually you must wrap requests with OpenTelemetry instrumentation libraries. However, a [new project](https://github.com/open-telemetry/opentelemetry-go-instrumentation) allows for automatic instrumentation of http and gRPC requests using [eBPF](/get-started/basics/observability/concepts/ebpf/), which requires no application code changes. Because the automatic instrumentation uses eBPF, it requires a Linux kernel. Automatic instrumentation should work on any Linux kernel above 4.4. For most cloud-native applications, this means you must include the Docker image to run as an agent in a container for each application. ### Configure You must configure the following options for each instrumented application: * Your application path, specified by `OTEL_GO_AUTO_TARGET_EXE`, is where the agent will watch for processes. * Your endpoint, specified by `OTEL_EXPORTER_OTLP_ENDPOINT`, is where telemetry will be sent. * Your service name, specified by `OTEL_SERVICE_NAME`, will be used as the Service Dataset in Honeycomb, which is where data is stored. Configure an [OpenTelemetry Collector](/send-data/opentelemetry/collector/) to receive traces over OTLP/gRPC and export those traces to Honeycomb. Then follow the instructions for [deployment in Kubernetes](#running-in-kubernetes) or [from source on a Linux machine](#running-on-a-linux-machine). ### Running in Kubernetes The automatic instrumentation agent runs in the same container node as your application. The agent requires `shareProcessNamespace`, as well as some elevated permissions in `securityContext`. The following example shows what a deployment `spec.template.spec` could look like with an existing application called "my-service": ```yaml theme={} spec: shareProcessNamespace: true securityContext: {} terminationGracePeriodSeconds: 30 containers: - name: my-service image: my-service:v42 ports: - containerPort: 7007 name: http - name: my-service-instrumentation image: ghcr.io/open-telemetry/opentelemetry-go-instrumentation/autoinstrumentation-go:v0.2.0-alpha env: - name: OTEL_GO_AUTO_TARGET_EXE value: /app/my-service - name: OTEL_EXPORTER_OTLP_ENDPOINT value: http://otel-collector:4317 - name: OTEL_SERVICE_NAME value: my-service-name securityContext: runAsUser: 0 capabilities: add: - SYS_PTRACE privileged: true ``` #### Example If you prefer to learn by example, we provide an [example application](https://github.com/honeycombio/example-greeting-service/tree/main/go-auto-instrumented) that illustrates a Kubernetes deployment. ### Running on a Linux Machine If the application is running in Linux, an alternative to Kubernetes is to build and run the instrumentation from source. To use the instrumentation without a Docker image, build a binary [from source](https://github.com/open-telemetry/opentelemetry-go-instrumentation) and save as `otel-go-instrumentation`. Set environment variables for the application, service name, and endpoint, and pass into a run command with the instrumentation. The following example shows how to enable instrumentation for an application running in `~/app/my-service`: ```bash theme={} OTEL_GO_AUTO_TARGET_EXE=~/app/my-service \ # application being instrumented OTEL_SERVICE_NAME=my-service \ # name of service in telemetry data OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317 \ # send to collector ./otel-go-instrumentation ``` Because eBPF has powerful capabilities, running this instrumentation may require additional privileges on the host, such as running with the `sudo` command. ## Sampling You can configure the OpenTelemetry SDK to [sample the data](/manage-data-volume/sample/guidelines/) it generates. Honeycomb [weights sampled data based on sample rate](/manage-data-volume/sample/sampled-data-in-honeycomb/), so you must set a resource attribute containing the sample rate. Use a [`TraceIdRatioBased` sampler](https://opentelemetry.io//docs/specs/otel/trace/sdk/#traceidratiobased), with a ratio expressed as `1/N`. Then, also create a resource attribute called `SampleRate` with the value of `N`. This allows Honeycomb to reweigh scalar values, like counts, so that they are accurate even with sampled data. In the example below, our goal is to keep approximately half (1/2) of the data volume. The resource attribute contains the denominator (2), while the OpenTelemetry sampler argument contains the decimal value (0.5). ```shell theme={} export OTEL_TRACES_SAMPLER="traceidratio" export OTEL_TRACES_SAMPLER_ARG=0.5 export OTEL_RESOURCE_ATTRIBUTES="SampleRate=2" ``` ## Choosing between gRPC and HTTP Most OpenTelemetry SDKs have an option to export telemetry as OTLP either over gRPC or HTTP/protobuf, with some also offering HTTP/JSON. If you are trying to choose between gRPC and HTTP, keep in mind: * Some SDKs default to using gRPC, and it may be easiest to start with the default option. * Some firewall policies are not set up to handle gRPC and require using HTTP. * gRPC may improve performance, but its long-lived connections may cause problems with load balancing, especially when using Refinery. gRPC default export uses port 4317, whereas HTTP default export uses port 4318. ## Endpoint URLs for OTLP/HTTP When using the `OTEL_EXPORTER_OTLP_ENDPOINT` environment variable with an SDK and an HTTP exporter, the final path of the endpoint is modified by the SDK to represent the specific signal being sent. For example, when exporting trace data, the endpoint is updated to append `v1/traces`. When exporting metrics data, the endpoint is updated to append `v1/metrics`. So, if you were to set the `OTEL_EXPORTER_OTLP_ENDPOINT` to `https://api.honeycomb.io`, traces would be sent to `https://api.honeycomb.io/v1/traces` and metrics would be sent to `https://api.honeycomb.io/v1/metrics`. The same modification is not necessary for gRPC. ```shell theme={} export OTEL_EXPORTER_OTLP_ENDPOINT=https://api.honeycomb.io # US instance #export OTEL_EXPORTER_OTLP_ENDPOINT=https://api.eu1.honeycomb.io # EU instance ``` If the desired outcome is to send data to a different endpoint depending on the signal, use `OTEL_EXPORTER_OTLP__ENDPOINT` instead of the more generic `OTEL_EXPORTER_OTLP_ENDPOINT`. When using a signal-specific environment variable, these paths must be appended manually. Set `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` for traces, appending the endpoint with `v1/traces`, and `OTEL_EXPORTER_OTLP_METRICS_ENDPOINT` for metrics, appending the endpoint with `v1/metrics`. Send both traces and metrics to Honeycomb using this method by setting the following variables: ```shell theme={} export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://api.honeycomb.io/v1/traces # US instance #export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://api.eu1.honeycomb.io/v1/traces # EU instance export OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=https://api.honeycomb.io/v1/metrics # US instance #export OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=https://api.eu1.honeycomb.io/v1/metrics # EU instance ``` More details about endpoints and signals can be found in the [OpenTelemetry Specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md). ## Troubleshooting To explore common issues when sending data, visit [Common Issues with Sending Data to Honeycomb](/troubleshoot/common-issues/sending-data/#opentelemetry-sdks-and-honeycomb-distributions). ### Errors Sending to Honeycomb If OpenTelemetry is unable to send spans to Honeycomb, it should print an error to the console. For example, this error indicates that the Honeycomb API key is missing or incorrect: ```sh theme={} 2025/02/20 15:56:34 traces export: failed to send to https://api.honeycomb.io/v1/traces: 401 Unauthorized ``` #### Nothing Sent and No Errors If no events arrive in Honeycomb and no errors are printed, try increasing the logging verbosity of the OpenTelemetry SDK before initialization: ```go theme={} import( "log" "os" "github.com/go-logr/stdr" ) stdr.SetVerbosity(100) logger := stdr.New(log.New(os.Stdout, "otel-logger ", log.LstdFlags|log.Lshortfile)) otel.SetLogger(logger) ``` This results in log statements like the following: ```sh theme={} otel-logger 2025/02/20 16:02:26 internal_logging.go:45: "level"=4 "msg"="TracerProvider created" "config"={"SpanProcessors"=[{"Type"="BatchSpanProcessor" "SpanExporter"={"Type"="otlptrace" "Client"={"Type"="otlphttphttp" "Endpoint"="api.honeycomb.io" "Insecure"=false}} "Config"={"MaxQueueSize"=2048 "BatchTimeout"="5s" "ExportTimeout"="30s" "MaxExportBatchSize"=512 "BlockOnQueueFull"=false}}] "SamplerType"="trace.parentBased" "IDGeneratorType"="*trace.randomIDGenerator" "SpanLimits"={"AttributeValueLengthLimit"=-1 "AttributeCountLimit"=128 "EventCountLimit"=128 "LinkCountLimit"=128 "AttributePerEventCountLimit"=128 "AttributePerLinkCountLimit"=128} "Resource"={"Attributes"={"telemetry.sdk.version"="1.26.0" "env.whereami"="somewhere" "service.name"="awesome-sauce" "telemetry.sdk.language"="go" "telemetry.sdk.name"="opentelemetry"} "SchemaURL"="https://opentelemetry.io/schemas/1.24.0"}} ``` A crucial piece of this log says that OpenTelemetry is configured to send to Honeycomb: ```sh theme={} "SpanExporter"={"Type"="otlptrace" "Client"={"Type"="otlphttphttp" "Endpoint"="api.honeycomb.io" "Insecure"=false}} ``` If the `SpanExporter` is missing, there is a problem with your exporter configuration. If it looks right, try [sending a custom span](#create-spans) immediately after initialization as a further test. # Send iOS Data to Honeycomb with Swift Source: https://docs.honeycomb.io/send-data/ios Instrument your iOS application with the Honeycomb OpenTelemetry Swift SDK and send telemetry to Honeycomb to monitor real device performance. The [Honeycomb OpenTelemetry Swift SDK](https://github.com/honeycombio/honeycomb-opentelemetry-swift) is Honeycomb's distribution of [OpenTelemetry Swift](https://github.com/open-telemetry/opentelemetry-swift). It simplifies adding instrumentation to your iOS applications and sending telemetry to Honeycomb. This page briefly covers usage of the SDK. If you just want to see some code, check out the [examples on GitHub](https://github.com/honeycombio/honeycomb-opentelemetry-swift/tree/main/Examples). ## Before You Begin Before you can add instrumentation to your iOS application, you will need to do a few things. ### Get Your Honeycomb API Key To send data to Honeycomb, you need to: 1. Sign up for a Honeycomb account. To sign up, decide whether you would like Honeycomb to store your data in a US-based or EU-based location, then [create a Honeycomb account in the US](https://ui.honeycomb.io/signup) or [create a Honeycomb account in the EU](https://ui.eu1.honeycomb.io/signup). 2. [Create a Honeycomb Ingest API Key](/configure/environments/manage-api-keys/#create-api-key). To get started, you can create a key that you expect to swap out when you deploy to production. Name it something helpful, perhaps noting that it's a Getting Started key. Make note of your API key; for security reasons, you will not be able to see the key again, and you will need it later! For setup, make sure you select the "Can create datasets" checkbox so that your data will show up in Honeycomb. Later, when you replace this key with a permanent one, you can uncheck that box. ### Install the Honeycomb Swift SDK Add [Honeycomb OpenTelemetry Swift](https://github.com/honeycombio/honeycomb-opentelemetry-swift) to your application's dependencies. The Honeycomb Swift SDK is compatible with applications targeting iOS 13+. If you manage dependencies in Xcode: 1. In Xcode, select **File > Add Package Dependencies...** 2. Enter `https://github.com/honeycombio/honeycomb-opentelemetry-swift` as the repository URL. 3. Get the version number for the [latest release](https://github.com/honeycombio/honeycomb-opentelemetry-swift/releases). 4. Add the `Honeycomb` package to your [application's target dependencies](https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app). If you manage dependencies with `Package.swift`: 1. Add Honeycomb OpenTelemetry Swift as a package dependency: ```swift theme={} dependencies: [ .package(url: "https://github.com/honeycombio/honeycomb-opentelemetry-swift.git", from: "2.2.1") ], ``` 2. Add `Honeycomb` as a target dependency: ```swift theme={} dependencies: [ .product(name: "Honeycomb", package: "honeycomb-opentelemetry-swift"), ], ``` ## Configuration | Option | Description | | ---------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | APIKey | `String`
Your [Honeycomb Ingest API Key](/configure/environments/manage-api-keys/#create-api-key).
**Required** if sending telemetry directly to Honeycomb. | | tracesAPIKey | `String`
Dedicated Ingest API Key to use when sending traces. Overrides `APIKey` for traces. | | metricsAPIKey | `String`
Dedicated Ingest API Key to use when sending metrics. Overrides `APIKey` for metrics. | | logsAPIKey | `String`
Dedicated Ingest API Key to use when sending logs. Overrides `APIKey` for logs. | | dataset | `String`
Name of the [dataset](/configure/datasets/manage/) to send telemetry data to.
**Required** if using Honeycomb Classic. | | metricsDataset | `String`
Name of the dataset to send metrics to. Overrides `dataset` for metrics. | | APIEndpoint | `String`
Telemetry is sent to this URL. For Honeycomb EU instances set this as `https://api.eu1.honeycomb.io:443`. If you're using an OpenTelemetry Collector, provide your collector URL instead.
Default: `https://api.honeycomb.io:443` (US instance) | | tracesEndpoint | `String`
API endpoint to send traces to. | | metricsEndpoint | `String`
API endpoint to send metrics to. | | logsEndpoint | `String`
API endpoint to send logs to. | | sampleRate | `Int`
Sample rate to apply. For example, a `sampleRate` of `40` means 1 in 40 traces will be exported. Default: `1`
| | sessionTimeout | `TimeInterval`
Maximum length of time, in seconds, for a single user session. Used to generate `session.id` span attribute.
Default: `TimeInterval(60 * 60 * 4)` (4 hours) | | serviceName | `String`
The name of your application. Used as the value for `service.name` resource attribute. | | serviceVersion | `String`
Current version of your application. Used as the value for `service.version` resource attribute. | | resourceAttributes | `Dictionary`
Attributes to attach to outgoing resources. | | headers | `Dictionary`
Headers to add to exported telemetry data. | | tracesHeaders | `Dictionary`
Headers to add to exported trace data. | | metricsHeaders | `Dictionary`
Headers to add to exported metrics data. | | logsHeaders | `Dictionary`
Headers to add to exported logs data. | | timeout | `TimeInterval`
Timeout used by exporter when sending data. | | tracesTimeout | `TimeInterval`
Timeout used by traces exporter. Overrides `timeout` for trace data. | | metricsTimeout | `TimeInterval`
Timeout used by metrics exporter. Overrides `timeout` for metrics data. | | logsTimeout | `TimeInterval`
Timeout used by logs exporter. Overrides `timeout` for logs data. | | protocol | `enum HoneycombOptions.OTLPProtocol`
Protocol to use when sending data.
Default: `.httpProtobuf` | | tracesProtocol | `enum HoneycombOptions.OTLPProtocol`
Overrides `protocol` for trace data. | | metricsProtocol | `enum HoneycombOptions.OTLPProtocol`
Overrides `protocol` for metrics data. | | logsProtocol | `enum HoneycombOptions.OTLPProtocol`
Overrides `protocol` for logs data. | | spanProcessor | `OpenTelemetryApi.SpanProcessor`
Additional span processor to use. | | metricKitInstrumentationEnabled | `Bool`
Enable MetricKit instrumentation.
Default: `true` | | urlSessionInstrumentationEnabled | `Bool`
Enable URLSession instrumentation.
Default: `true` | | uiKitInstrumentationEnabled | `Bool`
Enable UIKit view instrumentation.
Default: `true` | | touchInstrumentationEnabled | `Bool`
Enable UIKit touch instrumentation. Default: `false` | | unhandledExceptionInstrumentationEnabled | `Bool`
Enable unhandled exception instrumentation.
Default: `true` | | offlineCachingEnabled | `Bool`
Enable offline caching for telemetry. When offline caching is enabled, telemetry is cached during network failures. The SDK will retry exporting telemetry for up to 18 hours. Offline caching also adds a minimum delay of 5 seconds to telemetry exports.
**Offline caching is an alpha feature and may be unstable.**
Default: `false` | ### Enable Auto-Instrumentation [Automatic instrumentation packages](https://github.com/honeycombio/honeycomb-opentelemetry-swift?tab=readme-ov-file#auto-instrumentation) are enabled or disabled in your configuration. ```swift theme={} import Honeycomb import SwiftUI @main struct ExampleApp: App { init() { do { let options = try HoneycombOptions.Builder() .setAPIKey("YOUR-API-KEY") .setServiceName("YOUR-SERVICE-NAME") // Enable or disable auto-instrumentation packages .setMetricKitInstrumentationEnabled(true) .setURLSessionInstrumentationEnabled(true) .setUIKitInstrumentationEnabled(true) .setTouchInstrumentationEnabled(false) .setUnhandledExceptionInstrumentationEnabled(true) .setDebug(true) .build() try Honeycomb.configure(options: options) } catch { NSException(name: NSExceptionName("HoneycombOptionsError"), reason: "\(error)").raise() } } var body: some Scene { Text("Hello world!") } } ``` ### Add Resource Attributes Resource attributes are available on every span your instrumentation emits. Adding custom, application-specific attributes makes it easier to correlate your data to important business information. You can add extra resource attributes during SDK configuration with the `.setResourceAttributes()` method. ```swift theme={} import Honeycomb import SwiftUI @main struct ExampleApp: App { init() { do { let options = try HoneycombOptions.Builder() .setAPIKey("YOUR-API-KEY") .setServiceName("YOUR-SERVICE-NAME") .setDebug(true) .setResourceAttributes(["app.ab_test": "test c"]) .build() try Honeycomb.configure(options: options) } catch { NSException(name: NSExceptionName("HoneycombOptionsError"), reason: "\(error)").raise() } } var body: some Scene { Text("Hello world!") } } ``` ### Enable Sampling The Honeycomb Swift SDK includes optional [deterministic head sampling](/manage-data-volume/sample/). To enable sampling, call `.setSampleRate()` with your desired sample rate as an `Int` value. The sample rate is `1` by default, meaning every trace is exported. The example below sets a `sampleRate` of `40`, meaning 1 in 40 traces will be exported. ```swift theme={} // ... let options = try HoneycombOptions.Builder() .setAPIKey("YOUR-API-KEY") .setServiceName("YOUR-SERVICE-NAME") .setServiceVersion("0.0.1") .sampleRate(40) .setDebug(true) .build() try Honeycomb.configure(options: options) ``` ## Custom Instrumentation Automatic instrumentation is a fast way to instrument your code, but you get more insight into your application by adding custom, or manual, instrumentation. To add your own custom instrumentation, [include the OpenTelemetryApi as a dependency](https://github.com/open-telemetry/opentelemetry-swift) in your application. ### Add Attributes to an Active Span You can retrieve the currently active span in a trace and add attributes to it. This lets you add more context to traces and gives you more ways to group or filter traces in your queries: ```swift theme={} import OpenTelemetryApi func applyDiscountCode(discountCode: String) { let currentSpan = OpenTelemetry.instance.contextProvider.activeSpan currentSpan.setAttribute("app.cart.discount_code", discountCode) } ``` In the above example, we add an `app.cart.discount_code` attribute to the current span. This lets us use the `app.cart.discount_code` field in `WHERE` or `GROUP BY` clauses in the Honeycomb query builder. ### Acquire a Tracer For manual tracing, you need to acquire a tracer: ```swift theme={} import OpenTelemetryApi let tracer = OpenTelemetry.instance.tracerProvider.get( instrumentationName: "my-application-tracer", instrumentationVersion: "1.0.0" ) ``` ### Create Spans Create custom spans to get a clear view of the critical parts in your application. ```swift theme={} import OpenTelemetryApi let tracer = OpenTelemetry.instance.tracerProvider.get( instrumentationName: "my-application-tracer", instrumentationVersion: "1.0.0" ) func generateNewLevel() { let span = tracer.spanBuilder(spanName: "newLevel").startSpan() // do some work span.end() } ``` ## Custom Span Processing Span processors provide hooks for when a span starts and when it ends. This lets you mutate spans after they have been created by automatic or manual instrumentation. Here's a basic example of a span processor that adds an attribute to spans when they start: ```swift theme={} import Foundation import OpenTelemetryApi import OpenTelemetrySdk internal class BasicSpanProcessor: SpanProcessor { public let isStartRequired = true public let isEndRequired = false public func onStart( parentContext: SpanContext?, span: any ReadableSpan ) { span.setAttribute( key: "app.metadata", value: "extra metadata" ) } func onEnd(span: any OpenTelemetrySdk.ReadableSpan) {} func shutdown(explicitTimeout: TimeInterval?) {} func forceFlush(timeout: TimeInterval?) {} } ``` Add the span processor to your SDK configuration to enable it: ```swift theme={} import Honeycomb import SwiftUI @main struct ExampleApp: App { init() { do { let options = try HoneycombOptions.Builder() .setAPIKey("YOUR-API-KEY") .setServiceName("YOUR-SERVICE-NAME") .setSpanProcessor(BasicSpanProcessor()) .setDebug(true) .build() try Honeycomb.configure(options: options) } catch { NSException(name: NSExceptionName("HoneycombOptionsError"), reason: "\(error)").raise() } } var body: some Scene { Text("Hello world!") } } ``` ## Manual Instrumentation Utilities The Honeycomb Swift SDK provides utilities for manually instrumenting [SwiftUI views](https://github.com/honeycombio/honeycomb-opentelemetry-swift?tab=readme-ov-file#swiftui-view-instrumentation), [SwiftUI navigation](https://github.com/honeycombio/honeycomb-opentelemetry-swift?tab=readme-ov-file#swiftui-navigation-instrumentation), and [logging errors or exceptions](https://github.com/honeycombio/honeycomb-opentelemetry-swift?tab=readme-ov-file#manual-error-logging). * [Example: SwiftUI View Instrumentation](https://github.com/honeycombio/honeycomb-opentelemetry-swift/blob/main/Examples/SmokeTest/SmokeTest/ViewInstrumentationView.swift) * [Example: SwiftUI Navigation Instrumentation](https://github.com/honeycombio/honeycomb-opentelemetry-swift/blob/main/Examples/SmokeTest/SmokeTest/NavigationExamplesView.swift) ### SwiftUI View Trace render timings of your views by wrapping them with `HoneycombInstrumentedView(name: String)`. ```swift theme={} var body: some View { HoneycombInstrumentedView(name: "main view") { VStack { Text("Hello main view!") } } } ``` ### SwiftUI Navigation The SDK provides a view modifier for manually tracing a [NavigationStack](https://developer.apple.com/documentation/swiftui/navigationstack) when you are [managing navigation state externally](https://developer.apple.com/documentation/swiftui/navigationstack#Manage-navigation-state). The `instrumentNavigation(path: String)` view modifier creates spans on `path` changes (`NavigationTo`, `NavigationFrom`) with attributes for the full navigation path and what triggered the navigation. ```swift theme={} import Honeycomb import SwiftUI struct Fruit: Identifiable, Equatable, Hashable, Codable { let name: String let color: String var id: String { name } } let fruits = [ Fruit(name: "Apple", color: "Red"), Fruit(name: "Banana", color: "Yellow"), ] func fruit(from id: Fruit.ID?) -> Fruit? { if let fruitId = id { if let index = fruits.firstIndex(where: { $0.id == fruitId }) { return fruits[index] } } return nil } struct FruitDetails: View { let fruit: Fruit var body: some View { Text("\(fruit.name) is \(fruit.color)") } } struct ExampleNavigationStackView: View { @State private var presentedFruits: [Fruit] = [] var body: some View { NavigationStack(path: $presentedFruits) { List(fruits) { fruit in NavigationLink(fruit.name, value: fruit) } .navigationDestination(for: Fruit.self) { fruit in FruitDetails(fruit: fruit) } } .instrumentNavigation(path: presentedFruits) // View Modifier } } ``` For other navigation components, such as `TabView` or `NavigationSplitView`, you can use the `Honeycomb.setCurrentScreen(path: Any)` function to trace navigation. ```swift theme={} import Honeycomb import SwiftUI struct ExampleTabView: View { var body: some View { TabView { ViewA() .padding() .tabItem { Label("View A") } .onAppear { Honeycomb.setCurrentScreen(path: "View A") } ViewB() .padding() .tabItem { Label("View B") } .onAppear { Honeycomb.setCurrentScreen(path: "View B") } ViewC() .padding() .tabItem { Label("View C") } .onAppear { Honeycomb.setCurrentScreen(path: "View C") } } } } ``` ### Log Errors and Exceptions The `Honeycomb.log()` method records any `Error`, `NSError`, or `NSException` as a log record. You can use `Honeycomb.log()` for logging exceptions you catch in your own code that are not logged by the SDK. ```swift theme={} do { try thisFunctionMayThrow() } catch let error { Honeycomb.log( error: error, attributes: [ "user.name": AttributeValue.string(currentUser.name), "user.id": AttributeValue.int(currentUser.id) ], thread: Thread.current ); } ``` ## Trace Header Propagation If you are connecting your app to a backend service that you wish to view as a unified trace with your app, you will need to manually add headers to all your outgoing requests. You must also create a span and set it as the active span. The span's context will be used to generate the headers needed for trace propagation. ```swift theme={} import OpenTelemetryApi private struct HttpTextMapSetter: Setter { func set(carrier: inout [String: String], key: String, value: String) { carrier[key] = value } } private let textMapSetter = HttpTextMapSetter() func makeBackendRequest(data: Data) async throws { let url = URL(string: "https://mybackendservice") var request = URLRequest(url: url!) request.httpMethod = "POST" request.httpBody = data let allHeaders: [String: String] = [] let span = OpenTelemetry.instance.tracerProvider.get( instrumentationName: "mybackendservice.network", instrumentationVersion: getCurrentAppVersion() ) .spanBuilder(spanName: "backendRequest") // The span must be made the active span or else the network autoinstrumentation // will not be attached to the trace. .setActive(true) .startSpan() defer { span.end() } // Add the required headers to the `allHeaders` Dictionary OpenTelemetry.instance.propagators.textMapPropagator.inject( spanContext: span.context, carrier: &allHeaders, setter: textMapSetter ) allHeaders.forEach({ (key: String, value: String) in request.setValue(value, forHTTPHeaderField: key) }) let session = URLSession(configuration: URLSessionConfiguration.default) let (data, response) = try await session.data(for: request) // process your response data as normal } ``` ## Troubleshooting To explore common issues when sending data, visit [Common Issues with Sending Data in Honeycomb](/troubleshoot/common-issues/sending-data/#opentelemetry-sdks-and-honeycomb-distributions). # Attributes in the Honeycomb OpenTelemetry Swift SDK Source: https://docs.honeycomb.io/send-data/ios/attributes Reference the standard attributes the Honeycomb OpenTelemetry Swift SDK automatically adds to spans. When you instrument your application using the Honeycomb OpenTelemetry Swift SDK, spans automatically include a standard set of attributes. These attributes provide essential context about the environment, runtime, device, and SDK versions--helping you understand where and how telemetry is being generated. ## Core Span Attributes Every span includes some core attributes. * `honeycomb.distro.runtime_version`: Operating system version on the device. * `honeycomb.distro.version`: Version of the Honeycomb SDK in use. * `os.description`: String describing the OS version, build ID, and SDK level. * `os.name`: OS name. Always `iOS` for iOS devices. * `os.type`: OS type. Always `darwin` on Apple platforms. * `os.version`: Current OS Version. * `service.name`: Name of your application. Set via `setServiceName()` or inferred from your bundle. * `service.version`: Version of your application. Set via `setServiceVersion()`. Defaults to being inferred from your bundle. * `telemetry.distro.name`: Name of the Honeycomb SDK in use. Always `honeycomb-opentelemetry-swift` for the Honeycomb OpenTelemetry Swift SDK. * `telemetry.distro.version`: Version of the Honeycomb SDK in use. * `telemetry.sdk.language`: Coding language for the Honeycomb SDK in use. Always `swift` for the Honeycomb OpenTelemetry Swift SDK. * `telemetry.sdk.name`: Name of the telemetry SDK used to generate telemetry data. Always `opentelemetry` for the Honeycomb OpenTelemetry Swift SDK. * `telemetry.sdk.version`: Version of the OpenTelemetry SDK in use. ## UIDevice Attributes If your application uses [UIKit](https://developer.apple.com/documentation/uikit), the SDK also includes device-level attributes from [UIDevice](https://developer.apple.com/documentation/uikit/uidevice). These give insight into the physical device running your application. * `device.id`: Vendor-specific device identifier. ([UIDevice.identifierForVendor](https://developer.apple.com/documentation/uikit/uidevice/identifierforvendor)) * `device.name`: Name of the device. ([UIDevice.name](https://developer.apple.com/documentation/uikit/uidevice/name)) * `device.systemName`: Operating system (OS) name. ([UIDevice.systemName](https://developer.apple.com/documentation/uikit/uidevice/systemname)) * `device.systemVersion`: OS version string. ([UIDevice.systemVersion](https://developer.apple.com/documentation/uikit/uidevice/systemversion)) * `device.model`: Device model name. ([UIDevice.model](https://developer.apple.com/documentation/uikit/uidevice/model)) * `device.localizedModel`: Localized version of the device model. ([UIDevice.localizedModel](https://developer.apple.com/documentation/uikit/uidevice/localizedmodel)) * `device.userInterfaceIdiom`: Type of interface the device uses. ([UIDevice.userInterfaceIdiom](https://developer.apple.com/documentation/uikit/uidevice/userinterfaceidiom)) * `device.isMultitaskingSupported`: Indicates whether the device supports multitasking. ([UIDevice.isMultitaskingSupported](https://developer.apple.com/documentation/uikit/uidevice/ismultitaskingsupported)) * `device.orientation`: Current device orientation. ([UIDevice.orientation](https://developer.apple.com/documentation/uikit/uidevice/orientation) * `device.isLowPowerModeEnabled`: Indicates whether Low Power Mode is currently active. ([UIDevice.isLowPowerModeEnabled](https://developer.apple.com/documentation/foundation/processinfo/islowpowermodeenabled)) * `device.isBatteryMonitoringEnabled`: Indicates whether battery monitoring is turned on. ([UIDevice.isBatteryMonitoringEnabled](https://developer.apple.com/documentation/uikit/uidevice/isbatterymonitoringenabled)) * `device.batteryLevel`: Battery level. Included only if `UIDevice.current.batteryStateAttributesEnabled` is set to `true`. ([UIDevice.batteryLevel](https://developer.apple.com/documentation/uikit/uidevice/batterylevel)) * `device.batteryState`: Battery state. Included only if `UIDevice.current.batteryStateAttributesEnabled` is set to `true`. ([UIDevice.batteryState](https://developer.apple.com/documentation/uikit/uidevice/batterystate-swift.property)) ## MetricKit Attributes If [MetricKit](https://developer.apple.com/documentation/metrickit) is available and you've enabled MetricKit instrumentation, the SDK adds system performance and behavior metrics. These help identify performance bottlenecks, power usage trends, and device conditions. ### Application Metadata * `metrickit.metadata.app_build_version`: (String) Application bundle version. ([MXMetaData.applicationBuildVersion](https://developer.apple.com/documentation/metrickit/mxmetadata/applicationbuildversion/)) * `metrickit.metadata.device_type`: (String) Hardware identifier for the device. ([MXMetaData.deviceType](https://developer.apple.com/documentation/metrickit/mxmetadata/devicetype/)) * `metrickit.metadata.is_test_flight_app`: (Bool) Indicates whether the application is registered with TestFlight. ([MXMetaData.isTestFlightA](https://developer.apple.com/documentation/metrickit/mxmetadata/istestflightapp/)) * `metrickit.metadata.low_power_mode_enabled`: (Bool) Indicates whether low power mode is enabled. ([MXMetaData.lowPowerModeEnabled](https://developer.apple.com/documentation/metrickit/mxmetadata/lowpowermodeenabled/)) * `metrickit.metadata.os_version`: (String) OS version, version number, and build number. ([MXMetaData.osVersion](https://developer.apple.com/documentation/metrickit/mxmetadata/osversion/)) * `metrickit.metadata.platform_arch`: (String) Name of the processor architecture. ([MXMetaData.platformArchitecture](https://developer.apple.com/documentation/metrickit/mxmetadata/platformarchitecture/)) * `metrickit.metadata.region_format`: (String) Short country code for the region format setting. ([MXMetaData.regionFormat](https://developer.apple.com/documentation/metrickit/mxmetadata/regionformat/)) * `metrickit.metadata.pid`: (Int) Process ID of the running application. ([MXMetaData.pid](https://developer.apple.com/documentation/metrickit/mxmetadata/pid/)) ### Application Version History * `metrickit.includes_multiple_application_versions`: (Bool) Indicates whether the application version changed during the reporting window. ([MXMetricPayload.includesMultipleApplicationVersions](https://developer.apple.com/documentation/metrickit/mxmetricpayload/includesmultipleapplicationversions/)) * `metrickit.latest_application_version`: (String) Application version at the end of the reporting window. ([MXMetricPayload.latestApplicationVersion](https://developer.apple.com/documentation/metrickit/mxmetricpayload/latestapplicationversion/)) ### CPU and GPU Usage * `metrickit.cpu.cpu_time`: (Double) Total amount of CPU time used by the application. ([MXCPUMetric.cumulativeCPUTime](https://developer.apple.com/documentation/metrickit/mxcpumetric/cumulativecputime/)) * `metrickit.cpu.instruction_count`: Total number of CPU instructions executed during the reporting window. ([MXCPUMetric.cumulativeCPUInstructions](https://developer.apple.com/documentation/metrickit/mxcpumetric/cumulativecpuinstructions/)) * `metrickit.gpu.time`: (Double) Total amount of GPU time used by the application. ([MXGPUMetric.cumulativeGPUTime](https://developer.apple.com/documentation/metrickit/mxgpumetric/cumulativegputime/)) ### Cellular Connectivity * `metrickit.cellular_condition.bars_average`: (Double) Average cellular signal strength. ([MXCellularConditionMetric.histogrammedCellularConditionTime](https://developer.apple.com/documentation/metrickit/mxcellularconditionmetric/histogrammedcellularconditiontime/)) ### Application Run Time * `metrickit.app_time.foreground_time`: (Double) Total time the application spent in the foreground. ([MXAppRunTimeMetric.cumulativeForegroundTime](https://developer.apple.com/documentation/metrickit/mxappruntimemetric/cumulativeforegroundtime/)) * `metrickit.app_time.background_time`: (Double) Total time the application spent in the background. ([MXAppRunTimeMetric.cumulativeBackgroundTime](https://developer.apple.com/documentation/metrickit/mxappruntimemetric/cumulativebackgroundtime/)) * `metrickit.app_time.background_audio_time`: (Double) Total time playing audio while in the background. ([MXAppRunTimeMetric.cumulativeBackgroundAudioTime](https://developer.apple.com/documentation/metrickit/mxappruntimemetric/cumulativebackgroundaudiotime/)) * `metrickit.app_time.background_location_time`: (Double) Total time using location services in the background. ([MXAppRunTimeMetric.cumulativeBackgroundLocationTime](https://developer.apple.com/documentation/metrickit/mxappruntimemetric/cumulativebackgroundlocationtime/)) ### Location Accuracy * `metrickit.location_activity.best_accuracy_for_nav_time`: (Double) Total time spent tracking the current location at the best accuracy for navigation. ([MXLocationActivityMetric.cumulativeBestAccuracyForNavigationTime](https://developer.apple.com//documentation/metrickit/mxlocationactivitymetric/cumulativebestaccuracyfornavigationtime/)) * `metrickit.location_activity.best_accuracy_time`: (Double) Total time spent tracking the current location at the best general accuracy. ([MXLocationActivityMetric.cumulativeBestAccuracyTime](https://developer.apple.com/documentation/metrickit/mxlocationactivitymetric/cumulativebestaccuracytime/)) * `metrickit.location_activity.accuracy_10m_time`: (Double) Total time spent tracking the current location to an accuracy of 10 meters. ([MXLocationActivityMetric.cumulativeNearestTenMetersAccuracyTime](https://developer.apple.com/documentation/metrickit/mxlocationactivitymetric/cumulativenearesttenmetersaccuracytime/)) * `metrickit.location_activity.accuracy_100m_time`: (Double) Total time spent tracking the current location to an accuracy of 100 meters. ([MXLocationActivityMetric.cumulativeHundredMetersAccuracyTime](https://developer.apple.com/documentation/metrickit/mxlocationactivitymetric/cumulativehundredmetersaccuracytime/)) * `metrickit.location_activity.accuracy_1km_time`: (Double) Total time spent tracking the current location to an accuracy of 1 kilometer. ([MXLocationActivityMetric.cumulativeKilometerAccuracyTime](https://developer.apple.com/documentation/metrickit/mxlocationactivitymetric/cumulativekilometeraccuracytime/)) * `metrickit.location_activity.accuracy_3km_time`: (Double) Total time spent tracking the current location to an accuracy of 3 kilometers. ([MXLocationActivityMetric.cumulativeThreeKilometersAccuracyTime](https://developer.apple.com/documentation/metrickit/mxlocationactivitymetric/cumulativethreekilometersaccuracytime/)) ### Network Transfer * `metrickit.network_transfer.wifi_upload`: (Double) Total amount of data uploaded over WiFi connection. ([MXNetworkTransferMetric.cumulativeWifiUpload](https://developer.apple.com/documentation/metrickit/mxnetworktransfermetric/cumulativewifiupload)) * `metrickit.network_transfer.wifi_download`: (Double) Total amount of data downloaded over WiFi connection. ([MXNetworkTransferMetric..cumulativeWifiDownload](https://developer.apple.com/documentation/metrickit/mxnetworktransfermetric/cumulativewifidownload)) * `metrickit.network_transfer.cellular_upload`: (Double) Total amount of data uploaded over cellular connection. ([MXNetworkTransferMetric.cumulativeCellularUpload](https://developer.apple.com/documentation/metrickit/mxnetworktransfermetric/cumulativecellularupload)) * `metrickit.network_transfer.cellular_download`: (Double) Total amount of data downloaded over cellular connection. ([MXNetworkTransferMetric.cumulativeCellularDownload](https://developer.apple.com/documentation/metrickit/mxnetworktransfermetric/cumulativecellulardownload)) ### Application Launch * `metrickit.app_launch.time_to_first_draw_average`: (Double) Average time taken to launch the application. ([MXAppLaunchMetric.histogrammedTimeToFirstDraw](https://developer.apple.com/documentation/metrickit/mxapplaunchmetric/histogrammedtimetofirstdraw)) * `metrickit.app_launch.app_resume_time_average`: (Double) Average time taken to resume the application from the background. ([MXAppLaunchMetric.histogrammedApplicationResumeTime](https://developer.apple.com/documentation/metrickit/mxapplaunchmetric/histogrammedapplicationresumetime)) * `metrickit.app_launch.optimized_time_to_first_draw_average`: (Double) Average time for prewarmed launches. ([MXAppLaunchMetric.histogrammedOptimizedTimeToFirstDraw](https://developer.apple.com/documentation/metrickit/mxapplaunchmetric/histogrammedoptimizedtimetofirstdraw)) * `metrickit.app_launch.extended_launch_average`: (Double) Average time taken to launch, including extended launch tasks. ([MXAppLaunchMetric.histogrammedExtendedLaunch](https://developer.apple.com/documentation/metrickit/mxapplaunchmetric/histogrammedextendedlaunch)) ### Application Responsiveness * `metrickit.app_responsiveness.hang_time_average`: (Double) Average amount of time the application is too busy to handle user interaction responsively. ([MXAppResponsivenessMetric.histogrammedApplicationHangTime](https://developer.apple.com/documentation/metrickit/mxappresponsivenessmetric/histogrammedapplicationhangtime)) ### Disk I/O * `metrickit.diskio.logical_write_count`: (Double) Total amount of data written to disk. ([MXDiskIOMetric.cumulativeLogicalWrites](https://developer.apple.com/documentation/metrickit/mxdiskiometric/cumulativelogicalwrites)) ### Memory * `metrickit.memory.peak_memory_usage`: (Double) Largest amount of memory used by the application. ([MXMemoryMetric.peakMemoryUsage](https://developer.apple.com/documentation/metrickit/mxmemorymetric/peakmemoryusage)) * `metrickit.memory.suspended_memory_average`: (Double) Average amount of memory used by the application when it's suspended. ([MXMemoryMetric.averageSuspendedMemory](https://developer.apple.com/documentation/metrickit/mxmemorymetric/averagesuspendedmemory)) ### Display * `metrickit.display.pixel_luminance_average`: (Double) Average amount of pixel luminosity on an OLED display. ([MXDisplayMetric.averagePixelLuminance](https://developer.apple.com/documentation/metrickit/mxdisplaymetric/averagepixelluminance)) ### Animation * `metrickit.animation.scroll_hitch_time_ratio`: (Double) Ratio of time spent hitching while scrolling (UIScrollView). ([MXAnimationMetric.scrollHitchTimeRatio](https://developer.apple.com/documentation/metrickit/mxanimationmetric/scrollhitchtimeratio)) ### Application Exit Metrics * `metrickit.app_exit.foreground.normal_app_exit_count`: (Int) Number of times the application exited normally from the foreground. ([MXForegroundExitData.cumulativeNormalAppExitCount](https://developer.apple.com/documentation/metrickit/mxforegroundexitdata/cumulativenormalappexitcount)) * `metrickit.app_exit.foreground.memory_resource_limit_exit_count`: (Int) Number of times the application was terminated from the foreground for using too much memory. ([MXForegroundExitData.cumulativeMemoryResourceLimitExitCount](https://developer.apple.com/documentation/metrickit/mxforegroundexitdata/cumulativememoryresourcelimitexitcount)) * `metrickit.app_exit.foreground.bad_access_exit_count`: (Int) Number of times the application was terminated from the foreground for attempting an invalid memory access. ([MXForegroundExitData.cumulativeBadAccessExitCount](https://developer.apple.com/documentation/metrickit/mxforegroundexitdata/cumulativebadaccessexitcount)) * `metrickit.app_exit.foreground.abnormal_exit_count`: (Int) Number of times the application exited abnormally from the foreground. ([MXForegroundExitData.cumulativeAbnormalExitCount](https://developer.apple.com/documentation/metrickit/mxforegroundexitdata/cumulativeabnormalexitcount)) * `metrickit.app_exit.foreground.illegal_instruction_exit_count`: (Int) Number of times the application was terminated from the foreground for attempting to execute an illegal or undefined instruction. ([MXForegroundExitData.cumulativeIllegalInstructionExitCount](https://developer.apple.com/documentation/metrickit/mxforegroundexitdata/cumulativeillegalinstructionexitcount)) * `metrickit.app_exit.foreground.app_watchdog_exit_count`: (Int) Number of times the system watchdog terminated the application from the foreground. ([MXForegroundExitData.cumulativeAppWatchdogExitCount](https://developer.apple.com/documentation/metrickit/mxforegroundexitdata/cumulativeappwatchdogexitcount)) * `metrickit.app_exit.background.normal_app_exit_count`: (Int) Number of times the application exited normally from the background. ([MXBackgroundExitData.cumulativeNormalAppExitCount](https://developer.apple.com/documentation/metrickit/mxbackgroundexitdata/cumulativenormalappexitcount)) * `metrickit.app_exit.background.memory_resource_limit_exit_count`: (Int) Number of times the application was terminated from the background for using too much memory. ([MXBackgroundExitData.cumulativeMemoryResourceLimitExitCount](https://developer.apple.com/documentation/metrickit/mxbackgroundexitdata/cumulativememoryresourcelimitexitcount)) * `metrickit.app_exit.background.cpu_resource_limit_exit_count`: (Int) Number of times the application was terminated from the background for using too much CPU time. ([MXBackgroundExitData.cumulativeCPUResourceLimitExitCount](https://developer.apple.com/documentation/metrickit/mxbackgroundexitdata/cumulativecpuresourcelimitexitcount)) * `metrickit.app_exit.background.memory_pressure_exit_count`: (Int) Number of times the application was terminated from the background to free up memory. ([MXBackgroundExitData.cumulativeMemoryPressureExitCount](https://developer.apple.com/documentation/metrickit/mxbackgroundexitdata/cumulativememorypressureexitcount)) * `metrickit.app_exit.background.bad_access_exit_count`: (Int) Number of times the application was terminated from the background for attempting an invalid memory access. ([MXBackgroundExitData.cumulativeBadAccessExitCount](https://developer.apple.com/documentation/metrickit/mxbackgroundexitdata/cumulativebadaccessexitcount)) * `metrickit.app_exit.background.abnormal_exit_count`: (Int) Number of times the application exited abnormally from the background. ([MXBackgroundExitData.cumulativeAbnormalExitCount](https://developer.apple.com/documentation/metrickit/mxbackgroundexitdata/cumulativeabnormalexitcount)) * `metrickit.app_exit.background.illegal_instruction_exit_count`: (Int) Number of times the application was terminated from the background for attempting to execute an illegal or undefined instruction. ([MXBackgroundExitData.cumulativeIllegalInstructionExitCount](https://developer.apple.com/documentation/metrickit/mxbackgroundexitdata/cumulativeillegalinstructionexitcount)) * `metrickit.app_exit.background.app_watchdog_exit_count`: (Int) Number of times the system watchdog terminated the application from the background. ([MXBackgroundExitData.cumulativeAppWatchdogExitCount](https://developer.apple.com/documentation/metrickit/mxbackgroundexitdata/cumulativeappwatchdogexitcount)) * `metrickit.app_exit.background.suspended_with_locked_file_exit_count`: (Int) Number of times the application was terminated from the background while being suspended and having file locks. ([MXBackgroundExitData.cumulativeSuspendedWithLockedFileExitCount](https://developer.apple.com/documentation/metrickit/mxbackgroundexitdata/cumulativesuspendedwithlockedfileexitcount)) * `metrickit.app_exit.background.background_task_assertion_timeout_exit_count`: (Int) Number of times the application was terminated from the background for exceeding the allocated time for a background task. ([MXBackgroundExitData.cumulativeBackgroundTaskAssertionTimeoutExitCount](https://developer.apple.com/documentation/metrickit/mxbackgroundexitdata/cumulativebackgroundtaskassertiontimeoutexitcount)) ### Diagnostics * `metrickit.diagnostic.cpu_exception.total_cpu_time`: (Double) Total CPU time used during the exception. ([MXCPUExceptionDiagnostic.totalCPUTime](https://developer.apple.com/documentation/metrickit/mxcpuexceptiondiagnostic/totalcputime)) * `metrickit.diagnostic.cpu_exception.total_sampled_time`: (Double) Total time the application was sampled during the exception. ([MXCPUExceptionDiagnostic.totalSampledTime](https://developer.apple.com/documentation/metrickit/mxcpuexceptiondiagnostic/totalsampledtime)) * `metrickit.diagnostic.disk_write_exception.total_writes_caused`: (Double) Total amount of data written to disk during the disk write exception. ([MXDiskWriteExceptionDiagnostic.totalWritesCaused](https://developer.apple.com/documentation/metrickit/mxdiskwriteexceptiondiagnostic/totalwritescaused)) * `metrickit.diagnostic.hang.hang_duration`: (Double) Amount of time the app is busy and unable to respond to user interaction. ([MXHangDiagnostic.hangDuration](https://developer.apple.com/documentation/metrickit/mxhangdiagnostic/hangduration)) * `metrickit.diagnostic.crash.exception.mach_exception_type`: (Int) Mach exception type of the crash. ([MXCrashDiagnostic.exceptionType](https://developer.apple.com/documentation/metrickit/mxcrashdiagnostic/exceptiontype)) * `metrickit.diagnostic.crash.exception.code`: (Int) Encoded processor-specific information for the crash. ([MXCrashDiagnostic.exceptionCode](https://developer.apple.com/documentation/metrickit/mxcrashdiagnostic/exceptioncode)) * `metrickit.diagnostic.crash.exception.signal`: (Int) Signal associated with the crash. ([MXCrashDiagnostic.exceptionSignal](https://developer.apple.com/documentation/metrickit/mxcrashdiagnostic/signal)) * `metrickit.diagnostic.crash.exception.objc.message`: (String) Exception message string that explains the reason for the Objective-C exception. ([MXCrashDiagnosticObjectiveCExceptionReason](https://developer.apple.com/documentation/metrickit/mxcrashdiagnosticobjectivecexceptionreason)) * `metrickit.diagnostic.crash.exception.objc.type`: (String) Type of the Objective-C exception. ([MXCrashDiagnosticObjectiveCExceptionReason](https://developer.apple.com/documentation/metrickit/mxcrashdiagnosticobjectivecexceptionreason)) * `metrickit.diagnostic.crash.exception.termination_reason`: (String) Reason the application was terminated as a human-readable string. ([MXCrashDiagnostic.terminationReason](https://developer.apple.com/documentation/metrickit/mxcrashdiagnostic/terminationreason)) * `metrickit.diagnostic.crash.exception.objc.name`: (String) Name of the Objective-C exception that triggered the crash. ([MXCrashDiagnosticObjectiveCExceptionReason](https://developer.apple.com/documentation/metrickit/mxcrashdiagnosticobjectivecexceptionreason)) * `metrickit.diagnostic.crash.exception.objc.classname`: (String) Name of the Objective-C class in which the exception occurred. ([MXCrashDiagnosticObjectiveCExceptionReason](https://developer.apple.com/documentation/metrickit/mxcrashdiagnosticobjectivecexceptionreason)) * `metrickit.diagnostic.app_launch.launch_duration`: (Double) Total duration of the application launch, measured from process start until the application is responsive. ([MXAppLaunchDiagnostic.launchDuration](https://developer.apple.com/documentation/metrickit/mxapplaunchdiagnostic/launchduration)) # Symbolicate iOS Stack Traces with the OpenTelemetry Collector Source: https://docs.honeycomb.io/send-data/ios/symbolicate Use the dSYM processor in the OpenTelemetry Collector to replace obfuscated names in iOS stack traces with readable symbols for easier debugging. Use the dSym processor in your OpenTelemetry Collector to symbolicate iOS stack traces. The [dSym processor](https://github.com/honeycombio/opentelemetry-collector-symbolicator?tab=readme-ov-file#dsym-symbolication) replaces obfuscated names and addresses in your iOS stack traces with symbols from provided dSYM files. ## Before You Start The dSym processor is compatible with [Honeycomb OpenTelemetry Swift SDK](https://github.com/honeycombio/honeycomb-opentelemetry-swift) version `0.0.14` and later. To use the dSym processor, you need: * OpenTelemetry Collector built with `CGO` enabled. * An environment or container image with `glibc` support. We recommend `gcr.io/distroless/cc`, a secure and lightweight container image with CGO and `glibc` support. If you're not using the Honeycomb OpenTelemetry Swift SDK, make sure your exception data is in [the format the processor expects](https://github.com/honeycombio/opentelemetry-collector-symbolicator/blob/main/README.md#exception-information-format-1). ## Install By default, the [Honeycomb OpenTelemetry Collector distribution](https://github.com/honeycombio/honeycomb-collector-distro) includes the symbolicator processor, so you can skip to the next section if you're using it. If you use another collector distribution or build your own, it must be built with CGO enabled. You can install the symbolicator processor by adding it to your OpenTelemetry Collector build configuration file: ```yaml theme={} processors: - gomod: github.com/honeycombio/opentelemetry-collector-symbolicator/dsymprocessor v0.0.9 ``` You can find the latest dSym processor version on the [releases page](https://github.com/honeycombio/opentelemetry-collector-symbolicator/releases) in the GitHub repo. ## dSYM Files The dSym processor requires access to the dSYM file generated by your build process. This file can be stored in your local file system, Amazon S3, or Google Cloud Storage. To support symbolication, your dSYM file must be versioned with the generated build UUID in the file name. For example: `6A8CB813-45F6-3652-AD33-778FD1EAB196.dSYM`. ### Getting the Build UUID You can use the `dwarfdump` tool to get the build UUID from an an `.xcarchive` file generated by Xcode. The following example script finds the latest build and uploads it to the `app-archives` Amazon S3 bucket with the `ios` prefix. ```bash theme={} # Get the App Name if [[ -z "$1" ]]; then echo "❌ Usage: $0 " exit 1 fi TARGET_NAME=$1 export ARCHIVE_PATH=$(ls -dt ~/Library/Developer/Xcode/Archives/*/"$TARGET_NAME"*.xcarchive | head -1) echo "📦 Using Archive Path: $ARCHIVE_PATH" if [[ ! -d "$ARCHIVE_PATH" ]]; then echo "❌ Archive not found for target: $TARGET_NAME! Please archive the project first in Xcode." exit 1 fi find "$ARCHIVE_PATH/dSYMs" -name "*.dSYM" | while read line ; do echo "🔍 Found dsym at: $line" dsymuuid=$(dwarfdump -u "$line" | awk '{ print $2 }').dSYM echo "⬆️ Uploading dsym to: $dsymuuid" aws s3 cp --recursive "$line" s3://app-archives/ios/$dsymuuid done ``` ## Configure a File Store Add the `dsym_symbolicator` as a processor in your OpenTelemetry Collector configuration: ```yaml theme={} processors: dsym_symbolicator: ``` You can then configure where your source maps are stored. By default, the dSym processor loads dSYM files from a local directory. You can set the file path in your collector configuration: ```yaml theme={} processors: dsym_symbolicator: # dsym_store is sets which store to use, in this case local disk dsym_store: file_store local_dsyms: # (optional) path sets the base path of the files, defaults to `.` path: /tmp/dsyms ``` Make sure your collector can access the `path` directory you set, and that file paths in stack traces match the structure of your configured file store. Optionally, you can load dSYM files from an Amazon S3 bucket. Add to your OpenTelemetry Collector configuration: ```yaml theme={} processors: dsym_symbolicator: # dsym_store sets which store to use, in this case S3 dsym_store: s3_store s3_dsyms: # name of the bucket the files are stored in bucket: dsyms-bucket # (optional) the bucket's region region: us-east-1 # (optional) prefix is used to nest the files in a sub key of the bucket prefix: dsyms ``` Make sure your collector has permission to access the S3 bucket. Also, ensure the file paths in stack traces match the structure used in your file store. #### Private AWS S3 bucket authentication To use a private Amazon S3 bucket as your file store, set the `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` [environment variables](https://docs.aws.amazon.com/sdkref/latest/guide/environment-variables.html). Optionally, you can load dSYM files from a Google Cloud Storage (GCS) bucket. Add to your OpenTelemetry Collector configuration: ```yaml theme={} processors: dsym_symbolicator: # dsym_store sets which store to use, in this case GCS dsym_store: gcs_store gcs_dsyms: # the name of the bucket the files are stored in bucket: dsyms-bucket # (optional) prefix is used to nest the files in a sub key of the bucket prefix: dsyms ``` Make sure your collector has permission to access the GCS bucket. Also, ensure the file paths in stack traces match the structure used in your file store. #### Private GCS bucket authentication To use a private Google Cloud Storage bucket as your file store, set the `GOOGLE_APPLICATION_CREDENTIALS` [environment variable](https://cloud.google.com/docs/authentication/application-default-credentials). ## Advanced Configuration In addition to basic setup, you can customize how the dSym processor handles stack traces by configuring attribute mappings and additional processing options. After updating the configuration file, restart the OpenTelemetry Collector to apply the changes. ### Mapping Attributes Use these configuration options to specify which attributes the processor should read from and write to when handling stack traces: | Config Key | Description | Example Value | | -------------------------------------------------- | ---------------------------------------------------------------------------------------------------------- | ------------------------------------------------------ | | `symbolicator_failure_attribute_key` | Signals if the the symbolicator fails to fully symbolicate the stack trace | `exception.symbolicator.failed` | | `symbolicator_error_attribute_key` | Contains the error message if the the symbolicator fails to fully symbolicate the stack trace | `exception.symbolicator.error` | | `stack_trace_attribute_key` | Which attribute should the stack trace of a generic stacktrace log be sourced from | `exception.stacktrace` | | `metrickit_stack_trace_attribute_key` | Which attribute should the json representation of a metrickit stacktrace log be sourced from | `metrickit.diagnostic.crash.exception.stacktrace_json` | | `output_metrickit_stack_trace_attribute_key` | Which attribute should the symbolicated metrickit stack trace be populated into | `exception.stacktrace` | | `output_metrickit_exception_type_attribute_key` | Which attribute should the exception type be populated into | `exception.type`. | | `output_metrickit_exception_message_attribute_key` | Which attribute should the exception message be populated into | `exception.message`. | | `preserve_stack_trace` | After the stack trace has been symbolicated should the original values be preserved as attributes | `true` | | `original_stack_trace_attribute_key` | If the stack trace is being preserved, which key should it be copied to | `exception.stacktrace.original` | | `build_uuid_attribute_key` | Which resource attribute should the binary UUID of a generic stacktrace log be sourced from | `app.debug.build_uuid` | | `app_executable_attribute_key` | Which resource attribute should the name of the app executable of a generic stacktrace log be sourced from | `app.bundle.executable` | ### Additional Processing Options Use these configuration options to control how stack traces are processed and managed: | Config Key | Description | Example Value | | ----------------- | ----------------------------------------------------------------------------------------------------------- | ------------- | | `timeout` | Max duration to wait to symbolicate a stack trace in seconds. | `5` | | `dsym_cache_size` | The maximum number of dSYMs to cache. Reduce this if you are running into memory issues with the collector. | `128` | ### Language-Based Routing The dSYM processor supports language-based routing to ensure it only processes signals from iOS/macOS applications. This prevents the processor from running on signals from other platforms (like Android or JavaScript), improving performance and avoiding unnecessary processing. | Config Key | Description | Default Value | Example Values | | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------- | ------------------------ | | `language_attribute_key` | The attribute key that contains the programming language or SDK language of the telemetry signal. | `telemetry.sdk.language` | `telemetry.sdk.language` | | `allowed_languages` | A list of language values that this processor will handle. If the signal's language attribute matches any value in this list, the processor will run. If empty (default), the processor will process all signals regardless of language. **Important:** When `allowed_languages` is configured, signals without a language attribute will be skipped. | `[]` (empty, processes all) | `["swift", "ios"]` | **Example configuration:** ```yaml theme={} processors: dsym_symbolicator: allowed_languages: ["swift", "ios"] ``` `allowed_languages` configuration behavior: * Empty `allowed_languages` (default): Processes all signals, regardless of language attribute. * With `allowed_languages` configured: Only processes signals where the language attribute matches one of the allowed values (case-insensitive). * Missing language attribute: Skips processing when `allowed_languages` is configured. # Send Data to Honeycomb with Java Source: https://docs.honeycomb.io/send-data/java Explore available methods for sending telemetry from your Java application to Honeycomb. When you are working with Java, we recommend these methods of sending data to Honeycomb. When you want to instrument Java applications in a standard, vendor-agnostic, and future-proof way, we recommend using the OpenTelemetry Java Agent to send telemetry data to Honeycomb. The OpenTelemetry Java Agent allows you to send traces, logs, and metrics. When you need to create and send structured logs to Honeycomb, use Libhoney for Java, our structured logging library for Java applications. # Send Logs with Libhoney for Java Source: https://docs.honeycomb.io/send-data/java/libhoney Send structured events to Honeycomb from your Java application using Libhoney, Honeycomb's low-level structured logging library for the Events API. Libhoney for Java is Honeycomb's structured logging library for Java applications. It is a low-level library that helps you send structured events to Honeycomb's [Events API](/api/events/). If you are instrumenting a new application for tracing, we recommend that you use [OpenTelemetry](/send-data/opentelemetry/) instead. ## Installation The SDK is available from Maven Central Repository. To get started, add the SDK to your dependencies: ```groovy theme={} compile group: 'io.honeycomb.libhoney', name: 'libhoney-java', version: '1.5.4' ``` ```xml theme={} io.honeycomb.libhoney libhoney-java 1.5.4 ``` ## Links * [Changelog](https://github.com/honeycombio/libhoney-java/blob/main/CHANGELOG.md) * [Source Code](https://github.com/honeycombio/libhoney-java) * [Examples](https://github.com/honeycombio/libhoney-java/tree/main/examples) ## Initialization The `LibHoney` class is the entry point to the Honeycomb client library, and is used to create a `HoneyClient`. The `HoneyClient` class provides functionality to construct and send events. The typical application will only have one `HoneyClient` instance. Use `LibHoney`'s static methods to construct and configure an instance of `HoneyClient`, passing in your Team API key and the default dataset name to which it should send events. ```java theme={} public class Initialization { private HoneyClient honeyClient; public Initialization() { honeyClient = create( options() .setWriteKey("myTeamWriteKey") .setDataset("Cluster Dataset") .setSampleRate(2) .build() ); } } ``` ### Working With a Proxy To reach the Honeycomb API through a proxy server, you need to specify alternative `TransportOptions` when calling `create`, and provide the proxy address. For example, if your proxy is at `https://myproxy.example.com`: ```java theme={} public class Initialization { private HoneyClient honeyClient; public Initialization() { honeyClient = create( options() .setWriteKey("myTeamWriteKey") .setDataset("Cluster Dataset") .setSampleRate(2) .build(), transportOptions().setProxy(HttpHost.create("https://myproxy.example.com")).build() ); } } ``` Important notes on Libhoney: 1. Use of one `HoneyClient` instance across threads is thread safe. 2. Libhoney sends will not block your code - event sends are batched up and sent in a queue running in its own thread as the queue either fills to its limit or the default batch send interval is reached. 3. Pending writes to Honeycomb will be flushed automatically when the JVM shuts down. You do not need to worry about flushing them yourself. ## Building and Sending Events Once initialized, `HoneyClient` is ready to send events. In many cases, an event should be first customized with relevant data from its runtime context. For example, try putting a timer around a section of code, adding per-user information, or details about what it took to craft a response. You can add fields when and where you need to, or for some events but not others. (Error handlers are a good example of this.) `createEvent()` creates such a customizable `Event`. You can add fields to the event with `.addField()` and then submit to the Honeycomb server via `Event.send()`. Sending an event is an asynchronous action and will avoid blocking by default. ```java theme={} public static void main(String... args) { try (HoneyClient honeyClient = initializeClient()) { honeyClient .createEvent() .addField("userName", "Bob") .addField("userId", UUID.randomUUID().toString()) .setTimestamp(System.currentTimeMillis()) .send(); } } ``` Alternatively, an `EventFactory` is useful when a grouping of events being sent shares common properties. This can be created through the `buildEventFactory()` method. You can use an `EventFactory` to create many similar events as follows: ```java theme={} static class UserService { private final EventFactory localBuilder; UserService(HoneyClient libHoney) { int serviceLevelSampleRate = 2; localBuilder = libHoney.buildEventFactory() .addField("serviceName", "userService") .setSampleRate(serviceLevelSampleRate) .build(); } void sendEvent(String username) { localBuilder .createEvent() .addField("userName", username) .addField("userId", UUID.randomUUID().toString()) .setTimestamp(System.currentTimeMillis()) .send(); } } ``` All libraries set defaults that will allow your application to function as smoothly as possible during error conditions. When creating events faster than they can be sent, overflowed events will be dropped instead of backing up and slowing down your application. If you add the same key multiple times, only the last value added will be kept. ## Configuring Libhoney to Disable Sending Events to Honeycomb For situations in which you would like to disable sending events to Honeycomb, such as a test environment or in unit tests, use [`HoneyClient`'s constructor](https://github.com/honeycombio/libhoney-java/blob/main/libhoney/src/main/java/io/honeycomb/libhoney/HoneyClient.java) in which the `Transport` can be overridden. Create a mock `Transport` to substitute in that implements the `Transport` interface. One similar example can be seen [here](https://github.com/honeycombio/beeline-java/blob/df5307cdbf99b22e7bc46fc7e09780b7ec109742/beeline-spring-boot-starter/src/test/java/io/honeycomb/beeline/spring/mockmvctests/MockMvcTest.java). ## Handling Responses Sending an event is an asynchronous action and will avoid blocking by default. `.send()` will enqueue the event to be sent as soon as possible, meaning the return value of that method does not indicate that the event was successfully sent. To see whether events are being successfully received by Honeycomb's servers, register a `ResponseObserver` interface with `HoneyClient`. The `ResponseObserver` interface has four methods which are notified in different circumstances depending on the outcome of the sending of the event: * `onServerAccepted` will be notified for any event that was accepted on the server side * `onServerRejected` will be notified for any event that was rejected on the server side * `onClientRejected` will be notified for any event that was rejected on the client side * `onUnknown` will be notified for any event where the outcome was not clear All responses have methods to extract the original event metadata, metrics collected during the event, and a message explaining the response from Honeycomb: * `getEventMetadata`: Get the event metadata that was originally passed in with the event. The metadata is not modified by the client and not sent to the Honeycomb server. * `getMessage`: Get a human readable message explaining the response. * `getMetrics`: Get any metrics that may have been collected during the lifetime of the event. These metrics will only be complete if a response from the Honeycomb server was received. For responses to events either accepted by or rejected by the server, it is also possible to extract the event status code and raw HTTP response body. * `getEventStatusCode​`: Get the event-specific status code, if it is available, otherwise -1. For batched events this is the status code contained in the batch response body. * `getRawHttpResponseBody​`: Get a byte array of the raw response body. In the case of responses to events rejected by the client, the exception and rejection reason are accessible. * `getException`: Get the exception that may have caused the rejection (returns `null` if no exception was the cause). * `getReason`: Get the reason for the event having been rejected. Before sending an event, you have the option to attach metadata to that event. This metadata is not sent to Honeycomb; instead, it is used to help you match individual responses with sent events. When sending an event, `HoneyClient` will take the metadata from the event and attach it to the response for you to consume. Add metadata by calling `.addMetadata(k, v)` or `addMetadata(Map metadata)` on an event. You do not have to process responses if you are not interested in them—simply ignoring them is perfectly safe. Unread responses will be dropped. ## Troubleshooting Refer to [Common Issues with Sending Data in Honeycomb](/troubleshoot/common-issues/sending-data/#libhoney). ## Contributions Features, bug fixes and other changes to `libhoney` are gladly accepted. Please open issues or a pull request with your change. Remember to add your name to the CONTRIBUTORS file! All contributions will be released under the Apache License 2.0. # Send Data with the OpenTelemetry Java Agent Source: https://docs.honeycomb.io/send-data/java/opentelemetry-agent Instrument your Java application with the OpenTelemetry Java Agent and send traces, logs, and metrics to Honeycomb with minimal code changes. Use the OpenTelemetry Java Agent to instrument Java applications in a standard, vendor-agnostic, and future-proof way and send telemetry data to Honeycomb. In this guide, we will walk you through instrumenting with OpenTelemetry Java Agent, which will include adding automatic instrumentation to your application. For more structured learning, check out the [Instrumentation for OpenTelemetry Java](https://academy.honeycomb.io/app/courses/406eb56b-a3ea-4d48-8ad3-3e2c1945c143) course from Honeycomb Academy. ## Before You Begin Before you can set up automatic instrumentation for your Java application, you will need to do a few things. ### Prepare Your Development Environment To complete the required steps, you will need: * A working Java environment * An application written in Java ### Get Your Honeycomb API Key To send data to Honeycomb, you'll need to [sign up for a free Honeycomb account](https://ui.honeycomb.io/signup) and [create a Honeycomb Ingest API Key](/configure/environments/manage-api-keys/#create-api-key). To get started, you can create a key that you expect to swap out when you deploy to production. Name it something helpful, perhaps noting that it's a getting started key. Make note of your API key; for security reasons, you will not be able to see the key again, and you will need it later! For setup, make sure you check the "Can create datasets" checkbox so that your data will show up in Honeycomb. Later, when you replace this key with a permanent one, you can uncheck that box. If you want to use an API key you previously stored in a secure location, you can also [look up details for Honeycomb API Keys](/configure/environments/manage-api-keys/#find-api-keys) any time in your Environment Settings, and use them to retrieve keys from your storage location. ## Add Automatic Instrumentation Automatic instrumentation is handled with a Java Agent that runs alongside your application. Adding manual instrumentation uses the OpenTelemetry API, which is available when using our SDK as a dependency. ### Acquire Dependencies The OpenTelemetry Java Agent supports many [Java libraries and frameworks](https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/main/docs/supported-libraries.md#libraries---frameworks). The automatic instrumentation agent for OpenTelemetry Java will automatically generate trace data from your application. The agent is packaged as a JAR file and is run alongside your app. In order to use the automatic instrumentation agent, you must first download it: ```shell theme={} curl -L -O https://github.com/open-telemetry/opentelemetry-java-instrumentation/releases/latest/download/opentelemetry-javaagent.jar ``` ### Configure Create an `otelconfig.yaml` file with the following content: ```yaml theme={} file_format: "1.1" resource: attributes: - name: service.name value: ${OTEL_SERVICE_NAME:-my-service} tracer_provider: processors: - batch: exporter: otlp_http: endpoint: https://api.honeycomb.io/v1/traces # Use the endpoint below for EU # endpoint: https://api.eu1.honeycomb.io/v1/traces headers: - name: x-honeycomb-team value: ${HONEYCOMB_API_KEY} propagator: composite: - tracecontext: - baggage: ``` Set the following environment variables before running your application: | Environment Variable | Value | | :------------------- | :----------------------- | | `HONEYCOMB_API_KEY` | Your Honeycomb API key | | `OTEL_SERVICE_NAME` | The name of your service | When `OTEL_CONFIG_FILE` is set, the configuration file is the single source of truth for the SDK. Other `OTEL_*` environment variables are ignored by design, so set all SDK options in the YAML file. You can still reference environment variables from inside the YAML using `${VAR_NAME}` substitution. The OpenTelemetry declarative configuration is stable at the specification level. Individual fields still under active development are marked with a `/development` suffix in the YAML (see [configuration versioning](https://github.com/open-telemetry/opentelemetry-configuration/blob/main/VERSIONING.md#experimental-features)). Check the [language support status](https://github.com/open-telemetry/opentelemetry-configuration/blob/main/language-support-status.md) for per-SDK maturity. Add `meter_provider` and `logger_provider` sections to the same file to export metrics and logs. This version also enables resource detectors, which add attributes such as `host.*` and `process.*` automatically: ```yaml theme={} file_format: "1.1" resource: attributes: - name: service.name value: ${OTEL_SERVICE_NAME:-my-service} detection/development: detectors: - host: - process: - service: tracer_provider: # traces processors: - batch: exporter: otlp_http: endpoint: https://api.honeycomb.io/v1/traces headers: - name: x-honeycomb-team value: ${HONEYCOMB_API_KEY} meter_provider: # metrics readers: - periodic: exporter: otlp_http: endpoint: https://api.honeycomb.io/v1/metrics headers: - name: x-honeycomb-team value: ${HONEYCOMB_API_KEY} # Legacy metrics only; omit with the current metrics experience: # - name: x-honeycomb-dataset # value: ${HONEYCOMB_METRICS_DATASET} logger_provider: # logs processors: - batch: exporter: otlp_http: endpoint: https://api.honeycomb.io/v1/logs headers: - name: x-honeycomb-team value: ${HONEYCOMB_API_KEY} propagator: composite: - tracecontext: - baggage: ``` For the EU instance, replace `https://api.honeycomb.io` with `https://api.eu1.honeycomb.io` throughout the file. If you use [Honeycomb Classic](/troubleshoot/product-lifecycle/recommended-migrations/#migrate-from-honeycomb-classic-to-honeycomb-environments), you must also specify the Dataset for traces using the `x-honeycomb-dataset` header: ```yaml theme={} headers: - name: x-honeycomb-team value: ${HONEYCOMB_API_KEY} - name: x-honeycomb-dataset value: your-dataset ``` ### Run Point the agent at your configuration file using the `OTEL_CONFIG_FILE` environment variable, then run your application: ```shell theme={} OTEL_CONFIG_FILE=./otelconfig.yaml java -javaagent:opentelemetry-javaagent.jar -jar /path/to/myapp.jar ``` In Honeycomb's UI, you should now see your application's incoming requests and outgoing HTTP calls generate traces. ## Add Custom Instrumentation Automatic instrumentation is the easiest way to get started with instrumenting your code. To get additional insight into your system, you should also add custom, or manual, instrumentation where appropriate. You can use manual instrumentation whether you are using the Agent or the Builder. Follow the instructions below to add custom instrumentation to your code. To learn more about custom, or manual, instrumentation, visit the comprehensive set of topics covered by [Manual Instrumentation for Java](https://opentelemetry.io/docs/languages/java/manual/), including [the Annotations API](https://opentelemetry.io/docs/languages/java/automatic/annotations/), in OpenTelemetry's documentation. ### Acquire Dependencies To add custom instrumentation, some OpenTelemetry libraries can be added as dependencies for your application. The OpenTelemetry API provides methods that let you access the currently executing span and add attributes to it, and/or to create new spans. The Annotations library provides decorators the OpenTelemetry JavaAgent will use to [create spans for decorated methods](#creating-spans-around-methods). Use the `opentelemetry-instrumentation-bom` to align the versions of these dependencies with the version of OpenTelemetry JavaAgent in use. ```groovy theme={} dependencies { // Replace '{opentelemetry_java_instrumentation.version}' below with the version of the OTel JavaAgent in use. implementation(platform("io.opentelemetry.instrumentation:opentelemetry-instrumentation-bom:{opentelemetry_java_instrumentation.version}")) implementation("io.opentelemetry:opentelemetry-api") implementation("io.opentelemetry.instrumentation:opentelemetry-instrumentation-annotations") } ``` ```xml theme={} io.opentelemetry.instrumentation opentelemetry-instrumentation-bom {opentelemetry_java_instrumentation.version} pom import io.opentelemetry opentelemetry-api io.opentelemetry.instrumentation opentelemetry-instrumentation-annotations ``` ### Add Attributes to Spans Adding attributes to a currently executing span in a trace can be useful. For example, you may have an application or service that handles users and you want to associate the user with the span when querying your service in Honeycomb. To do this, get the current span from the context and set an attribute with the user ID. In your code, import `io.opentelemetry.api.trace.Span` to get access to the span: ```java theme={} import io.opentelemetry.api.trace.Span; ... Span span = Span.current(); span.setAttribute("user.id", user.getId()); ``` This will add a `user.id` field to the current span so that you can use the field in `WHERE`, `GROUP BY` or `ORDER` clauses in the Honeycomb query builder. ### Acquire a Tracer To create spans, you need to get a `Tracer`. ```java theme={} import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.trace.Tracer; //... Tracer tracer = GlobalOpenTelemetry.getTracer("tracer.name.here"); ``` When you create a `Tracer`, OpenTelemetry requires you to give it a name as a string. This string is the only required parameter. When traces are sent to Honeycomb, the name of the `Tracer` is turned into the `library.name` field, which can be used to show all spans created from a particular tracer. In general, pick a name that matches the appropriate scope for your traces. If you have one tracer for each service, then use the service name. If you have multiple tracers that live in different "layers" of your application, then use the name that corresponds to that "layer". The `library.name` field is also used with traces created from instrumentation libraries. ### Create New Spans Automatic instrumentation can show the shape of requests to your system, but only you know the really important parts. To get the full picture of what's happening, you will have to add custom, or manual, instrumentation and create some custom spans. To do this, create or re-use `Tracer` registered by the Agent and start a span. In your code, import `io.opentelemetry.api.GlobalOpenTelemetry`, `io.opentelemetry.api.trace.Span`, and `io.opentelemetry.api.trace.Tracer`: ```java theme={} import io.opentelemetry.api.GlobalOpenTelemetry; import io.opentelemetry.api.trace.Span; import io.opentelemetry.api.trace.Tracer; ... Tracer tracer = GlobalOpenTelemetry.getTracer("my-service"); Span span = tracer.spanBuilder("expensive-query").startSpan(); // ... do cool stuff span.end(); ``` #### Creating Spans Around Methods You can also use the annotation `@WithSpan` to wrap the execution of a method with a span. The span will be automatically closed once the method has completed. Unless explicitly specified, the span will be named `className.methodName`. To override the name of the span, add a name in parentheses as an argument. In your code, import `io.opentelemetry.instrumentation.annotations.WithSpan` to allow usage of this annotation: ```java theme={} import io.opentelemetry.instrumentation.annotations.WithSpan; ... @WithSpan("importantSpan") public String getImportantInfo() { return importantInfo; } ``` ### Add Multi-Span Attributes Sometimes you want to add the same attribute to many spans within the same trace. This attribute may include variables calculated during your program, or other useful values for correlation or debugging purposes. To add this attribute, leverage the OpenTelemetry concept of [baggage](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/overview.md#baggage-signal). Baggage allows you to add a `key` with a `value` as an attribute to every subsequent child span of the current application context. In your code, import `io.opentelemetry.api.baggage.Baggage` to allow use of the `Baggage` class: ```java theme={} import io.opentelemetry.api.baggage.Baggage; import io.opentelemetry.api.trace.Span; import io.opentelemetry.context.Scope; ... try (final Scope ignored = Baggage.current() .toBuilder() .put("app.username", name) .build() .makeCurrent() ) { // all subsequently created spans in this block will have the `app.username` attribute } ``` Any Baggage attributes that you set in your application will be attached to outgoing network requests as a header. If your service communicates to a third party API, do **NOT** put sensitive information in the Baggage attributes. ## Sampling You can configure the OpenTelemetry SDK to [sample the data](/manage-data-volume/sample/guidelines/) it generates. Honeycomb [weights sampled data based on sample rate](/manage-data-volume/sample/sampled-data-in-honeycomb/), so you must set a resource attribute containing the sample rate. Use a [`TraceIdRatioBased` sampler](https://opentelemetry.io//docs/specs/otel/trace/sdk/#traceidratiobased), with a ratio expressed as `1/N`. Then, also create a resource attribute called `SampleRate` with the value of `N`. This allows Honeycomb to reweigh scalar values, like counts, so that they are accurate even with sampled data. In the example below, our goal is to keep approximately half (1/2) of the data volume. The resource attribute contains the denominator (2), while the OpenTelemetry sampler argument contains the decimal value (0.5). | System Property /
Environment Variable | Value | | :---------------------------------------------------------- | :------------- | | `otel.traces.sampler`
`OTEL_TRACES_SAMPLER` | `traceidratio` | | `otel.traces.sampler.arg`
`OTEL_TRACES_SAMPLER_ARG` | `0.5` | | `otel.resource.attributes`
`OTEL_RESOURCE_ATTRIBUTES` | `SampleRate=2` | The value of `SampleRate` **must** be a positive integer. ## Using HTTP Instead of gRPC By default, OpenTelemetry for Java uses gRPC protocol. To use HTTP instead of gRPC, update the protocol using one of the configuration methods: * System property: `-Dotel.exporter.otlp.protocol=http/protobuf` * Environment variable: `export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf` The protocol can also be set specific to each signal, such as `OTEL_EXPORTER_OTLP_TRACES_PROTOCOL` and `OTEL_EXPORTER_OTLP_METRICS_PROTOCOL`. If you are sending data to Honeycomb directly, you can find Trace and Metric Endpoint configuration options, as well as OpenTelemetry Headers, in the OpenTelemetry for Java chart. If you are using an [OpenTelemetry Collector](/send-data/opentelemetry/collector/), specify the endpoint of the collector, and add the headers to the collector configuration file. ## Endpoint URLs for OTLP/HTTP When using the `OTEL_EXPORTER_OTLP_ENDPOINT` environment variable with an SDK and an HTTP exporter, the final path of the endpoint is modified by the SDK to represent the specific signal being sent. For example, when exporting trace data, the endpoint is updated to append `v1/traces`. When exporting metrics data, the endpoint is updated to append `v1/metrics`. So, if you were to set the `OTEL_EXPORTER_OTLP_ENDPOINT` to `https://api.honeycomb.io`, traces would be sent to `https://api.honeycomb.io/v1/traces` and metrics would be sent to `https://api.honeycomb.io/v1/metrics`. The same modification is not necessary for gRPC. ```shell theme={} export OTEL_EXPORTER_OTLP_ENDPOINT=https://api.honeycomb.io # US instance #export OTEL_EXPORTER_OTLP_ENDPOINT=https://api.eu1.honeycomb.io # EU instance ``` If the desired outcome is to send data to a different endpoint depending on the signal, use `OTEL_EXPORTER_OTLP__ENDPOINT` instead of the more generic `OTEL_EXPORTER_OTLP_ENDPOINT`. When using a signal-specific environment variable, these paths must be appended manually. Set `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` for traces, appending the endpoint with `v1/traces`, and `OTEL_EXPORTER_OTLP_METRICS_ENDPOINT` for metrics, appending the endpoint with `v1/metrics`. Send both traces and metrics to Honeycomb using this method by setting the following variables: ```shell theme={} export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://api.honeycomb.io/v1/traces # US instance #export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://api.eu1.honeycomb.io/v1/traces # EU instance export OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=https://api.honeycomb.io/v1/metrics # US instance #export OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=https://api.eu1.honeycomb.io/v1/metrics # EU instance ``` More details about endpoints and signals can be found in the [OpenTelemetry Specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md). ## Troubleshooting To explore common issues when sending data, visit [Common Issues with Sending Data in Honeycomb](/troubleshoot/common-issues/sending-data/#opentelemetry-sdks-and-honeycomb-distributions). # Instrument Frontend Web Applications with OpenTelemetry Source: https://docs.honeycomb.io/send-data/javascript-browser Instrument your frontend web application with the Honeycomb OpenTelemetry Web SDK to capture Core Web Vitals and user interactions and send them to Honeycomb. The [Honeycomb OpenTelemetry Web SDK](https://github.com/honeycombio/honeycomb-opentelemetry-web) is Honeycomb's distribution of OpenTelemetry for web applications. It includes instrumentation for things like Core Web Vitals as well as instrumentation provided by the standard OpenTelemetry distribution for JavaScript. This page covers basic usage of the SDK, you can find more [examples on GitHub](https://github.com/honeycombio/honeycomb-opentelemetry-web/tree/main/packages/honeycomb-opentelemetry-web/examples). If you're using micro frontend architecture, visit [Observability and Micro Frontends](/get-started/best-practices/micro-frontends/) to see our recommendations for implementing OpenTelemetry and the Honeycomb OpenTelemetry Web SDK. ## Installing the SDK Before you can use Honeycomb’s OpenTelemetry Web SDK, you need to install it. Navigate to the root directory of your web application and install the package: ```shell npm theme={} npm install @honeycombio/opentelemetry-web @opentelemetry/auto-instrumentations-web ``` ```shell yarn theme={} yarn add @honeycombio/opentelemetry-web @opentelemetry/auto-instrumentations-web ``` | Module | Description | | --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | | `auto-instrumentations-web` | OpenTelemetry's meta package that includes various web automatic instrumentation including request and document load instrumentation. | | `opentelemetry-web` | Honeycomb's Web Instrumentation package that streamlines configuration and allows you to instrument as quickly and easily as possible. | Alternatively, install [individual instrumentation packages](https://github.com/open-telemetry/opentelemetry-js#instrumentations). Finally, confirm that the install was successful by opening your `package.json` file and checking that the `Dependencies` list now contains `@honeycomb/opentelemetry-web`. ## Initializing Initialize the SDK at the start of your web application. This ensures that events such as startup time and early asset loads are captured. ```js theme={} import { HoneycombWebSDK, WebVitalsInstrumentation } from '@honeycombio/opentelemetry-web'; import { getWebAutoInstrumentations } from '@opentelemetry/auto-instrumentations-web'; const sdk = new HoneycombWebSDK({ // Uncomment the line below to send to EU instance. Defaults to US. // endpoint: "https://api.eu1.honeycomb.io:443", apiKey: "YOUR-API-KEY", serviceName: "YOUR-SERVICE-NAME", // add automatic instrumentation instrumentations: [getWebAutoInstrumentations(), new WebVitalsInstrumentation()], }); sdk.start(); ``` ## Configuring The Honeycomb OpenTelemetry Web SDK can be configured using these [configuration options](https://github.com/honeycombio/honeycomb-opentelemetry-web/tree/main/packages/honeycomb-opentelemetry-web#sdk-configuration). For example: ```ts theme={} import { HoneycombWebSDK, WebVitalsInstrumentation } from '@honeycombio/opentelemetry-web'; import { getWebAutoInstrumentations } from '@opentelemetry/auto-instrumentations-web'; const sdk = new HoneycombWebSDK({ // Uncomment the line below to send to EU instance. Defaults to US. // endpoint: "https://api.eu1.honeycomb.io:443", apiKey: "YOUR-API-KEY", serviceName: "YOUR-SERVICE-NAME", debug: true, sampleRate: 40, instrumentations: [ getWebAutoInstrumentations(), new WebVitalsInstrumentation() ], webVitalsInstrumentationConfig: { vitalsToTrack: ['CLS', 'FCP', 'INP', 'LCP', 'TTFB'], lcp: { dataAttributes: ['hello', 'world'], }, }, resourceAttributes: { "user.kind": user.kind, // Specific to your app. }, spanProcessors: [ new ExampleSpanProcessor(); ], }); sdk.start(); ``` ### Adding resource attributes Resource attributes are available on every span your instrumentation emits. Adding custom, application-specific attributes makes it easier to correlate your data to important business information. You can set resource attributes using the `resourceAttributes` configuration option. ```ts theme={} import { HoneycombWebSDK } from '@honeycombio/opentelemetry-web'; const sdk = new HoneycombWebSDK({ // Uncomment the line below to send to EU instance. Defaults to US. // endpoint: "https://api.eu1.honeycomb.io:443", apiKey: "YOUR-API-KEY", serviceName: "YOUR-SERVICE-NAME", resourceAttributes: { // Data in this object is applied to every trace emitted. "user.id": user.id, // Specific to your app. "user.role": user.role, // Specific to your app. }, }); sdk.start(); ``` ### Enabling sampling The SDK includes optional [deterministic head sampling](/manage-data-volume/sample/). The sample rate is `1` by default, meaning every trace is exported. The example below sets a `sampleRate` of `40`, meaning 1 in 40 traces will be exported. ```ts theme={} import { HoneycombWebSDK } from '@honeycombio/opentelemetry-web'; const sdk = new HoneycombWebSDK({ apiKey: "YOUR-API-KEY", // Uncomment the line below to send to EU instance. Defaults to US. // endpoint: "https://api.eu1.honeycomb.io:443", serviceName: "YOUR-SERVICE-NAME", sampleRate: 40, }); sdk.start(); ``` ### Sending to OpenTelemetry Collector In production, we recommend running an [OpenTelemetry Collector](/send-data/opentelemetry/collector/). Your application sends telemetry to your Collector instead of directly to Honeycomb. Your Collector then forwards the telemetry data to Honeycomb, keeping your API key stored securely in the Collector's configuration. Configure your Collector's URL by setting the `endpoint` option when initializing the Honeycomb Web SDK: ```ts theme={} import { HoneycombWebSDK } from '@honeycombio/opentelemetry-web'; const sdk = new HoneycombWebSDK({ endpoint: "http(s)://YOUR-COLLECTOR-URL", serviceName: "YOUR-SERVICE-NAME", skipOptionsValidation: true // because we are not including apiKey }); sdk.start(); ``` ### Sending to Honeycomb To send telemetry data directly to Honeycomb, set the `apiKey` option with your [Ingest API Key](/configure/environments/manage-api-keys/#create-api-key). ```ts theme={} import { HoneycombWebSDK } from '@honeycombio/opentelemetry-web'; const sdk = new HoneycombWebSDK({ apiKey: "YOUR-API-KEY", // Uncomment the line below to send to EU instance. Defaults to US. // endpoint: "https://api.eu1.honeycomb.io:443", serviceName: "YOUR-SERVICE-NAME", }); sdk.start(); ``` ### Send to a custom proxy An alternative to the OpenTelemetry Collector is to create your own custom proxy endpoint. Update the `HoneycombWebSDK` with the URL of the custom endpoint and omit your API Key, because that will be set in your proxy. ```javascript theme={} // index.js or main.js // other import statements... import { HoneycombWebSDK } from '@honeycombio/opentelemetry-web'; import { getWebAutoInstrumentations } from '@opentelemetry/auto-instrumentations-web'; const configDefaults = { ignoreNetworkEvents: true, // propagateTraceHeaderCorsUrls: [ // /.+/g, // Regex to match your backend URLs. Update to the domains you wish to include. // ] } const sdk = new HoneycombWebSDK({ debug: true, // Set to false for production environment. serviceName: '[YOUR APPLICATION NAME HERE]', // Replace with your application name. Honeycomb uses this string to find your dataset when we receive your data. When no matching dataset exists, we create a new one with this name if your API Key has the appropriate permissions. endpoint: '[YOUR PROXY ENDPOINT HERE]', instrumentations: [getWebAutoInstrumentations({ // Loads custom configuration for xml-http-request instrumentation. '@opentelemetry/instrumentation-xml-http-request': configDefaults, '@opentelemetry/instrumentation-fetch': configDefaults, '@opentelemetry/instrumentation-document-load': configDefaults, })], }); sdk.start(); // application instantiation code ``` Set the environment variables like the API Key and Honeycomb endpoint in the server-side code to keep it hidden from public view. For example, to setup a proxy using a basic Express server, include the following in a post to either `https://api.honeycomb.io/v1/traces` (if you are using our US instance) or `https://api.eu1.honeycomb.io/v1/traces` (if you are using our EU instance): ```javascript theme={} const options = { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-honeycomb-team': process.env.HONEYCOMB_API_KEY, }, body: JSON.stringify(otlpJsonExportedFromFrontend), }; ``` The server will also need [`cors` setup](https://expressjs.com/en/resources/middleware/cors.html) to allow connections from the browser, and will need to be able to [parse json](https://expressjs.com/en/4x/api.html#express.json). #### Example Express Proxy To accept `POST`s to `http://localhost:3000/v1/traces` from the browser at `http://localhost:5000` to then send on to Honeycomb, the entire code might look like this: ```javascript theme={} // frontend.js const sdk = new HoneycombWebSDK({ endpoint: "http://localhost:3000/v1/traces", serviceName: "your-service-name", skipOptionsValidation: true // because we are not including apiKey instrumentations: [getWebAutoInstrumentations()], }) ``` ```javascript theme={} // backend.js import { config } from 'dotenv'; import express from 'express'; import fetch from 'node-fetch'; import cors from 'cors'; const app = express(); const port = 3000; app.use( cors({ origin: ['http://localhost:5000', 'http://127.0.0.1:5000'], methods: ['POST'], credentials: true, }), ); // Allow parsing of json app.use(express.json()); // our api relay route app.post('/v1/traces', async (req, res) => { try { const otlpJsonExportedFromFrontend = await req.body; const options = { method: 'POST', headers: { 'Content-Type': 'application/json', 'x-honeycomb-team': process.env.HONEYCOMB_API_KEY, }, body: JSON.stringify(otlpJsonExportedFromFrontend), }; // sending on to Honeycomb const response = await fetch('https://api.honeycomb.io/v1/traces', options) // US instance //const response = await fetch('https://api.eu1.honeycomb.io/v1/traces', options) // EU instance .then((response) => console.log(response)) .catch((err) => console.error(err)); return res.json({ success: true, response, }); } catch (err) { return res.status(500).json({ success: false, message: err.message, }); } }); app.listen(port, () => console.log(`Server listening on port ${port}!`)); ``` If your framework has server-side api routes that separate server-side code from the client-side bundle, that may be a viable option to consider for this endpoint. ### Web Vitals instrumentation options Configure [web vitals instrumentation](https://github.com/honeycombio/honeycomb-opentelemetry-web/tree/main/packages/honeycomb-opentelemetry-web#webvitalsinstrumentationconfig) by passing a `WebVitalsInstrumentationConfig` object with your options. ```ts theme={} import { HoneycombWebSDK } from '@honeycombio/opentelemetry-web'; const sdk = new HoneycombWebSDK({ apiKey: "YOUR-API-KEY", // Uncomment the line below to send to EU instance. Defaults to US. // endpoint: "https://api.eu1.honeycomb.io:443", serviceName: "YOUR-SERVICE-NAME", webVitalsInstrumentationConfig: { vitalsToTrack: ['CLS', 'FCP', 'INP', 'LCP', 'TTFB'], lcp: { dataAttributes: ['hello', 'barBiz'], }, }, }); sdk.start(); ``` | name | required? | type | default value | description | | ------------------------- | --------- | -------------------- | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | enabled | optional | boolean | `true` | Whether or not to enable this automatic instrumentation. | | lcp | optional | VitalOpts | `undefined` | Pass-through configuration options for web-vitals. Refer to Google Chrome's [ReportOpts](https://github.com/GoogleChrome/web-vitals?tab=readme-ov-file#reportopts). | | lcp.applyCustomAttributes | optional | function | `undefined` | A function for adding custom attributes to core web vitals spans. | | lcp.dataAttributes | optional | `string[]` | `undefined` | An array of attribute names to filter reported as `lcp.element.data.someAttr`
  • `undefined` will send all `data-*` attribute-value pairs.
  • `[]` will send none
  • `['myAttr']` will send the value of `data-my-attr` or `''` if it's not supplied.

    Note: An attribute that's defined, but that has no specified value, such as `

    `, will be sent as `{`lcp.element.data.myAttr`: '' }`, which is inline with the [dataset API](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/dataset). | | cls | optional | VitalOpts | `undefined` | Pass-through configuration options for web-vitals. Refer to Google Chrome's [ReportOpts](https://github.com/GoogleChrome/web-vitals?tab=readme-ov-file#reportopts). | | cls.applyCustomAttributes | optional | function | `undefined` | A function for adding custom attributes to core web vitals spans. | | inp | optional | VitalOptsWithTimings | `undefined` | Pass-through configuration options for web-vitals. Refer to Google Chrome's [ReportOpts](https://github.com/GoogleChrome/web-vitals?tab=readme-ov-file#reportopts). | | inp.applyCustomAttributes | optional | function | `undefined` | A function for adding custom attributes to core web vitals spans. | | inp.includeTimingsAsSpans | optional | boolean | `false` | When set to `true`, this option will emit `PerformanceLongAnimationFrameTiming` and `PerformanceScriptTiming` as spans. | | fcp | optional | VitalOpts | `undefined` | Pass-through configuration options for web-vitals. Refer to Google Chrome's [ReportOpts](https://github.com/GoogleChrome/web-vitals?tab=readme-ov-file#reportopts). | | fcp.applyCustomAttributes | optional | function | `undefined` | A function for adding custom attributes to core web vitals spans. | | ttf | optional | VitalOpts | `undefined` | Pass-through configuration options for web-vitals. Refer to Google Chrome's [ReportOpts](https://github.com/GoogleChrome/web-vitals?tab=readme-ov-file#reportopts). | | ttf.applyCustomAttributes | optional | function | `undefined` | A function for adding custom attributes to core web vitals spans. | ### Visualizing traces locally Honeycomb's Web Instrumentation package can create a link to a trace visualization in the Honeycomb UI for local traces. Local visualizations enables a faster feedback cycle when adding, modifying, or verifying instrumentation. Enable local visualizations by setting the `localVisualizations` configuration option to `true`. ```javascript theme={} const { HoneycombWebSDK } = require("@honeycombio/opentelemetry-web"); const sdk = new HoneycombWebSDK({ apiKey: "YOUR-API-KEY", // Uncomment the line below to send to EU instance. Defaults to US. // endpoint: "https://api.eu1.honeycomb.io:443", serviceName: "YOUR-SERVICE-NAME", localVisualizations: true, debug: true, }); ``` The output displays the name of the root span and a link to Honeycomb that shows its trace. Select the link to view the trace in detail within the Honeycomb UI. ```text theme={} Trace for root-span-name Honeycomb link: ``` Disable local visualizations for production environments. Local visualization creates additional overhead and should only be used during development or testing. ### Enabling debug logging Turn on debug logging by setting the `debug` configuration option to `true`. ```javascript theme={} const { HoneycombWebSDK } = require("@honeycombio/opentelemetry-web"); const sdk = new HoneycombWebSDK({ apiKey: "YOUR-API-KEY", // Uncomment the line below to send to EU instance. Defaults to US. // endpoint: "https://api.eu1.honeycomb.io:443", serviceName: "YOUR-SERVICE-NAME", debug: true }); ``` When the debug setting is enabled, the Honeycomb Web Instrumentation package configures a [DiagConsoleLogger](https://github.com/open-telemetry/opentelemetry-js/blob/main/api/src/diag/consoleLogger.ts) that logs telemetry to the console with the log level of Debug. The debug setting in the Honeycomb Web Instrumentation package will also output to the console the main options configuration, including but not limited to API Key and endpoint. Keep in mind that printing to the console is not recommended for production and should only be used for debugging purposes. ## Adding automatic instrumentation The Honeycomb OpenTelemetry Web SDK includes [auto-instrumentation](https://github.com/honeycombio/honeycomb-opentelemetry-web/tree/main/packages/honeycomb-opentelemetry-web#auto-instrumentation) for: * [Document & resource loading](https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/packages/instrumentation-document-load) * [Fetch requests](https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/opentelemetry-instrumentation-fetch) * [XML HTTP requests](https://github.com/open-telemetry/opentelemetry-js/tree/main/experimental/packages/opentelemetry-instrumentation-xml-http-request) * [User interactions](https://github.com/open-telemetry/opentelemetry-js-contrib/tree/main/packages/instrumentation-user-interaction) * [Core web vitals](https://github.com/honeycombio/honeycomb-opentelemetry-web/blob/main/docs/web-vitals.md) Automatic instrumentation is enabled by default. You can enable or disable individual auto-instrumentation libraries in your configuration using the `instrumentations` option. ```ts theme={} import { HoneycombWebSDK, WebVitalsInstrumentation } from '@honeycombio/opentelemetry-web'; import { getWebAutoInstrumentations } from '@opentelemetry/auto-instrumentations-web'; const configDefaults = { ignoreNetworkEvents: true, propagateTraceHeaderCorsUrls: [ /.+/g, // Regex to match your backend URLs. Update to the domains you wish to include. ] } const sdk = new HoneycombWebSDK({ // Uncomment the line below to send to EU instance. Defaults to US. // endpoint: "https://api.eu1.honeycomb.io:443", apiKey: "YOUR-API-KEY", serviceName: "YOUR-SERVICE-NAME", instrumentations: [ getWebAutoInstrumentations({ // optionally apply defaults config to instrumentation '@opentelemetry/instrumentation-xml-http-request': configDefaults, '@opentelemetry/instrumentation-fetch': configDefaults, // optionally disable document load instrumentation '@opentelemetry/instrumentation-document-load': { enabled: false }, }), new WebVitalsInstrumentation() ], }); sdk.start(); ``` ## Adding custom instrumentation Automatic instrumentation is a fast way to instrument your code, but you get more insight into your application by adding custom, otherwise known as manual, instrumentation. Adding custom instrumentation requires the the OpenTelemetry API package. ```shell npm theme={} npm install --save @opentelemetry/api ``` ```shell yarn theme={} yarn add @opentelemetry/api ``` ### Adding attributes to an active span You can retrieve the currently active span in a trace and add attributes to it. This lets you add more context to traces and gives you more ways to group or filter traces in your queries. ```ts TypeScript theme={} import { trace } from '@opentelemetry/api'; function handleUser(user: User) { let currentActiveSpan = trace.getActiveSpan(); currentActiveSpan.setAttribute('user.id', user.getId()); } ``` ```js JavaScript theme={} const { trace } = require("@opentelemetry/api"); function handleUser(user) { let activeSpan = trace.getActiveSpan(); activeSpan.setAttribute("user.id", user.getId()); } ``` ### Acquiring a tracer For manual tracing, you need to get a tracer: ```typescript TypeScript theme={} import { trace } from '@opentelemetry/api'; const tracer = trace.getTracer("tracer.name.here"); ``` ```js JavaScript theme={} const { trace } = require("@opentelemetry/api"); const tracer = trace.getTracer("tracer.name.here"); ``` When you create a `Tracer`, OpenTelemetry requires you to give it a name as a string. This string is the only required parameter. When traces are sent to Honeycomb, the name of the `Tracer` is turned into the `library.name` field, which can be used to show all spans created from a particular tracer. In general, pick a name that matches the appropriate scope for your traces. If you have one tracer for each service, then use the service name. If you have multiple tracers that live in different "layers" of your application, then use the name that corresponds to that "layer". The `library.name` field is also used with traces created from instrumentation libraries. ### Creating spans Create custom spans to get a clear view of the critical parts in your application. ```typescript TypeScript theme={} import { trace } from '@opentelemetry/api'; const tracer = trace.getTracer('example-tracer', '0.1.0'); function trackWork() { const span = tracer.startActiveSpan('do work'); console.log('performing work'); span.end(); } ``` ```javascript JavaScript theme={} const { trace } = require("@opentelemetry/api"); const tracer = trace.getTracer("my-service-tracer"); function trackWork() { const span = tracer.startActiveSpan('do work'); console.log('performing work'); span.end(); } ``` ### Adding multi-span attributes Sometimes you want to add the same attribute to many spans within the same trace. This attribute may include variables calculated during your program, or other useful values for correlation or debugging purposes. To add this attribute, leverage the OpenTelemetry concept of [baggage](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/overview.md#baggage-signal). Baggage allows you to add a `key` with a `value` as an attribute to every subsequent child span within the current application context. ```typescript TypeScript theme={} import { Context, context, propagation, } from '@opentelemetry/api'; tracer.startActiveSpan('main', (span) => { span.setAttribute('app.username', name); // add to current span // new context based on current, with key/values added to baggage const ctx: Context = propagation.setBaggage( context.active(), propagation.createBaggage({ 'app.username': { value: name } }) ); // within the new context, do some work and baggage will be // applied as attributes on child spans context.with(ctx, () => { tracer.startActiveSpan('childSpan', (childSpan) => { doTheWork(); childSpan.end(); }); }); span.end(); }); ``` ```javascript JavaScript theme={} tracer.startActiveSpan('main', (span) => { span.setAttribute('app.username', name); // add to current span // new context based on current, with key/values added to baggage const ctx = propagation.setBaggage( context.active(), propagation.createBaggage({ 'app.username': { value: name } }) ); // within the new context, do some work and baggage will be // applied as attributes on child spans context.with(ctx, () => { tracer.startActiveSpan('childSpan', (childSpan) => { doTheWork(); childSpan.end(); }); }); span.end(); }); ``` ## Adding custom span processing The Honeycomb Web SDK uses span processors as synchronous hooks for when a span starts and when a span ends. This lets you mutate spans after they have been created by automatic instrumentation or manually. Some examples of the actions you can take on spans in a span processor include: * Add attributes * Add span events * Add span links * Update the name of a span * Record an exception on a span * Get the span context to create child spans * Stop spans from being sent ### Example: Basic custom span processor Here is a basic example of a custom span processor: ```typescript theme={} class TestSpanProcessorOne implements SpanProcessor { onStart(span: Span): void { span.setAttributes({ 'processor1.name': 'TestSpanProcessorOne', }); } onEnd(): void {} forceFlush() { return Promise.resolve(); } shutdown() { return Promise.resolve(); } } ``` To use it, add the span processor to your configuration when you initialize the Honeycomb Web SDK: ```typescript theme={} const sdk = new HoneycombWebSDK({ debug: true, apiKey: 'api-key-goes-here', serviceName: 'hny-web-distro', // ... other config spanProcessors: [new TestSpanProcessorOne()], }); sdk.start(); ``` ### Example: Adding user information after SDK initialization Here is an example span processor that adds custom information for users: ```typescript theme={} import { SpanProcessor } from '@opentelemetry/sdk-trace-base'; import { Span } from '@opentelemetry/api'; export class UserInfoSpanProcessor implements SpanProcessor { userInfo: { userId: string; customerId: string; role: string } | undefined; constructor() { const getUserInfo = (): Promise<{ userId: string; customerId: string; role: string; }> => { return new Promise((resolve) => { setTimeout(() => { resolve({ userId: '1234', customerId: '5678', role: 'admin', }); }, 2000); }); }; getUserInfo().then( (userInfo: { userId: string; customerId: string; role: string }) => { this.userInfo = userInfo; }, ); } onStart(span: Span) { if (this.userInfo) { span.setAttributes({ 'app.user.id': this.userInfo.userId, 'app.user.customer_id': this.userInfo.customerId, 'app.user.role': this.userInfo.role, }); } } onEnd() {} forceFlush() { return Promise.resolve(); } shutdown() { return Promise.resolve(); } } ``` To use it, add the span processor to your configuration when you initialize the Honeycomb Web SDK: ```typescript theme={} const sdk = new HoneycombWebSDK({ debug: true, apiKey: 'api-key-goes-here', serviceName: 'hny-web-distro', // ... other configuration spanProcessors: [new UserInfoSpanProcessor()], }); sdk.start(); ``` ### Example: Dynamic page routes with React Router Here is an example span processor that adds attributes to spans based on the state of the React Router. It sets the `page.route` attribute to the generic dynamic route, and records the span as an error if there are errors in the router state. ```typescript theme={} import { SpanProcessor } from '@opentelemetry/sdk-trace-base'; import { Span } from '@opentelemetry/api'; /** * SpanProcessor that adds attributes to spans based on the state of the React Router * Sets the page.route attribute to the generic dynamic route * Records the span as an error if there are errors in the router state (e.g. 404) */ export class ReactRouterSpanProcessor implements SpanProcessor { router; route; constructor({ router }: { router }) { this.router = router; this.route = router.state.matches[router.state.matches.length - 1]?.route.path; this.router.subscribe((state: any) => { this.route = state.matches[state.matches.length - 1]?.route.path; }); } onStart(span: Span) { const { errors } = this.router.state; // If there are errors, set the span status to error and record the error message if (errors !== null) { span.setStatus({ code: 2, message: errors[0].data, }); } // Set the page.route as the generic dynamic route, making things easier to query // e.g. /name/:name/pet/:pet instead of name/123/pet/456 // url.path attribute will have the more specific computed route span.setAttributes({ 'page.route': this.route }); } onEnd() {} forceFlush() { return Promise.resolve(); } shutdown() { return Promise.resolve(); } } ``` To use it, add the span processor to your configuration when you initialize the Honeycomb Web SDK: ```typescript theme={} const sdk = new HoneycombWebSDK({ debug: true, apiKey: 'api-key-goes-here', serviceName: 'hny-web-distro', // ... other configuration spanProcessors: [new ReactRouterSpanProcessor({ router: router })], }); sdk.start(); ``` ## Propagating span context A [Context Manager](https://opentelemetry.io/docs/languages/js/context/#context-manager) stores and propagates global span context through your system. OpenTelemetry provides a context manager for browser instrumentation based on the [Zone.js](https://github.com/angular/angular/tree/main/packages/zone.js) library to track global context across asynchronous execution threads. This context manager can be added used in your instrumentation like so: ```js theme={} import { ZoneContextManager } from '@opentelemetry/context-zone'; const sdk = new HoneycombWebSDK({ // other config options omitted... contextManager: new ZoneContextManager() }); sdk.start(); ``` Zone.js has known limitations with async/await code, and [requires](https://github.com/open-telemetry/opentelemetry-js/tree/main/packages/opentelemetry-context-zone-peer-dep#installation) your code to be transpiled down to ES2015. It may also negatively impact your application's performance. For these reasons, the Honeycomb Web SDK does not enable the Zone.js context manager by default. ### Automatically propagate the trace context header Use request automatic instrumentation to automatically send spans for every HTTP request. `@opentelemetry/instrumentation-xml-http-request` automatically instruments XHR requests and `@opentelemetry/instrumentation-fetch` automatically instruments fetch requests. If your browser application uses a request library to make requests, such as [`axios`](https://axios-http.com/) or [`superagent`](https://github.com/ladjs/superagent), these requests are also automatically instrumented by enabling the `xml-http-request` or `fetch` instrumentation, depending on what the library uses to make requests. When using the Honeycomb Instrumentation snippet (as documented on this page), uncomment the `propagateTraceHeaderCorsUrls` array and add regex to include all target domains. This method allows you to propagate to your backend services without leaking trace IDs to third-party services. ```javascript theme={} const configDefaults = { ignoreNetworkEvents: true, propagateTraceHeaderCorsUrls: [ /.+/g, // Regex to match your backend URLs. Update to the domains you wish to include. ] } ``` ### Manually propagate the trace context header It is also possible to manually propagate the [trace context header](https://www.w3.org/TR/trace-context/) if automatic instrumentation is not an option: ```javascript theme={} // General request handler, instrumented with OTel // Forwards traceparent header to connect spans created in the browser // with spans created on the backend const request = async (url, method = 'GET', headers, body) => { return trace .getTracer('request-tracer') .startActiveSpan(`Request: ${method} ${url}`, async (span) => { // construct W3C traceparent header const traceparent = `00-${span.spanContext().traceId}-${span.spanContext().spanId}-01`; try { const response = await fetch(url, { method, headers: { ...headers, // set traceparent header traceparent: traceparent, }, body, }); span.setAttributes({ 'http.method': method, 'http.url': url, 'response.status_code': response.status, }); if (response.ok && response.status >= 200 && response.status < 400) { span.setStatus({ code: SpanStatusCode.OK }); return response.text(); } else { throw new Error(`Request Error ${response.status} ${response.statusText}`); } } catch (error) { span.setStatus({ code: SpanStatusCode.ERROR, message: error.message }); throw new Error(error); } finally { span.end(); } }); }; ``` ## Troubleshooting Running into issues? Here are some common problems and ways to fix them. To explore common issues when sending data, visit [Common Issues with Sending Data in Honeycomb](/troubleshoot/common-issues/sending-data/#opentelemetry-sdks-and-honeycomb-distributions). ### Dataset not appearing in Honeycomb The `apiKey` variable is used to send your data to Honeycomb. Make sure you have replaced the placeholder value for it with your Honeycomb Ingest API Key and that your API key permissions include "Can create datasets". If Honeycomb is successfully instantiating but your API key is not included, you should see output similar to the following in your browser console: ```bash theme={} @opentelemetry/api: Registered a global for diag v1.7.0 @honeycombio/opentelemetry-web: Honeycomb Web SDK Debug Mode Enabled @honeycombio/opentelemetry-web: API Key configured for traces: '' @honeycombio/opentelemetry-web: Service Name configured for traces: '' @honeycombio/opentelemetry-web: Endpoint configured for traces: 'https://api.honeycomb.io/v1/traces' @honeycombio/opentelemetry-web: Sample Rate configured for traces: '1' ``` ### Dataset has unexpected name We use the `serviceName` variable to name your dataset in Honeycomb. Be sure you have replaced the placeholder value for it with a name that you will find useful. ### Next.js "Navigator Is Undefined" error If a "navigator is undefined" error appears when you attempt to start your local server while following Next.js instructions, the instrumentation is being run in a server-side rendering path. To fix this, try adding the `'use client';` directive at the top of the file where you instantiate Honeycomb’s web instrumentation. Adding the `'use client';` directive tells React to only execute the file in a client environment. If you are still seeing an error after adding the `'use client';` directive, try wrapping the function in a try/catch block. By wrapping the function, you can catch the error and avoid instantiation in server-side environments, ensuring that your application starts up even if the code is executed in a server-side environment. ```javascript theme={} try { const sdk = new HoneycombWebSDK({ debug: true, apiKey: '[YOUR API KEY HERE]' // Replace with your Honeycomb Ingest API Key serviceName: '[YOUR APPLICATION NAME HERE]', // Replace with your application name. Honeycomb will name your dataset using this variable. instrumentations: [getWebAutoInstrumentations()], // Adds automatic instrumentation }); sdk.start(); } catch (e) {} ``` ### Receiving 464 errors You may receive a `464` error response from the Honeycomb API when sending telemetry using gRPC and HTTP1. The gRPC format depends on using HTTP2 and any request over HTTP1 will be rejected by the Honeycomb servers. # Symbolicate JavaScript Stack Traces with the OpenTelemetry Collector Source: https://docs.honeycomb.io/send-data/javascript-browser/symbolicate Use the source map processor in the OpenTelemetry Collector to resolve minified JavaScript stack traces into readable symbols for easier debugging. Use the sourcemap processor in your OpenTelemetry Collector to symbolicate JavaScript (JS) stack traces. The [sourcemap processor](https://github.com/honeycombio/opentelemetry-collector-symbolicator?tab=readme-ov-file#javascript-source-maps) replaces minified names and addresses in your JS stack traces with symbols from provided source maps. ## Before You Start The sourcemap processor is compatible with [Honeycomb OpenTelemetry Web SDK](https://github.com/honeycombio/honeycomb-opentelemetry-web) version 0.12.0 and later. To use the sourcemap processor, you need: * OpenTelemetry Collector built with `CGO` enabled. * An environment or container image with `glibc` support. We recommend `gcr.io/distroless/cc`, a secure and lightweight container image with CGO and `glibc` support. If you're not using the Honeycomb OpenTelemetry Web SDK, make sure your exception data is in [the format the processor expects](https://github.com/honeycombio/opentelemetry-collector-symbolicator/blob/main/README.md#exception-information-format). ## Install By default, the [Honeycomb OpenTelemetry Collector distribution](https://github.com/honeycombio/honeycomb-collector-distro) includes the sourcemap processor, so you can skip to the next section if you're using it. If you use another collector distribution or build your own, it must be built with CGO enabled. You can install the sourcemap processor by adding it to your OpenTelemetry Collector build configuration file: ```yaml theme={} processors: - gomod: github.com/honeycombio/opentelemetry-collector-symbolicator/sourcemapprocessor v0.0.14 ``` You can find the latest sourcemap processor version on the [releases page](https://github.com/honeycombio/opentelemetry-collector-symbolicator/releases) in the GitHub repo. ## Source Files and Source Maps The sourcemap processor requires access to your minimized JS source files and associated source maps. These can be stored in your local file system, Amazon S3, or Google Cloud Storage. To support symbolication, your minified source files must have a comment with a `sourceMappingURL` pointing to the relative path of the source map file. ```js theme={} //# sourceMappingURL=/static/dist/main.c383b093b0b66825a9c3.js.map ``` You should also version your source files and source maps with a file hash in the file name, for example: `vendor.1c285a50f5307be9648d.js`. This helps prevent conflicts and ensure the correct file versions are used. ## Configure a File Store Add the `source_map_symbolicator` as a processor in your OpenTelemetry Collector configuration: ```yaml theme={} processors: source_map_symbolicator: ``` You can then configure where your source maps are stored. By default, the sourcemap processor loads source map files from a local directory. You can set the file path in your collector configuration: ```yaml theme={} processors: source_map_symbolicator: # source_map_store is sets which store to use, in this case local disk source_map_store: file_store local_source_maps: # (optional) path sets the base path of the files, defaults to `.` path: /tmp/sourcemaps ``` Make sure your collector can access the `path` directory you set, and that file paths in stack traces match the structure of your configured file store. #### How the Processor Retrieves Files from Local Disk When retrieving files from local disk, the processor: 1. Gets the base file name from the URL included in the stack trace. 2. The `path`, if configured, is joined with the base file name. 3. Reads the file using the joined path from disk. For example: * Original URL: `https://example.com/static/dist/main.c383b093b0b66825a9c3.js` * `path` is set to `/tmp/sourcemaps` * New path: `/tmp/sourcemaps/main.c383b093b0b66825a9c3.js.map` Optionally, you can load source maps from an Amazon S3 bucket. Add to your OpenTelemetry Collector configuration: ```yaml theme={} processors: source_map_symbolicator: # source_map_store sets which store to use, in this case S3 source_map_store: s3_store s3_source_maps: # name of the bucket the files are stored in bucket: source-maps-bucket # (optional) the bucket's region region: us-east-1 # (optional) prefix is used to nest the files in a sub key of the bucket prefix: source-maps ``` Make sure your collector has permission to access the S3 bucket. Also, ensure the file paths in stack traces match the structure used in your file store. #### How the Processor Retrieves Files from S3 When retrieving files from an Amazon S3 bucket, the processor: 1. Gets the base file name from the URL included in the stack trace. 2. The `prefix`, if configured, is joined with the base file name. 3. Uses this joined path as the key to retrieve the file from the bucket. For example: * Original URL: `https://example.com/static/dist/main.c383b093b0b66825a9c3.js` * `prefix` is set to `source-maps` * New path: `sourcemaps/main.c383b093b0b66825a9c3.js.map` Optionally, you can load source maps from a Google Cloud Storage (GCS) bucket. Add to your OpenTelemetry Collector configuration: ```yaml theme={} processors: source_map_symbolicator: # source_map_store sets which store to use, in this case GCS source_map_store: gcs_store gcs_source_maps: # the name of the bucket the files are stored in bucket: source-maps-bucket # (optional) prefix is used to nest the files in a sub key of the bucket prefix: source-maps ``` Make sure your collector has permission to access the GCS bucket. Also, ensure the file paths in stack traces match the structure used in your file store. #### How the Processor Retrieves Files from GCS When retrieving files from a Google Cloud Storage bucket, the processor: 1. Gets the base file name from the URL included in the stack trace. 2. The `prefix`, if configured, is joined with the base file name. 3. Uses this joined path as the key to retrieve the file from the bucket. For example: * Original URL: `https://example.com/static/dist/main.c383b093b0b66825a9c3.js` * `prefix` is set to `source-maps` * New path: `source-maps/main.c383b093b0b66825a9c3.js.map` ## Advanced Configuration In addition to basic setup, you can customize how the sourcemap processor handles stack traces by configuring attribute mappings and additional processing options. After updating the configuration file, restart the OpenTelemetry Collector to apply the changes. ### Mapping Attributes Use these configuration options to specify which attributes the processor should read from and write to when handling stack traces: | Config Key | Description | Example Value | | ------------------------------------------- | ------------------------------------------------------------------------------------------------- | ---------------------------------------------------- | | `symbolicator_failure_attribute_key` | Signals if the the symbolicator fails to fully symbolicate the stack trace | `exception.symbolicator.failed` | | `symbolicator_error_attribute_key` | Contains the error message if the the symbolicator fails to fully symbolicate the stack trace | `exception.symbolicator.error` | | `symbolicator_parsing_method_attribute_key` | Stores the stack trace parsing method used by the processor | `exception.symbolicator.parsing_method` | | `columns_attribute_key` | Which attribute should the columns of the stack trace be sourced from | `exception.structured_stacktrace.columns` | | `functions_attribute_key` | Which attribute should the functions of the stack trace be sourced from | `exception.structured_stacktrace.functions` | | `lines_attribute_key` | Which attribute should the lines of the stack trace be sourced from | `exception.structured_stacktrace.lines` | | `urls_attribute_key` | Which attribute should the urls of the stack trace be sourced from | `exception.structured_stacktrace.urls` | | `stack_trace_attribute_key` | Which attribute should the symbolicated stack trace be populated into | `exception.stacktrace` | | `exception_type_attribute_key` | Which attribute contains the exception type | `exception.type` | | `exception_message_attribute_key` | Which attribute contains the exception message | `exception.message` | | `preserve_stack_trace` | After the stack trace has been symbolicated should the original values be preserved as attributes | `true` | | `original_stack_trace_attribute_key` | If the stack trace is being preserved which key should it be copied to | `exception.stacktrace.original` | | `original_columns_attribute_key` | If the stack trace is being preserved which key should the functions be copied to | `exception.structured_stacktrace.functions.original` | | `original_functions_attribute_key` | If the stack trace is being preserved which key should the lines be copied to | `exception.structured_stacktrace.lines.original` | | `original_lines_attribute_key` | If the stack trace is being preserved which key should the columns be copied to | `exception.structured_stacktrace.columns.original` | | `original_urls_attribute_key` | If the stack trace is being preserved which key should the urls be copied to | | ### Additional Processing Options Use these configuration options to control how stack traces are processed and managed: | Config Key | Description | Example Value | | ----------------------- | ------------------------------------------------------------------------------------------------------------------- | ------------- | | `timeout` | Maximum time (in seconds) to wait for symbolication before timing out. | `5` | | `source_map_cache_size` | Maximum number of source maps to cache in memory. Reduce this value if the Collector encounters memory constraints. | `128` | ### Language-Based Routing The source map processor supports language-based routing to ensure it only processes signals from JavaScript/TypeScript applications. This prevents the processor from running on signals from other languages (like Java or Swift), improving performance and avoiding unnecessary processing. | Config Key | Description | Default Value | Example Values | | ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------- | ------------------------------------- | | `language_attribute_key` | The attribute key that contains the programming language or SDK language of the telemetry signal. | `telemetry.sdk.language` | `telemetry.sdk.language` | | `allowed_languages` | A list of language values that this processor will handle. If the signal's language attribute matches any value in this list, the processor will run. If empty (default), the processor will process all signals regardless of language. **Important:** When `allowed_languages` is configured, signals without a language attribute will be skipped. | `[]` (empty, processes all) | `["javascript", "webjs", "hermesjs"]` | If using Honeycomb's React Native SDK, you'll want to enable `hermesjs` as a value. See the [SDK's default attribute values](https://github.com/honeycombio/honeycomb-opentelemetry-react-native/tree/main?tab=readme-ov-file#default-attributes) **Example configuration:** ```yaml theme={} processors: source_map_symbolicator: allowed_languages: ["javascript", "webjs"] ``` `allowed_languages` configuration behavior: * Empty `allowed_languages` (default): Processes all signals, regardless of language attribute. * With `allowed_languages` configured: Only processes signals where the language attribute matches one of the allowed values (case-insensitive). * Missing language attribute: Skips processing when `allowed_languages` is configured. # Send Data to Honeycomb with Node.js Source: https://docs.honeycomb.io/send-data/javascript-nodejs Explore available methods for sending telemetry from your Node.js application to Honeycomb. When you are working with Node.js, we recommend these methods of sending data to Honeycomb. When you want to instrument Node.js applications in a standard, vendor-agnostic, and future-proof way, we recommend using the OpenTelemetry JavaScript SDK to send telemetry data to Honeycomb. The OpenTelemetry JavaScript SDK allows you to send traces and metrics. Logs is in development. When you need to create and send structured logs to Honeycomb, use Libhoney for Node.js, our structured logging library for Node.js applications. # Send Logs with Libhoney for JavaScript Source: https://docs.honeycomb.io/send-data/javascript-nodejs/libhoney Send structured events to Honeycomb from your JavaScript application using Libhoney, Honeycomb's low-level structured logging library for the Events API. Libhoney for JavaScript is Honeycomb's structured logging library for JavaScript applications. It is a low-level library that helps you send structured events to Honeycomb's [Events API](/api/events/). If you are instrumenting a new application for tracing, we recommend that you use [OpenTelemetry](/send-data/opentelemetry/) instead. For direct use in browser-side JavaScript applications, make sure to generate a separate API key that can only send events. Leaking an API key with those permissions would allow malicious users to access other data such as markers. See our [Browser JS guide](/send-data/javascript-browser/) for more information on how you can more safely send data about your web app from the client to Honeycomb. ## Installation ```shell npm theme={} npm install libhoney --save ``` ```shell yarn theme={} yarn add libhoney ``` ## Links * [Source Code](https://github.com/honeycombio/libhoney-js) * [Examples](https://github.com/honeycombio/libhoney-js/tree/main/examples) ## Initialization Initialize the library by passing in your Team API key and the default dataset name to which it should send events. Using ES6 modules: ```javascript theme={} import Libhoney from "libhoney"; let hny = new Libhoney({ writeKey: "YOUR_API_KEY", dataset: "honeycomb-js-example" // disabled: true // uncomment for testing or development. }); ``` Using `require`: ```javascript theme={} var Libhoney = require("libhoney"); var hny = new Libhoney({ writeKey: "YOUR_API_KEY", dataset: "honeycomb-js-example" }); ``` ### Using a Proxy To route event traffic through a proxy, configure it by passing an additional item, like: ```javascript theme={} import Libhoney from "libhoney"; let hny = new Libhoney({ proxy: "https://proxy-address-or-name:port", writeKey: "YOUR_API_KEY", dataset: "honeycomb-js-example" // disabled: true // uncomment for testing or development. }); ``` Find further configuration options in [the source code](https://github.com/honeycombio/libhoney-js/blob/b43b445a75188d2d2037fb32933262355155dd03/src/libhoney.js#L22). To silence `libhoney` in a test or development environment, include `{ disabled: true }` in the `new libhoney(...)` initialization. ## Building and Sending Events Once initialized, `libhoney` is ready to send events. Events go through three phases: * Creation `event = libhoney.newEvent()` * Adding fields `event.addField("key", "val")`, `event.add(dataMap)` * Transmission `event.send()` Upon calling `.send()`, the event is dispatched to be sent to Honeycomb. All libraries set defaults that will allow your application to function as smoothly as possible during error conditions. If you create events faster than they can be sent, overflowed events are dropped instead of backing up and slowing down your application. In its simplest form, you can add a single attribute to an event with the `.addField(k, v)` method. If you add the same key multiple times, only the last value added is kept. Other JavaScript objects can be added to an event with the `.add(data)` method. Events can have metadata associated with them that is not sent to Honeycomb. This metadata is used to identify the event when processing the response. More detail about metadata is below in the Response section. ## Handling Responses Sending an event is an asynchronous action and will avoid blocking by default—calling `.send()` will enqueue the event to be sent as soon as possible. Assign a `responseCallback` to check whether events were successfully received by Honeycomb's servers. Before sending an event, you have the option to attach metadata to that event. This metadata is not sent to Honeycomb; instead, it is used to help you match up individual responses with sent events. When sending an event, `libhoney` will take the metadata from the event and attach it to the response object for you to consume. Add metadata by populating the `.metadata` attribute directly on an event. For instance: ```javascript theme={} let hny = new Libhoney({ writeKey: "YOUR_API_KEY", dataset: "honeycomb-js-example", responseCallback: responses => { responses.forEach(resp => { console.log(resp); }); } }); let ev = hny.newEvent(); ev.addField("latencyMs", 240); ev.metadata = { id: "recognize-me-later" }; ev.send(); ``` This will print out the asynchronous responses from sending the event or batch of events. A status code of `200` or `202` indicates the event was received by our API successfully, whereas other status codes could indicate issues such as write key authentication failures or rate limiting. ```javascript theme={} { status_code: 202, duration: 320, metadata: {id: "recognize-me-later"}, error: undefined } ``` Responses have a number of fields describing the result of an attempted event send: * **metadata**: the metadata you attached to the event to which this response corresponds * **status\_code**: the HTTP status code returned by Honeycomb when trying to send the event. `2xx` indicates success. * **duration**: the number of milliseconds it took to send the event. * **error**: when the event does not even get to create a HTTP attempt, the reason will be in this field. (For example, when sampled or dropped because of a queue overflow.) You do not have to process responses if you are not interested in them—simply ignoring them is perfectly safe. Unread responses will be dropped. ## Examples Honeycomb can calculate all sorts of statistics, so send the data you care about and let us crunch the averages, percentiles, lower/upper bounds, cardinality—whatever you want—for you. ### Simple: Send a Blob Immediately ```javascript theme={} import Libhoney from "libhoney"; let hny = new Libhoney({ writeKey: "YOUR_API_KEY", dataset: "honeycomb-js-example" }); hny.sendNow({ message: "Test Honeycomb event", randomFloat: Math.random(), hostname: os.hostname(), favoriteColor: "chartreuse" }); ``` ### Intermediate: Override Some Attributes ```javascript theme={} // ... Initialization code ... let params = { hostname: "foo.local", built: false, userId: -1 }; hny.add(params); let builder = hny.newBuilder({ built: true }); // Spawn a new event and override the timestamp let event = builder.newEvent(); event.addField("userId", 15); event.addField("latencyMs", Date.now() - start); event.timestamp = new Date(Date.UTC(2016, 1, 29, 1, 1, 1)); event.send(); ``` Further examples can be found [on GitHub](https://github.com/honeycombio/libhoney-js). ## Middleware Examples: Express [Express](https://expressjs.com/) is light, flexible, and built to make it easy to drop in utility and middleware functionality to augment your application logic. Each inbound HTTP request as received by a framework like Express maps nicely to Honeycomb events, representing "a single thing of interest that happened" in a given system. Express middleware functions are simply functions that have access to the request object, response object, and next middleware function in the application's request-response chain. As such, you can define a simple `express-honey.js` file as in the following: ```javascript theme={} import Libhoney from "libhoney"; module.exports = function(options) { let honey = new Libhoney(options); return function(req, res, next) { honey.sendNow({ app: req.app, baseUrl: req.baseUrl, fresh: req.fresh, hostname: req.hostname, ip: req.ip, method: req.method, originalUrl: req.originalUrl, params: req.params, path: req.path, protocol: req.protocol, query: req.query, route: req.route, secure: req.secure, xhr: req.xhr }); next(); }; }; ``` And, in your Express `app.js`, configure your new `express-honey` and include it in the execution path like the following: ```javascript theme={} let express = require("express"); let hny = require("./express-honey"); let app = express(); app.use( hny({ apiHost: process.env["HONEY_API_HOST"], writeKey: process.env["YOUR_API_KEY"], dataset: process.env["HONEY_DATASET"] }) ); // ... additional Express handling code here ``` See the [`examples/` directory on GitHub](https://github.com/honeycombio/libhoney-js/tree/main/examples) for more sample code demonstrating how to use events, builders, fields, and dynamic fields, specifically in the context of Express middleware. ## Advanced Usage: Using Builders Builders are, at their simplest, a convenient way to avoid repeating common attributes that may not apply globally. Creating a builder for a given component allows a variety of different events to be spawned and sent within the component, without having to repeat the component name as an attribute for each. You can clone builders—the cloned builder will have a copy of all the fields and dynamic fields in the original. As your application forks down into more and more specific functionality, you can create more detailed builders. The final event creation in the leaves of your application's tree will have all the data you have added along the way in addition to the specifics of this event. The global scope is essentially a specialized builder, for capturing attributes that are likely useful to all events (for example, hostname or environment). Adding this kind of peripheral and normally unavailable information to every event gives you enormous power to identify patterns that would otherwise be invisible in the context of a single request. ## Advanced Usage: Dynamic Fields The top-level `libhoney` and Builders support `.addDynamicField(func)`. Adding a dynamic field to a Builder or top-level `libhoney` ensures that each time an event is created, the provided function is executed and the returned key/value pair is added to the event. This may be useful for including dynamic process information such as memory used, number of threads, concurrent requests, and so on to each event. Adding this kind of dynamic data to an event makes it easy to understand the application's context when looking at an individual event or error condition. ## Troubleshooting Refer to [Common Issues with Sending Data in Honeycomb](/troubleshoot/common-issues/sending-data/#libhoney) for Libhoney. ## Contributions Features, bug fixes and other changes to `libhoney` are gladly accepted. Please open issues or a pull request with your change. All contributions will be released under the Apache License 2.0. # Send Data with the OpenTelemetry JavaScript SDK Source: https://docs.honeycomb.io/send-data/javascript-nodejs/opentelemetry-sdk Instrument your Node.js application with the OpenTelemetry JavaScript SDK and send traces, logs, and metrics to Honeycomb. Use the OpenTelemetry JavaScript SDK to instrument Node.js applications in a standard, vendor-agnostic, and future-proof way and send telemetry data to Honeycomb. In this guide, we will walk you through instrumenting with OpenTelemetry for JavaScript, which will include adding automatic instrumentation to your application. For more structured learning, check out the [Instrumentation for OpenTelemetry JavaScript](https://academy.honeycomb.io/app/courses/2ee2544e-866c-4251-90b5-bd17f6e59494) course from Honeycomb Academy. ## Before You Begin Before you can set up automatic instrumentation for your Node.js application, you will need to do a few things. ### Prepare Your Development Environment To complete the required steps, you will need: * A working Node.js environment * An application written in Node.js ### Get Your Honeycomb API Key To send data to Honeycomb, you'll need to [sign up for a free Honeycomb account](https://ui.honeycomb.io/signup) and [create a Honeycomb Ingest API Key](/configure/environments/manage-api-keys/#create-api-key). To get started, you can create a key that you expect to swap out when you deploy to production. Name it something helpful, perhaps noting that it's a getting started key. Make note of your API key; for security reasons, you will not be able to see the key again, and you will need it later! For setup, make sure you check the "Can create datasets" checkbox so that your data will show up in Honeycomb. Later, when you replace this key with a permanent one, you can uncheck that box. If you want to use an API key you previously stored in a secure location, you can also [look up details for Honeycomb API Keys](/configure/environments/manage-api-keys/#find-api-keys) any time in your Environment Settings, and use them to retrieve keys from your storage location. ## Add Automatic Instrumentation Automatic instrumentation is enabled by adding [instrumentation packages](https://github.com/open-telemetry/opentelemetry-js#instrumentations). Add custom, or manual, instrumentation using the OpenTelemetry API. ### Acquire Dependencies Open your terminal, navigate to the location of your project on your drive, and install OpenTelemetry's automatic instrumentation meta package and OpenTelemetry's Node.js SDK package: ```shell theme={} npm install --save \ @opentelemetry/auto-instrumentations-node \ @opentelemetry/sdk-node ``` | Module | Description | | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `auto-instrumentations-node` | OpenTelemetry's meta package that provides a way to add automatic instrumentation to any Node application to capture telemetry data from a number of popular libraries and frameworks, like `express`, `dns`, `http`, and more. | | `sdk-node` | OpenTelemetry's Node.js distribution package that streamlines configuration and allows you to instrument as quickly and easily as possible. | Alternatively, install [individual instrumentation packages](https://github.com/open-telemetry/opentelemetry-js#instrumentations). If using TypeScript, install `ts-node` to run the code: ```shell theme={} npm install --save-dev ts-node ``` Open your terminal, navigate to the location of your project on your drive, and install OpenTelemetry's automatic instrumentation meta package and OpenTelemetry's Node.js SDK package: ```shell theme={} yarn add \ @opentelemetry/auto-instrumentations-node \ @opentelemetry/sdk-node ``` | Module | Description | | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `auto-instrumentations-node` | OpenTelemetry's meta package that provides a way to add automatic instrumentation to any Node application to capture telemetry data from a number of popular libraries and frameworks, like `express`, `dns`, `http`, and more. | | `sdk-node` | OpenTelemetry's Node.js distribution package that streamlines configuration and allows you to instrument as quickly and easily as possible. | Alternatively, install [individual instrumentation packages](https://github.com/open-telemetry/opentelemetry-js#instrumentations). If using TypeScript, install `ts-node` to run the code: ```shell theme={} yarn add --dev ts-node ``` ### Initialize Create an initialization file, commonly known as the `tracing.ts` file: ```typescript theme={} // Example filename: tracing.ts import { startNodeSDK } from '@opentelemetry/sdk-node'; import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node'; startNodeSDK({ instrumentations: [ getNodeAutoInstrumentations(), ], }); ``` Create an initialization file, commonly known as the `tracing.js` file: ```javascript theme={} // Example filename: tracing.js 'use strict'; const { startNodeSDK } = require('@opentelemetry/sdk-node'); const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node'); startNodeSDK({ instrumentations: [ getNodeAutoInstrumentations(), ], }); ``` ### Configure Create an `otelconfig.yaml` file with the following content: ```yaml theme={} file_format: "1.1" resource: attributes: - name: service.name value: ${OTEL_SERVICE_NAME:-my-service} tracer_provider: processors: - batch: exporter: otlp_http: endpoint: https://api.honeycomb.io/v1/traces # Use the endpoint below for EU # endpoint: https://api.eu1.honeycomb.io/v1/traces headers: - name: x-honeycomb-team value: ${HONEYCOMB_API_KEY} propagator: composite: - tracecontext: - baggage: ``` Set the following environment variables before running your application: | Environment Variable | Value | | :------------------- | :----------------------- | | `HONEYCOMB_API_KEY` | Your Honeycomb API key | | `OTEL_SERVICE_NAME` | The name of your service | When `OTEL_CONFIG_FILE` is set, the configuration file is the single source of truth for the SDK. Other `OTEL_*` environment variables are ignored by design, so set all SDK options in the YAML file. You can still reference environment variables from inside the YAML using `${VAR_NAME}` substitution. The OpenTelemetry declarative configuration is stable at the specification level. Individual fields still under active development are marked with a `/development` suffix in the YAML (see [configuration versioning](https://github.com/open-telemetry/opentelemetry-configuration/blob/main/VERSIONING.md#experimental-features)). Check the [language support status](https://github.com/open-telemetry/opentelemetry-configuration/blob/main/language-support-status.md) for per-SDK maturity. Add `meter_provider` and `logger_provider` sections to the same file to export metrics and logs. This version also enables resource detectors, which add attributes such as `host.*` and `process.*` automatically: ```yaml theme={} file_format: "1.1" resource: attributes: - name: service.name value: ${OTEL_SERVICE_NAME:-my-service} detection/development: detectors: - host: - os: - process: - service: - env: tracer_provider: # traces processors: - batch: exporter: otlp_http: endpoint: https://api.honeycomb.io/v1/traces headers: - name: x-honeycomb-team value: ${HONEYCOMB_API_KEY} meter_provider: # metrics readers: - periodic: exporter: otlp_http: endpoint: https://api.honeycomb.io/v1/metrics headers: - name: x-honeycomb-team value: ${HONEYCOMB_API_KEY} # Legacy metrics only; omit with the current metrics experience: # - name: x-honeycomb-dataset # value: ${HONEYCOMB_METRICS_DATASET} logger_provider: # logs processors: - batch: exporter: otlp_http: endpoint: https://api.honeycomb.io/v1/logs headers: - name: x-honeycomb-team value: ${HONEYCOMB_API_KEY} propagator: composite: - tracecontext: - baggage: ``` For the EU instance, replace `https://api.honeycomb.io` with `https://api.eu1.honeycomb.io` throughout the file. If you use [Honeycomb Classic](/troubleshoot/product-lifecycle/recommended-migrations/#migrate-from-honeycomb-classic-to-honeycomb-environments), you must also specify the Dataset for traces using the `x-honeycomb-dataset` header: ```yaml theme={} headers: - name: x-honeycomb-team value: ${HONEYCOMB_API_KEY} - name: x-honeycomb-dataset value: your-dataset ``` If you are sending data directly to Honeycomb, you must configure the API key and service name. If you are using an [OpenTelemetry Collector](/send-data/opentelemetry/collector/), configure your API key at the Collector level instead. ### Run Point the SDK at your configuration file using the `OTEL_CONFIG_FILE` environment variable, then run the Node.js app with the initialization file: ```shell theme={} OTEL_CONFIG_FILE=./otelconfig.yaml ts-node -r ./tracing.ts YOUR_APPLICATION_NAME.ts ``` Be sure to replace `YOUR_APPLICATION_NAME` with the name of your application's main file. Alternatively, you can import the initialization file as the first step in your application lifecycle. In Honeycomb's UI, you should now see your application's incoming requests and outgoing HTTP calls generate traces. Point the SDK at your configuration file using the `OTEL_CONFIG_FILE` environment variable, then run the Node.js app with the initialization file: ```shell theme={} OTEL_CONFIG_FILE=./otelconfig.yaml node -r ./tracing.js YOUR_APPLICATION_NAME.js ``` Be sure to replace `YOUR_APPLICATION_NAME` with the name of your application's main file. Alternatively, you can import the initialization file as the first step in your application lifecycle. In Honeycomb's UI, you should now see your application's incoming requests and outgoing HTTP calls generate traces. ## Add Custom Instrumentation Automatic instrumentation is the easiest way to get started with instrumenting your code. To get additional insight into your system, you should also add custom, or manual, instrumentation where appropriate. Follow the instructions below to add custom instrumentation to your code. To learn more about custom, or manual, instrumentation, visit the comprehensive set of topics covered by [Manual Instrumentation for JavaScript](https://opentelemetry.io/docs/languages/js/instrumentation/) in OpenTelemetry's documentation. ### Acquire Dependencies To start adding custom instrumentation, ensure that the OpenTelemetry API package exists as a direct dependency in your project. This package provides access to the high-level instrumentation APIs, which gives the ability to retrieve the current span to enrich with additional attributes, to create new spans, and to generate metrics. ```shell npm theme={} npm install --save @opentelemetry/api ``` ```shell yarn theme={} yarn add @opentelemetry/api ``` ### Add Attributes to Spans Adding attributes to a currently executing span in a trace can be useful. For example, you may have an application or service that handles users, and you want to associate the user with the span when querying your service in Honeycomb. To do this, get the current span from the context and set an attribute with the user ID: ```typescript TypeScript theme={} import { trace } from '@opentelemetry/api'; function handleUser(user) { let activeSpan = trace.getActiveSpan(); activeSpan.setAttribute("user.id", user.getId()); } ``` ```javascript JavaScript theme={} const { trace } = require("@opentelemetry/api"); function handleUser(user) { let activeSpan = trace.getActiveSpan(); activeSpan.setAttribute("user.id", user.getId()); } ``` This will add a `user.id` field to the current span, so you can use the field in `WHERE`, `GROUP BY` or `ORDER` clauses in the Honeycomb query builder. ### Initialize a Tracer To create spans, you need to initialize a `Tracer`. ```typescript TypeScript theme={} import { trace } from '@opentelemetry/api'; const tracer = trace.getTracer("tracer.name.here"); ``` ```js JavaScript theme={} const { trace } = require("@opentelemetry/api"); const tracer = trace.getTracer("tracer.name.here"); ``` When you create a `Tracer`, OpenTelemetry requires you to give it a name as a string. This string is the only required parameter. When traces are sent to Honeycomb, the name of the `Tracer` is turned into the `library.name` field, which can be used to show all spans created from a particular tracer. In general, pick a name that matches the appropriate scope for your traces. If you have one tracer for each service, then use the service name. If you have multiple tracers that live in different "layers" of your application, then use the name that corresponds to that "layer". The `library.name` field is also used with traces created from instrumentation libraries. You can then use this tracer to create custom spans. ### Create New Spans Automatic instrumentation can show the shape of requests to your system, but only you know the truly important parts. To get the full picture of what is happening, you must add custom, or manual, instrumentation and create some custom spans. To do this, grab the tracer from the OpenTelemetry API: ```typescript TypeScript theme={} import { trace } from '@opentelemetry/api'; const tracer = trace.getTracer("my-service-tracer"); function runQuery() { tracer.startActiveSpan("expensive-query", (span) => { // ... do cool stuff span.end(); }); } ``` ```javascript JavaScript theme={} const { trace } = require("@opentelemetry/api"); const tracer = trace.getTracer("my-service-tracer"); function runQuery() { tracer.startActiveSpan("expensive-query", (span) => { // ... do cool stuff span.end(); }); } ``` ### Add Multi-Span Attributes Sometimes you want to add the same attribute to many spans within the same trace. This attribute may include variables calculated during your program, or other useful values for correlation or debugging purposes. To add this attribute to multiple spans, leverage the OpenTelemetry concept of [baggage](https://opentelemetry.io/docs/concepts/signals/baggage/). Baggage allows you to add a `key` with a `value` as an attribute to every subsequent child span within the current application context. 1. Install the baggage span processor package using your terminal: ```shell theme={} npm install --save @opentelemetry/baggage-span-processor ``` 2. When configuring the OpenTelemetry SDK tracer provider, add the `BaggageSpanProcessor`: ```javascript theme={} import { BaggageSpanProcessor } from "@opentelemetry/baggage-span-processor"; const sdk = new NodeSDK({ // ... processors: [ new BaggageSpanProcessor() ] }); ``` 3. Add a baggage entry for the current trace and replace `key` and `value` with your desired key-value pair: ```typescript TypeScript theme={} import { Context, context, propagation, } from '@opentelemetry/api'; tracer.startActiveSpan('main', (span) => { span.setAttribute('key', 'value'); // add to current span // new context based on current, with key/values added to baggage const ctx: Context = propagation.setBaggage( context.active(), propagation.createBaggage({ 'key': { value: 'value' } }) ); // within the new context, do some work and baggage will be // applied as attributes on child spans context.with(ctx, () => { tracer.startActiveSpan('childSpan', (childSpan) => { doTheWork(); childSpan.end(); }); }); span.end(); }); ``` ```javascript JavaScript theme={} tracer.startActiveSpan('main', (span) => { span.setAttribute('key', 'value'); // add to current span // new context based on current, with key/values added to baggage const ctx = propagation.setBaggage( context.active(), propagation.createBaggage({ 'key': { value: 'value' } }) ); // within the new context, do some work and baggage will be // applied as attributes on child spans context.with(ctx, () => { tracer.startActiveSpan('childSpan', (childSpan) => { doTheWork(); childSpan.end(); }); }); span.end(); }); ``` Any Baggage attributes that you set in your application will be attached to outgoing network requests as a header. If your service communicates to a third party API, do **NOT** put sensitive information in the Baggage attributes. ## Sampling You can configure the OpenTelemetry SDK to [sample the data](/manage-data-volume/sample/guidelines/) it generates. Honeycomb [weights sampled data based on sample rate](/manage-data-volume/sample/sampled-data-in-honeycomb/), so you must set a resource attribute containing the sample rate. Use a [`TraceIdRatioBased` sampler](https://opentelemetry.io//docs/specs/otel/trace/sdk/#traceidratiobased), with a ratio expressed as `1/N`. Then, also create a resource attribute called `SampleRate` with the value of `N`. This allows Honeycomb to reweigh scalar values, like counts, so that they are accurate even with sampled data. In the example below, our goal is to keep approximately half (1/2) of the data volume. The resource attribute contains the denominator (2), while the OpenTelemetry sampler argument contains the decimal value (0.5). To get access to a sampler, install the core OpenTelemetry package: ```shell theme={} npm install --save @opentelemetry/core ``` Import the `TraceIdRatioBasedSampler`, and add as a sampler to the `NodeSDK` along with the `SampleRate` in the `Resource`. ```javascript theme={} // tracing.js const { TraceIdRatioBasedSampler } = require("@opentelemetry/sdk-trace-node"); const sdk = new NodeSDK({ resource: new Resource({ [SemanticResourceAttributes.SERVICE_NAME]: "", SampleRate: 2, }), traceExporter, instrumentations: [getNodeAutoInstrumentations()], sampler: new TraceIdRatioBasedSampler(0.5), }); ``` ## Choosing between gRPC and HTTP Most OpenTelemetry SDKs have an option to export telemetry as OTLP either over gRPC or HTTP/protobuf, with some also offering HTTP/JSON. If you are trying to choose between gRPC and HTTP, keep in mind: * Some SDKs default to using gRPC, and it may be easiest to start with the default option. * Some firewall policies are not set up to handle gRPC and require using HTTP. * gRPC may improve performance, but its long-lived connections may cause problems with load balancing, especially when using Refinery. gRPC default export uses port 4317, whereas HTTP default export uses port 4318. ## Endpoint URLs for OTLP/HTTP When using the `OTEL_EXPORTER_OTLP_ENDPOINT` environment variable with an SDK and an HTTP exporter, the final path of the endpoint is modified by the SDK to represent the specific signal being sent. For example, when exporting trace data, the endpoint is updated to append `v1/traces`. When exporting metrics data, the endpoint is updated to append `v1/metrics`. So, if you were to set the `OTEL_EXPORTER_OTLP_ENDPOINT` to `https://api.honeycomb.io`, traces would be sent to `https://api.honeycomb.io/v1/traces` and metrics would be sent to `https://api.honeycomb.io/v1/metrics`. The same modification is not necessary for gRPC. ```shell theme={} export OTEL_EXPORTER_OTLP_ENDPOINT=https://api.honeycomb.io # US instance #export OTEL_EXPORTER_OTLP_ENDPOINT=https://api.eu1.honeycomb.io # EU instance ``` If the desired outcome is to send data to a different endpoint depending on the signal, use `OTEL_EXPORTER_OTLP__ENDPOINT` instead of the more generic `OTEL_EXPORTER_OTLP_ENDPOINT`. When using a signal-specific environment variable, these paths must be appended manually. Set `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT` for traces, appending the endpoint with `v1/traces`, and `OTEL_EXPORTER_OTLP_METRICS_ENDPOINT` for metrics, appending the endpoint with `v1/metrics`. Send both traces and metrics to Honeycomb using this method by setting the following variables: ```shell theme={} export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://api.honeycomb.io/v1/traces # US instance #export OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=https://api.eu1.honeycomb.io/v1/traces # EU instance export OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=https://api.honeycomb.io/v1/metrics # US instance #export OTEL_EXPORTER_OTLP_METRICS_ENDPOINT=https://api.eu1.honeycomb.io/v1/metrics # EU instance ``` More details about endpoints and signals can be found in the [OpenTelemetry Specification](https://github.com/open-telemetry/opentelemetry-specification/blob/main/specification/protocol/exporter.md). To configure the endpoint URL and API key in code instead of with environment variables, specify `/v1/traces` like so: ```javascript theme={} // Configure OTLPTraceExporter const traceExporter = new OTLPTraceExporter({ url: "https://api.honeycomb.io/v1/traces", // US instance //url: "https://api.eu1.honeycomb.io/v1/traces", // EU instance headers: { "x-honeycomb-team": 'your-api-key', }, }); ``` ## Troubleshooting To explore common issues when sending data, visit [Common Issues with Sending Data in Honeycomb](/troubleshoot/common-issues/sending-data/#opentelemetry-sdks-and-honeycomb-distributions). # Send Data from Kubernetes Source: https://docs.honeycomb.io/send-data/kubernetes Instrument your Kubernetes cluster with OpenTelemetry and send traces, logs, and metrics to Honeycomb to monitor workload performance and health. Use OpenTelemetry to collect Kubernetes resource and status metrics from nodes, pods, containers, and volumes. This data answers questions like: * Which pods are using the most CPU? * How do resource limits compare to container resource use? * What do system metrics look like at the node level? * Why are pods failing to start? Adding telemetry to Kubernetes and then analyzing with Honeycomb provides a flexible way to aggregate, structure, and enrich events from applications running on Kubernetes. This data answers questions like: * How did response time change after a canary deployment? * How does application performance vary with container resource limits? * Are application errors happening on specific nodes, or across the fleet? ## Getting Started: Create Your Telemetry Pipeline Do you have 10 minutes? Then you've come to the right place. Use our Quick Start to create a telemetry pipeline, which will prepare you to instrument your application code. Use Helm to deploy OpenTelemetry Collectors that set up a telemetry pipeline to send Kubernetes metrics and events from your cluster to Honeycomb. ## Add Low-Code Automatic Instrumentation to Your Applications Once you have a telemetry pipeline in place, add automatic instrumentation to your applications. If you have already used OpenTelemetry to instrument your applications to send data to Honeycomb, you can skip this step and jump straight to [configuring OpenTelemetry to forward telemetry data to your Collectors](/send-data/kubernetes/opentelemetry/collect-instrumented-code/). Set up the OpenTelemetry Operator for Kubernetes to add automatic instrumentation to your applications--using very little code. ## Getting Help To ask questions and learn more, join our [Pollinators Community Slack](/troubleshoot/community/#join-pollinators-community-slack). # Add Automatic Instrumentation (Low Code) Source: https://docs.honeycomb.io/send-data/kubernetes/opentelemetry/add-automatic-instrumentation Install the OpenTelemetry Operator for Kubernetes to automatically inject instrumentation into your deployed applications with minimal code changes. Once you have a telemetry pipeline in place, you can gather metrics, logs, and traces from your deployed applications by adding automatic instrumentation to your applications. You can do this with very little code by installing the [OpenTelemetry Operator for Kubernetes](https://opentelemetry.io/docs/kubernetes/operator/) in your cluster. Once installed, the Operator will monitor when pods are created and check whether it should sideload automatic instrumentation packages. We consider this approach to be "low-code" because it requires you to access and modify the Kubernetes deployment manifests for your application. This approach also pushes automatic instrumentation into your code base as the application starts, so that trace data can be gathered. Although this is a very minimal amount of change overall and does not require you to directly modify any application code, we differentiate this from "no-code" because it does require that you modify how your applications are deployed on Kubernetes. Supported languages include: * .NET * Java * Node.js * Python * Go ## Before You Begin Before beginning this guide, you should have: * Created a running Kubernetes cluster. * Created a namespace named `honeycomb`. * [Deployed an OpenTelemetry Collector in DaemonSet mode, listening on the Node IP](/send-data/kubernetes/opentelemetry/create-telemetry-pipeline/). ## Step 1: Install the Operator Install the OpenTelemetry Operator Pods into your cluster using a Helm chart: ```shell theme={} helm install \ --set admissionWebhooks.certManager.enabled=false \ --set admissionWebhooks.autoGenerateCert.enabled=true \ --set manager.collectorImage.repository="ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector-k8s" \ --namespace honeycomb \ --create-namespace \ opentelemetry-operator open-telemetry/opentelemetry-operator ``` In this example, we want the Operator to add automatic instrumentation to a Go application, so we must include the `manager.featureGates` configuration line to the command. If you are working with a different programming language, you can omit this line. In this example, we use an automatically generated self-signed certificate by setting `admissionWebhooks.certManager.enabled` to `false` and `admissionWebhooks.autoGenerateCert.enabled` to `true`. We do not recommend that you use this configuration in a production environment, but setting up a [cert-manager](https://cert-manager.io/docs/) is outside the scope of this document. ## Step 2: Verify the Operator Installation Check that the Operator is installed by using the `kubectl` command to see if the pod is running: ```shell theme={} kubectl get pods --namespace honeycomb ``` This command should return something like: ```pre theme={} NAME READY STATUS RESTARTS AGE opentelemetry-operator-567bc4ff75-p287g 2/2 Running 0 21s ``` The result should contain one pod, with two containers, running under a name containing the prefix `opentelemetry-operator`. After verifying that the pod is running correctly, you can monitor the work the operator does by tailing the logs with the `kubectl` command: ```shell theme={} kubectl logs -n honeycomb -f opentelemetry-operator-567bc4ff75-p287g ``` This command should return something like: ```pre theme={} {"level":"info","ts":"2023-09-22T15:21:27Z","msg":"Starting Controller","controller":"opentelemetrycollector","controllerGroup":"opentelemetry.io","controllerKind":"OpenTelemetryCollector"} {"level":"info","ts":"2023-09-22T15:21:27Z","logger":"instrumentation-resource","msg":"default","name":"otel-autoinstrumentation"} {"level":"info","ts":"2023-09-22T15:21:27Z","logger":"collector-upgrade","msg":"no instances to upgrade"} {"level":"info","ts":"2023-09-22T15:21:27Z","logger":"instrumentation-resource","msg":"validate update","name":"otel-autoinstrumentation"} {"level":"info","ts":"2023-09-22T15:21:27Z","msg":"Starting workers","controller":"opentelemetrycollector","controllerGroup":"opentelemetry.io","controllerKind":"OpenTelemetryCollector","worker count":1} {"level":"info","ts":"2023-09-22T15:34:24Z","logger":"instrumentation-resource","msg":"default","name":"otel-autoinstrumentation"} {"level":"info","ts":"2023-09-22T15:34:24Z","logger":"instrumentation-resource","msg":"validate update","name":"otel-autoinstrumentation"} ``` ## Step 3: Configure Automatic Instrumentation Deploy an Instrumentation manifest to your Kubernetes cluster, which will enable the OpenTelemetry Operator to automatically instrument your services: ```shell theme={} kubectl apply --namespace honeycomb -f https://docs.honeycomb.io/_assets/code-samples/kubernetes/values-files/otel-autoinstrumentation.yaml ``` [Download](/_assets/code-samples/kubernetes/values-files/otel-autoinstrumentation.yaml) ```yaml theme={} apiVersion: opentelemetry.io/v1alpha1 kind: Instrumentation metadata: name: otel-autoinstrumentation spec: exporter: endpoint: http://$(OTEL_NODE_IP):4317 propagators: - tracecontext - baggage - b3 sampler: type: parentbased_traceidratio argument: "1" python: env: # Required if endpoint is set to 4317. # Python autoinstrumentation uses http/proto by default # so data must be sent to 4318 instead of 4317. - name: OTEL_EXPORTER_OTLP_ENDPOINT value: http://$(OTEL_NODE_IP):4318 dotnet: env: # Required if endpoint is set to 4317. # Dotnet autoinstrumentation uses http/proto by default # See https://github.com/open-telemetry/opentelemetry-dotnet-instrumentation/blob/888e2cd216c77d12e56b54ee91dafbc4e7452a52/docs/config.md\#otlp - name: OTEL_EXPORTER_OTLP_ENDPOINT value: http://$(OTEL_NODE_IP):4318 java: image: ghcr.io/open-telemetry/opentelemetry-operator/autoinstrumentation-java:2.10.0 env: # Required if endpoint is set to 4317. # Java autoinstrumentation agent v2.0+ uses http/proto by default # See https://github.com/open-telemetry/opentelemetry-java-instrumentation/blob/9bbfe7fe4e3f65cb698d6d2320ac87372d5d572f/javaagent-tooling/src/main/java/io/opentelemetry/javaagent/tooling/config/OtlpProtocolPropertiesSupplier.java#L19 - name: OTEL_EXPORTER_OTLP_ENDPOINT value: http://$(OTEL_NODE_IP):4318 nodejs: env: # Optional. # We recommend disabling fs automatic instrumentation because # it can be noisy and expensive during startup - name: OTEL_NODE_DISABLED_INSTRUMENTATIONS value: fs ``` This manifest instructs the Operator to perform the following actions whenever you add annotations to your pods: * Inject instrumentation into your applications * Configure the export to send data to the node's IP address ## Step 4: Add Annotations to Your Application's Kubernetes Manifest In the deployment manifest for your application, add the required annotations. These will vary according to programming language. For example, our Go application requires the following annotations. Note where the annotations are located in the manifest: ```yaml theme={} apiVersion: apps/v1 kind: Deployment metadata: name: my-go-app spec: replicas: 1 template: metadata: labels: app: my-go-app annotations: # Added Annotations for auto-instrumentation go here - points at the namespace where the instrumentation # manifest is installed and the name of meta.name field in the instrumentation manifest instrumentation.opentelemetry.io/inject-go: "honeycomb/otel-autoinstrumentation" # Go Requires an additional annotation to the path of the binary on the container instrumentation.opentelemetry.io/otel-go-auto-target-exe: "/path/to/my-go-app" spec: serviceAccountName: my-go-app ``` Each supported programming language requires different annotations: ```yaml theme={} annotations: instrumentation.opentelemetry.io/inject-dotnet: "honeycomb/otel-autoinstrumentation" ``` ```yaml theme={} annotations: instrumentation.opentelemetry.io/inject-java: "honeycomb/otel-autoinstrumentation" ``` ```yaml theme={} annotations: instrumentation.opentelemetry.io/inject-nodejs: "honeycomb/otel-autoinstrumentation" ``` ```yaml theme={} annotations: instrumentation.opentelemetry.io/inject-python: "honeycomb/otel-autoinstrumentation" ``` Go requires an extra annotation that tells the Operator where to find the Go binary of your application on the container. ```yaml theme={} annotations: instrumentation.opentelemetry.io/inject-go: "honeycomb/otel-autoinstrumentation" instrumentation.opentelemetry.io/otel-go-auto-target-exe: "/app/frontend-service" ``` Possible values for the annotation include: * `"true"` - inject an `Instrumentation` Kubernetes Custom Resource (CR) instance from the current namespace * `"my-instrumentation"` - inject a specific `Instrumentation` CR instance from the current namespace * `"my-other-namespace/my-instrumentation"` - inject a specific `Instrumentation` CR instance from another namespace * `"false"` - do not inject an `Instrumentation` CR instance ## Explore Your Data In Honeycomb The next time requests are made to your application, data should start flowing to Honeycomb. Once your applications are sending data, you can [explore trace data](/investigate/) and gain insights from the Kubernetes attributes that have been attached by the [Kubernetes Attributes Processor](/send-data/kubernetes/opentelemetry/components/#kubernetes-attributes-processor) in your Collector. If several requests have been made to your application and after several minutes, you still do not see any data, reach out for help in our [Pollinators Community Slack](/troubleshoot/community/#join-pollinators-community-slack). Pro/Enterprise users can [visit Honeycomb Support](https://support.honeycomb.io/) or [email support@honeycomb.io](mailto:support@honeycomb.io). ## Additional Resources * [Operator documentation on opentelemetry.io](https://opentelemetry.io/docs/kubernetes/operator/) * [OpenTelemetry Operator README in GitHub](https://github.com/open-telemetry/opentelemetry-operator/blob/main/README.md) # Send Data from Instrumented Code to Collectors Source: https://docs.honeycomb.io/send-data/kubernetes/opentelemetry/collect-instrumented-code Configure your OpenTelemetry-instrumented applications to export telemetry to the Collectors running in your Kubernetes cluster. If you're already using OpenTelemetry, or you've decided to instrument your code with OpenTelemetry's SDKs, you need to tell the SDKs where to send the telemetry data. ## Before You Begin Before beginning this guide, you should have: * Created a running Kubernetes cluster. * Deployed some applications to your cluster and instrumented them with OpenTelemetry. * [Deployed an OpenTelemetry Collector in DaemonSet mode, listening on the Node IP](/send-data/kubernetes/opentelemetry/create-telemetry-pipeline/#step-4-deploy-collectors). ## Forward Data from Your Application Code to the Collectors Now that you have a telemetry pipeline in your cluster, you must configure the SDKs to forward the telemetry data to your Collectors. To do this, you will use the [Kubernetes Downward API](https://kubernetes.io/docs/concepts/workloads/pods/downward-api/), which allows you to pass information about the wider context of your Kubernetes environment into your deployments and therefore your pods. For example, you can use the Downward API to add environment variables that can store pieces of metadata, like the Cluster name. In our Kubernetes Quick Start, you deployed a DaemonSet-mode Collector listening on the IP address of the node, which is where your SDK must send telemetry data. 1. Using the Downward API, create an environment variable and pass in the node's IP address: ```yaml theme={} env: - name: NODE_IP valueFrom: fieldRef: fieldPath: status.hostIP ``` 2. Configure the node's environment variable name and value. In this example, we use .NET's standard environment variable, which is named `OTEL_EXPORTER_OTLP_ENDPOINT`, and set it to the value of the node's IP address. ```yaml theme={} env: - name: NODE_IP valueFrom: fieldRef: fieldPath: status.hostIP - name: OTEL_EXPORTER_OTLP_ENDPOINT value: http://$(NODE_IP):4317 ``` For a list of OTLP exporter configuration options, visit [OpenTelemetry's Protocol Exporter](https://opentelemetry.io/docs/specs/otel/protocol/exporter/). After a few minutes, data should start flowing through your observability pipeline and into Honeycomb. # OpenTelemetry's Kubernetes Components Source: https://docs.honeycomb.io/send-data/kubernetes/opentelemetry/components Reference the OpenTelemetry Collector components used to gather data from Kubernetes, including receivers, processors, and exporters for cluster telemetry. With Honeycomb and OpenTelemetry, you can analyze and query data across not only your applications, but also your entire Kubernetes cluster. The following components available in the OpenTelemetry Collector will allow you to gather the best data from your Kubernetes cluster and applications to be analyzed in Honeycomb. ## Kubernetes Attributes Processor OpenTelemetry's [Kubernetes Attributes Processor](https://opentelemetry.io/docs/kubernetes/collector/components/#kubernetes-attributes-processor) automatically discovers Kubernetes pods, extracts their metadata (for example, pod name or node name), and adds the extracted metadata to spans, metrics, and logs as resource attributes. Because the Kubernetes Attributes Processor adds Kubernetes context to your telemetry, you can correlate your application's traces, metrics, and logs with your Kubernetes telemetry, such as pod metrics and events. We highly recommend that you include this processor in any Collector that receives telemetry from Kubernetes pods. ## Kubeletstats Receiver OpenTelemetry's [Kubeletstats Receiver](https://opentelemetry.io/docs/kubernetes/collector/components/#kubeletstats-receiver) gathers metrics about the Kubernetes node and its workloads. This receiver can gather metrics like container memory usage, pod cpu usage, and node network errors. All of the gathered telemetry includes Kubernetes metadata, such as pod name or node name. When you use the Kubeletstats Receiver with the Kubernetes Attributes Processor to enhance your application telemetry, you can correlate your application traces, metrics, and logs with the metrics produced by the Kubeletstats Receiver. ## Kubernetes Cluster Receiver OpenTelemetry Collectors use the [Kubernetes Cluster Receiver](https://opentelemetry.io/docs/kubernetes/collector/components/#kubernetes-cluster-receiver) to collect metrics about the state of the cluster as a whole. This receiver can gather metrics about node conditions, pod phases, container restarts, available and desired deployments, and more. Since the receiver gathers telemetry for the cluster as a whole, only one instance of the receiver is needed across the cluster in order to collect all the data. ## Kubernetes Objects Receiver OpenTelemetry's [Kubernetes Objects Receiver](https://opentelemetry.io/docs/kubernetes/collector/components/#kubernetes-objects-receiver) collects objects from the Kubernetes API server. Because the receiver gathers telemetry for the cluster as a whole, only one instance of the receiver is needed across the cluster in order to collect all the data. Most commonly, this receiver is used to watch Kubernetes Events. To learn more about using the Kubernetes Objects Receiver to send Kubernetes Events to Honeycomb, visit [Kubernetes Events with the OpenTelemetry Collector](/send-data/kubernetes/send-events-objects-receiver/). ## OpenTelemetry Filelog Receiver OpenTelemetry's [Filelog Receiver](https://opentelemetry.io/docs/kubernetes/collector/components/#filelog-receiver) tails and parses logs from files. Although the Filelog Receiver is not Kubernetes specific, we recommend it as the primary solution for collecting any logs from Kubernetes. The Filelog Receiver processes logs through a series of operators that are chained together, each of which performs a simple responsibility, such as parsing JSON. Configuring a Filelog Receiver can be complicated. The easiest way to get started is to use the OpenTelemetry Collector Helm chart with the `logsCollection` preset. ## OpenTelemetry Marker Exporter The OpenTelemetry Collector's [Marker Exporter](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/exporter/honeycombmarkerexporter) allows you to send a [Honeycomb Marker](/configure/environments/manage-markers/) based on the shape of incoming telemetry. In your OpenTelemetry Collector exporter configuration, you can specify a set of rules that will be evaluated against incoming telemetry. When a condition is met, a marker is sent and appears in Honeycomb. For example, whenever a Kubernetes Event contains a `reason` of `Backoff`, the configuration below sends a marker: ```yaml theme={} exporters: honeycombmarker: api_key: YOUR-API-KEY-HERE markers: # Creates a new marker each time the exporter sees a Kubernetes event with a reason of Backoff - type: k8s-backoff-events rules: - log_conditions: - IsMap(body) and IsMap(body["object"]) and body["object"]["reason"] == "Backoff" ``` # Create a Telemetry Pipeline Source: https://docs.honeycomb.io/send-data/kubernetes/opentelemetry/create-telemetry-pipeline Set up an OpenTelemetry Collector pipeline for your Kubernetes cluster and start sending traces, logs, and metrics to Honeycomb in under 10 minutes. Whether you want to maximize Honeycomb's capabilities or begin with a more limited set of telemetry data for your Kubernetes applications, we recommend that you use [OpenTelemetry](https://opentelemetry.io/), a highly configurable, open-source, and vendor-neutral instrumentation framework. In this guide, you will learn how to get answers about how your applications on Kubernetes are performing in production using OpenTelemetry Collectors and Honeycomb--and you'll do it in under 10 minutes. When you finish, you'll have visibility into in-depth Kubernetes data, including Kubernetes logs, events, and node/cluster metrics. And you'll be given the opportunity to take the next step toward leveraging Honeycomb's full potential by instrumenting your code. ## Overview In the next 10 minutes, you will create a series of OpenTelemetry Collectors that will work together to pull in the correct telemetry and apply Kubernetes-specific data to it, which will help correlate issues. Your implementation will also lay the foundation for your applications to send telemetry data, if you choose to instrument them. Collectors Overview 1. Each node will contain a Collector, which will use the node's Kubelet API to gather metrics data about the node and the node's pod resources. 2. The entire cluster will contain a separate Collector, which will use the Kubernetes API to get details about Kubernetes Events, such as active deployments. 3. Applications will be able to use the node's IP address to send telemetry data (logs, metrics, and traces) to the Collector that is local to the node, if you instrument them. 4. Each Collector will send telemetry data directly to Honeycomb over gRPC. ## Collected Data When you finish, you will have access to: * Default [metrics provided by Kubelet Stats](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/receiver/kubeletstatsreceiver/documentation.md) for nodes and pods, plus the optional `uptime`, `*_request_utilization`, and `*_limit_utilization` metrics * Default [Kubernetes Cluster metrics](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/receiver/k8sclusterreceiver/documentation.md) * All Kubernetes events from the cluster * Additional Kubernetes metadata, plus all the pod's labels and annotations as resource attributes whenever possible, including: * `k8s.namespace.name` * `k8s.deployment.name` * `k8s.statefulset.name` * `k8s.daemonset.name` * `k8s.cronjob.name` * `k8s.job.name` * `k8s.node.name` * `k8s.pod.name` * `k8s.pod.uid` * `k8s.pod.start_time` ## Before You Begin Before beginning this guide, you should have: * Created a running Kubernetes cluster. * Installed the `kubectl` command-line utility locally. * Installed [Helm 3.9+](https://helm.sh/) locally. * Deployed some applications to Kubernetes. You'll also need your Honeycomb API Key. You can [find your Honeycomb API Key](/configure/environments/manage-api-keys/#find-api-keys) in your Environment Settings. Let's get started! ## Step 1: Create a Namespace To help you manage your objects in the cluster, create a namespace to contain the collector infrastructure. In this example, we call the namespace `honeycomb`. ```shell theme={} kubectl create namespace honeycomb ``` ## Step 2: Configure Kubernetes with Your Honeycomb API Key Within your new namespace, create a Kubernetes Secret that contains your Honeycomb API Key. You can [find your Honeycomb API Key](/configure/environments/manage-api-keys/#find-api-keys) in your environment in Honeycomb. ```shell theme={} export HONEYCOMB_API_KEY=mykey kubectl create secret generic honeycomb --from-literal=api-key=$HONEYCOMB_API_KEY --namespace=honeycomb ``` ## Step 3: Add OpenTelemetry's Helm Repository [OpenTelemetry's Helm GitHub repository](https://github.com/open-telemetry/opentelemetry-helm-charts) includes Helm charts with all of the resources you need to deploy Collectors to your Kubernetes cluster. 1. Add the repo: ```shell theme={} helm repo add open-telemetry https://open-telemetry.github.io/opentelemetry-helm-charts ``` 2. Update your repos to ensure Helm is aware of the latest versions: ```shell theme={} helm repo update ``` ## Step 4: Deploy Collectors Deploy your Collectors: * A Deployment-mode Collector to collect your cluster metrics. * A DaemonSet-mode Collector to collect application telemetry data and metrics from your cluster's node(s). You can deploy both Collectors using the same Helm chart, but with different names and values files. Deploy the Deployment-mode Collector: ```shell theme={} helm install otel-collector-cluster open-telemetry/opentelemetry-collector --namespace honeycomb --values https://docs.honeycomb.io/_assets/code-samples/kubernetes/values-files/values-deployment.yaml ``` [Download](/_assets/code-samples/kubernetes/values-files/values-deployment.yaml) ```yaml theme={} mode: deployment image: repository: ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector-k8s extraEnvs: - name: HONEYCOMB_API_KEY valueFrom: secretKeyRef: name: honeycomb key: api-key # We only want one of these collectors - any more and we'd produce duplicate data replicaCount: 1 presets: # enables the k8sclusterreceiver and adds it to the metrics pipelines clusterMetrics: enabled: true # enables the k8sobjectsreceiver to collect events only and adds it to the logs pipelines kubernetesEvents: enabled: true config: receivers: k8s_cluster: collection_interval: 30s metrics: # Disable replicaset metrics by default. These are typically high volume, low signal metrics. # If volume is not a concern, then the following blocks can be removed. k8s.replicaset.desired: enabled: false k8s.replicaset.available: enabled: false jaeger: null zipkin: null processors: transform/events: error_mode: ignore log_statements: - context: log statements: # adds a new watch-type attribute from the body if it exists - set(attributes["watch-type"], body["type"]) where IsMap(body) and body["type"] != nil # create new attributes from the body if the body is an object - merge_maps(attributes, body, "upsert") where IsMap(body) and body["object"] == nil - merge_maps(attributes, body["object"], "upsert") where IsMap(body) and body["object"] != nil # Transform the attributes so that the log events use the k8s.* semantic conventions - merge_maps(attributes, attributes[ "metadata"], "upsert") where IsMap(attributes[ "metadata"]) - set(attributes["k8s.pod.name"], attributes["regarding"]["name"]) where attributes["regarding"]["kind"] == "Pod" - set(attributes["k8s.node.name"], attributes["regarding"]["name"]) where attributes["regarding"]["kind"] == "Node" - set(attributes["k8s.job.name"], attributes["regarding"]["name"]) where attributes["regarding"]["kind"] == "Job" - set(attributes["k8s.cronjob.name"], attributes["regarding"]["name"]) where attributes["regarding"]["kind"] == "CronJob" - set(attributes["k8s.namespace.name"], attributes["regarding"]["namespace"]) where attributes["regarding"]["kind"] == "Pod" or attributes["regarding"]["kind"] == "Job" or attributes["regarding"]["kind"] == "CronJob" # Transform the type attribtes into OpenTelemetry Severity types. - set(severity_text, attributes["type"]) where attributes["type"] == "Normal" or attributes["type"] == "Warning" - set(severity_number, SEVERITY_NUMBER_INFO) where attributes["type"] == "Normal" - set(severity_number, SEVERITY_NUMBER_WARN) where attributes["type"] == "Warning" exporters: otlp/k8s-metrics: endpoint: "api.honeycomb.io:443" # US instance #endpoint: "api.eu1.honeycomb.io:443" # EU instance headers: "x-honeycomb-team": "${env:HONEYCOMB_API_KEY}" "x-honeycomb-dataset": "k8s-metrics" otlp/k8s-events: endpoint: "api.honeycomb.io:443" # US instance #endpoint: "api.eu1.honeycomb.io:443" # EU instance headers: "x-honeycomb-team": "${env:HONEYCOMB_API_KEY}" "x-honeycomb-dataset": "k8s-events" service: pipelines: traces: null metrics: receivers: [k8s_cluster] exporters: [ otlp/k8s-metrics ] logs: receivers: [k8sobjects] processors: [ memory_limiter, transform/events, batch ] exporters: [ otlp/k8s-events ] ports: jaeger-compact: enabled: false jaeger-thrift: enabled: false jaeger-grpc: enabled: false zipkin: enabled: false ``` Deploy the DaemonSet-mode Collector: ```shell theme={} helm install otel-collector open-telemetry/opentelemetry-collector --namespace honeycomb --values https://docs.honeycomb.io/_assets/code-samples/kubernetes/values-files/values-daemonset.yaml ``` [Download](/_assets/code-samples/kubernetes/values-files/values-daemonset.yaml) ```yaml theme={} mode: daemonset image: repository: ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector-k8s # Required to use the kubeletstats cpu/memory utilization metrics clusterRole: create: true rules: - apiGroups: - "" resources: - nodes/proxy verbs: - get extraEnvs: - name: HONEYCOMB_API_KEY valueFrom: secretKeyRef: name: honeycomb key: api-key presets: # enables the k8sattributesprocessor and adds it to the traces, metrics, and logs pipelines kubernetesAttributes: enabled: true extractAllPodLabels: true extractAllPodAnnotations: true # enables the kubeletstatsreceiver and adds it to the metrics pipelines kubeletMetrics: enabled: true config: receivers: jaeger: null zipkin: null kubeletstats: insecure_skip_verify: true # required as most clusters use self-signed certificates collection_interval: 30s metric_groups: - node - pod metrics: k8s.node.uptime: enabled: true k8s.pod.uptime: enabled: true k8s.pod.cpu_limit_utilization: enabled: true k8s.pod.cpu_request_utilization: enabled: true k8s.pod.memory_limit_utilization: enabled: true k8s.pod.memory_request_utilization: enabled: true exporters: otlp_http: endpoint: "https://api.honeycomb.io:443" # US instance #endpoint: "https://api.eu1.honeycomb.io:443" # EU instance headers: "x-honeycomb-team": "${env:HONEYCOMB_API_KEY}" otlp_http/k8s-metrics: endpoint: "https://api.honeycomb.io:443" # US instance #endpoint: "https://api.eu1.honeycomb.io:443" # EU instance headers: "x-honeycomb-team": "${env:HONEYCOMB_API_KEY}" "x-honeycomb-dataset": "k8s-metrics" otlp_http/k8s-logs: endpoint: "https://api.honeycomb.io:443" # US instance #endpoint: "https://api.eu1.honeycomb.io:443" # EU instance headers: "x-honeycomb-team": "${env:HONEYCOMB_API_KEY}" "x-honeycomb-dataset": "k8s-logs" service: pipelines: traces: receivers: [otlp] exporters: [otlp_http] metrics: receivers: [kubeletstats] exporters: [otlp/k8s-metrics] logs: exporters: [otlp/k8s-logs] ports: jaeger-compact: enabled: false jaeger-thrift: enabled: false jaeger-grpc: enabled: false zipkin: enabled: false ``` Deploy the Deployment-mode Collector: ```shell theme={} helm install otel-collector-cluster open-telemetry/opentelemetry-collector --namespace honeycomb --values https://docs.honeycomb.io/_assets/code-samples/kubernetes/values-files/eu-values-deployment.yaml ``` [Download](/_assets/code-samples/kubernetes/values-files/eu-values-deployment.yaml) ```yaml theme={} mode: deployment image: repository: ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector-k8s extraEnvs: - name: HONEYCOMB_API_KEY valueFrom: secretKeyRef: name: honeycomb key: api-key # We only want one of these collectors - any more and we'd produce duplicate data replicaCount: 1 presets: # enables the k8sclusterreceiver and adds it to the metrics pipelines clusterMetrics: enabled: true # enables the k8sobjectsreceiver to collect events only and adds it to the logs pipelines kubernetesEvents: enabled: true config: receivers: k8s_cluster: collection_interval: 30s metrics: # Disable replicaset metrics by default. These are typically high volume, low signal metrics. # If volume is not a concern, then the following blocks can be removed. k8s.replicaset.desired: enabled: false k8s.replicaset.available: enabled: false jaeger: null zipkin: null processors: transform/events: error_mode: ignore log_statements: - context: log statements: # adds a new watch-type attribute from the body if it exists - set(attributes["watch-type"], body["type"]) where IsMap(body) and body["type"] != nil # create new attributes from the body if the body is an object - merge_maps(attributes, body, "upsert") where IsMap(body) and body["object"] == nil - merge_maps(attributes, body["object"], "upsert") where IsMap(body) and body["object"] != nil # Transform the attributes so that the log events use the k8s.* semantic conventions - merge_maps(attributes, attributes[ "metadata"], "upsert") where IsMap(attributes[ "metadata"]) - set(attributes["k8s.pod.name"], attributes["regarding"]["name"]) where attributes["regarding"]["kind"] == "Pod" - set(attributes["k8s.node.name"], attributes["regarding"]["name"]) where attributes["regarding"]["kind"] == "Node" - set(attributes["k8s.job.name"], attributes["regarding"]["name"]) where attributes["regarding"]["kind"] == "Job" - set(attributes["k8s.cronjob.name"], attributes["regarding"]["name"]) where attributes["regarding"]["kind"] == "CronJob" - set(attributes["k8s.namespace.name"], attributes["regarding"]["namespace"]) where attributes["regarding"]["kind"] == "Pod" or attributes["regarding"]["kind"] == "Job" or attributes["regarding"]["kind"] == "CronJob" # Transform the type attribtes into OpenTelemetry Severity types. - set(severity_text, attributes["type"]) where attributes["type"] == "Normal" or attributes["type"] == "Warning" - set(severity_number, SEVERITY_NUMBER_INFO) where attributes["type"] == "Normal" - set(severity_number, SEVERITY_NUMBER_WARN) where attributes["type"] == "Warning" exporters: otlp/k8s-metrics: # endpoint: "api.honeycomb.io:443" # US instance endpoint: "api.eu1.honeycomb.io:443" # EU instance headers: "x-honeycomb-team": "${env:HONEYCOMB_API_KEY}" "x-honeycomb-dataset": "k8s-metrics" otlp/k8s-events: # endpoint: "api.honeycomb.io:443" # US instance endpoint: "api.eu1.honeycomb.io:443" # EU instance headers: "x-honeycomb-team": "${env:HONEYCOMB_API_KEY}" "x-honeycomb-dataset": "k8s-events" service: pipelines: traces: null metrics: receivers: [k8s_cluster] exporters: [ otlp/k8s-metrics ] logs: receivers: [k8sobjects] processors: [ memory_limiter, transform/events, batch ] exporters: [ otlp/k8s-events ] ports: jaeger-compact: enabled: false jaeger-thrift: enabled: false jaeger-grpc: enabled: false zipkin: enabled: false ``` Deploy the DaemonSet-mode Collector: ```shell theme={} helm install otel-collector open-telemetry/opentelemetry-collector --namespace honeycomb --values https://docs.honeycomb.io/_assets/code-samples/kubernetes/values-files/eu-values-daemonset.yaml ``` [Download](/_assets/code-samples/kubernetes/values-files/eu-values-daemonset.yaml) ```yaml theme={} mode: daemonset image: repository: ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector-k8s # Required to use the kubeletstats cpu/memory utilization metrics clusterRole: create: true rules: - apiGroups: - "" resources: - nodes/proxy verbs: - get extraEnvs: - name: HONEYCOMB_API_KEY valueFrom: secretKeyRef: name: honeycomb key: api-key presets: # enables the k8sattributesprocessor and adds it to the traces, metrics, and logs pipelines kubernetesAttributes: enabled: true extractAllPodLabels: true extractAllPodAnnotations: true # enables the kubeletstatsreceiver and adds it to the metrics pipelines kubeletMetrics: enabled: true config: receivers: jaeger: null zipkin: null kubeletstats: insecure_skip_verify: true # required as most clusters use self-signed certificates collection_interval: 30s metric_groups: - node - pod metrics: k8s.node.uptime: enabled: true k8s.pod.uptime: enabled: true k8s.pod.cpu_limit_utilization: enabled: true k8s.pod.cpu_request_utilization: enabled: true k8s.pod.memory_limit_utilization: enabled: true k8s.pod.memory_request_utilization: enabled: true exporters: otlp_http: # endpoint: "https://api.honeycomb.io:443" # US instance endpoint: "https://api.eu1.honeycomb.io:443" # EU instance headers: "x-honeycomb-team": "${env:HONEYCOMB_API_KEY}" otlp_http/k8s-metrics: # endpoint: "https://api.honeycomb.io:443" # US instance endpoint: "https://api.eu1.honeycomb.io:443" # EU instance headers: "x-honeycomb-team": "${env:HONEYCOMB_API_KEY}" "x-honeycomb-dataset": "k8s-metrics" otlp_http/k8s-logs: # endpoint: "https://api.honeycomb.io:443" # US instance endpoint: "https://api.eu1.honeycomb.io:443" # EU instance headers: "x-honeycomb-team": "${env:HONEYCOMB_API_KEY}" "x-honeycomb-dataset": "k8s-logs" service: pipelines: traces: receivers: [otlp] exporters: [otlp_http] metrics: receivers: [kubeletstats] exporters: [otlp_http/k8s-metrics] logs: exporters: [otlp_http/k8s-logs] ports: jaeger-compact: enabled: false jaeger-thrift: enabled: false jaeger-grpc: enabled: false zipkin: enabled: false ``` If Collector installation fails and returns an error like the following: ```bash theme={} Error: INSTALLATION FAILED: template: opentelemetry-collector/templates/service.yaml:38:28: executing "opentelemetry-collector/templates/service.yaml" at : error calling include: template: opentelemetry-collector/templates/_helpers.tpl:148:44: executing "opentelemetry-collector.serviceInternalTrafficPolicy" at : error calling eq: incompatible types for comparison ``` Make sure you have [Helm 3.9+](https://helm.sh/) installed, as older Helm versions typically cause this error. ## Step 5: Verify the Collector Installation Check that the Collectors are installed by using the `kubectl` command to see if the pods are running: ```shell theme={} kubectl get pods --namespace honeycomb ``` This command should return something like: ```pre theme={} NAME READY STATUS RESTARTS AGE otel-collector-cluster-opentelemetry-collector-7c9cc9f8d-k9ncw 1/1 Running 0 9m21s otel-collector-opentelemetry-collector-agent-fcn5v 1/1 Running 0 17m ``` The result should contain one pod running under a name containing the prefix `otel-collector-cluster`, and one pod running under a name containing the word `agent` for each node in your Kubernetes cluster. You should now have an OpenTelemetry installation in your cluster that can: * Receive tracing data from service applications in your cluster and forward it to Honeycomb. * Gather and send metrics data from all of the pods in your cluster. * Gather and send metrics data about the nodes in your cluster. ## Explore Your Data in Honeycomb After a few minutes, data should start flowing into Honeycomb. If you do not see any data after several minutes, reach out for help in our [Pollinators Community Slack](/troubleshoot/community/#join-pollinators-community-slack). Pro/Enterprise users can [visit Honeycomb Support](https://support.honeycomb.io/) or [email support@honeycomb.io](mailto:support@honeycomb.io). To explore metrics related to your Kubernetes cluster, log in to Honeycomb and query the `k8s-metrics` dataset in your environment. Try asking the Query Assistant questions like: * "Show me the average CPU of my pods" * "What's the P99 memory usage of my nodes?" To explore the events emitted by Kubernetes itself, query the `k8s-events` dataset. These may be a little harder to understand, so try asking the Query Assistant questions like: * "Show me the pods that have a reason of Started" * "Show me pods that are crashing" For each question you ask, the Query Assistant will create a general query. You can further customize each query by adding visualizations, or by filtering or grouping the data. ## What's Next? Now that you have created an observability pipeline and have gotten some metrics, you can use these to get even more visibility into your Kubernetes cluster. * **Configure your applications to send data to the OpenTelemetry Collectors** Have you already instrumented your applications with OpenTelemetry? You'll need to [configure your pods and applications to send data to your new Collectors](/send-data/kubernetes/opentelemetry/collect-instrumented-code/). * **Add low-code, automatic instrumentation to your applications** Do you want more insight into your application data, but can't fully instrument your code yet? You can get even more insight by using the OpenTelemetry Operator to automatically instrument your applications. To learn more, visit [Low-Code Auto-Instrumentation with the OpenTelemetry Operator for Kubernetes](/send-data/kubernetes/opentelemetry/add-automatic-instrumentation/). ## Additional Information The DaemonSet-mode Collector uses the following components: * [Kubernetes Attribute Processor](/send-data/kubernetes/opentelemetry/components/#kubernetes-attributes-processor) * [Kubeletstats Receiver](/send-data/kubernetes/opentelemetry/components/#kubeletstats-receiver) The Deployment-mode Collector uses the following components: * [Kubernetes Cluster Receiver](/send-data/kubernetes/opentelemetry/components/#kubernetes-cluster-receiver) * [Kubernetes Objects Receiver](/send-data/kubernetes/opentelemetry/components/#kubernetes-objects-receiver) # Send Events with the Kubernetes Objects Receiver Source: https://docs.honeycomb.io/send-data/kubernetes/send-events-objects-receiver Send Kubernetes Events to Honeycomb using the OpenTelemetry Kubernetes Objects Receiver, even if your applications are not instrumented with OpenTelemetry. If you are running applications that are not using OpenTelemetry in your Kubernetes cluster, you can still collect the events from your cluster. In this guide, you will learn how to use an OpenTelemetry Collector to get additional insight into your data by sending your Kubernetes Events to Honeycomb using OpenTelemetry's [Kubernetes Objects Receiver](https://opentelemetry.io/docs/kubernetes/collector/components/#kubernetes-objects-receiver). ## Before You Begin Before beginning this guide, you should have: * Created a running Kubernetes cluster. * Created a namespace named `honeycomb`. * [Deployed an OpenTelemetry Collector in Deployment mode with a Helm chart](/send-data/kubernetes/opentelemetry/create-telemetry-pipeline/#step-4-deploy-collectors). ## Collect Events Enable the Kubernetes Objects Receiver to collect events by adding the `kubernetesEvents` preset in the values file for your [OpenTelemetry Deployment-mode Collector](/send-data/kubernetes/opentelemetry/create-telemetry-pipeline/#step-4-deploy-collectors). Place it near the top of the values file under the `config` section: ```yaml theme={} presets: kubernetesEvents: enabled: true ``` To review the configuration, [download the values file for the Deployment-mode Collector](/_assets/code-samples/kubernetes/values-files/values-deployment.yaml). Apply this to only a Deployment-mode Collector with a replica count of 1. Running multiple receivers on the same Kubernetes cluster will cause duplicate events to be sent for every Collector running this receiver. ## Format Event Data By default, the `kubernetesEvents` preset in the OpenTelemetry Helm chart will configure the Collector to pull all of the events from the Kubernetes cluster and export them as logs. Honeycomb users can derive a great deal of value from these logs--when they are structured appropriately. To transform the bodies of these logs into structured content that is easily queried in Honeycomb, use the [OpenTelemetry Transform Processor](https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/processor/transformprocessor/README.md) to parse the event data. To force the event data to conform to the standard `k8s.*` attribute naming that all other telemetry types use: 1. Add the following to the values file for your [OpenTelemetry Deployment-mode Collector](/send-data/kubernetes/opentelemetry/create-telemetry-pipeline/#step-4-deploy-collectors). Place it near the top of the values file under the `config` section: ```yaml theme={} processors: transform/events: error_mode: ignore log_statements: - context: log statements: - set(attributes["watch-type"], body["type"]) where IsMap(body) and body["type"] != nil - merge_maps(attributes, body, "upsert") where IsMap(body) and body["object"] == nil - merge_maps(attributes, body["object"], "upsert") where IsMap(body) and body["object"] != nil - merge_maps(attributes, attributes[ "metadata"], "upsert") where IsMap(attributes[ "metadata"]) # Maps the name of the resource to the right k8s.* attribute - set(attributes["k8s.pod.name"], attributes["regarding"] ["name"]) where attributes["regarding"]["kind"] == "Pod" - set(attributes["k8s.node.name"], attributes["regarding"]["name"]) where attributes["regarding"]["kind"] == "Node" - set(attributes["k8s.job.name"], attributes["regarding"]["name"]) where attributes["regarding"]["kind"] == "Job" - set(attributes["k8s.cronjob.name"], attributes["regarding"]["name"]) where attributes["regarding"]["kind"] == "CronJob" - set(attributes["k8s.namespace.name"], attributes["regarding"]["namespace"]) where attributes["regarding"]["kind"] == "Pod" or attributes["regarding"]["kind"] == "Job" or attributes["regarding"]["kind"] == "CronJob" # Converts event types to Otel log Severities - set(severity_text, attributes["type"]) where attributes["type"] == "Normal" or attributes["type"] == "Warning" - set(severity_number, SEVERITY_NUMBER_INFO) where attributes["type"] == "Normal" - set(severity_number, SEVERITY_NUMBER_WARN) where attributes["type"] == "Warning" ``` 2. Under the `config` section, update your `pipelines` section to match the following: ```yaml theme={} service: pipelines: metrics: exporters: [ otlp/k8s-metrics ] logs: processors: [ memory_limiter, transform/events, batch ] exporters: [ otlp/k8s-logs ] ``` # Send Logs with OpenTelemetry's Filelog Receiver Source: https://docs.honeycomb.io/send-data/kubernetes/send-logs-filelog-receiver Send container logs from your Kubernetes cluster to Honeycomb using the OpenTelemetry Filelog Receiver, even without application-level instrumentation. If you are running applications that are not using OpenTelemetry in your Kubernetes cluster, you can still collect the logs from your containers. In this guide, you will learn how to use an OpenTelemetry Collector to get additional insight into your data by sending your container logs to Honeycomb using OpenTelemetry's [Filelog Receiver](https://opentelemetry.io/docs/kubernetes/collector/components/#filelog-receiver). ## Before You Begin Before beginning this guide, you should have: * Created a running Kubernetes cluster. * [Deployed an OpenTelemetry Collector in DaemonSet mode using a Helm chart](/send-data/kubernetes/opentelemetry/create-telemetry-pipeline/). ## Collect Logs Enable the Filelog Receiver to collect logs by adding the `logsCollection` preset in the values file for your [OpenTelemetry DaemonSet-mode Collector](/send-data/kubernetes/opentelemetry/create-telemetry-pipeline/#step-4-deploy-collectors). Place it near the top of the values file under the `config` section: ```yaml theme={} presets: logsCollection: enabled: true ``` [Download](/_assets/code-samples/kubernetes/values-files/values-daemonset.yaml) ```yaml theme={} mode: daemonset image: repository: ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector-k8s # Required to use the kubeletstats cpu/memory utilization metrics clusterRole: create: true rules: - apiGroups: - "" resources: - nodes/proxy verbs: - get extraEnvs: - name: HONEYCOMB_API_KEY valueFrom: secretKeyRef: name: honeycomb key: api-key presets: # enables the k8sattributesprocessor and adds it to the traces, metrics, and logs pipelines kubernetesAttributes: enabled: true extractAllPodLabels: true extractAllPodAnnotations: true # enables the kubeletstatsreceiver and adds it to the metrics pipelines kubeletMetrics: enabled: true config: receivers: jaeger: null zipkin: null kubeletstats: insecure_skip_verify: true # required as most clusters use self-signed certificates collection_interval: 30s metric_groups: - node - pod metrics: k8s.node.uptime: enabled: true k8s.pod.uptime: enabled: true k8s.pod.cpu_limit_utilization: enabled: true k8s.pod.cpu_request_utilization: enabled: true k8s.pod.memory_limit_utilization: enabled: true k8s.pod.memory_request_utilization: enabled: true exporters: otlp_http: endpoint: "https://api.honeycomb.io:443" # US instance #endpoint: "https://api.eu1.honeycomb.io:443" # EU instance headers: "x-honeycomb-team": "${env:HONEYCOMB_API_KEY}" otlp_http/k8s-metrics: endpoint: "https://api.honeycomb.io:443" # US instance #endpoint: "https://api.eu1.honeycomb.io:443" # EU instance headers: "x-honeycomb-team": "${env:HONEYCOMB_API_KEY}" "x-honeycomb-dataset": "k8s-metrics" otlp_http/k8s-logs: endpoint: "https://api.honeycomb.io:443" # US instance #endpoint: "https://api.eu1.honeycomb.io:443" # EU instance headers: "x-honeycomb-team": "${env:HONEYCOMB_API_KEY}" "x-honeycomb-dataset": "k8s-logs" service: pipelines: traces: receivers: [otlp] exporters: [otlp_http] metrics: receivers: [kubeletstats] exporters: [otlp/k8s-metrics] logs: exporters: [otlp/k8s-logs] ports: jaeger-compact: enabled: false jaeger-thrift: enabled: false jaeger-grpc: enabled: false zipkin: enabled: false ``` ## Tune Logs Collection By default, the `logsCollection` preset in the OpenTelemetry Helm chart will configure the Collector to collect all the pod logs in a cluster. In larger clusters, you may want to configure the preset to target specific pods or applications to avoid being overwhelmed. ### Restrict Logs by Location or Name To collect only logs in a specific directory or with a specific filename, combine the preset with some configuration: ```yaml theme={} presets: logsCollection: enabled: true config: receivers: filelog: include: - /var/log/pods/my-namespace*/*/*.log - /var/log/pods/*mypodname*/*/*.log - /var/log/pods/*/my-containername/*.log ``` ### Restrict Logs by Label Selector To collect logs for only certain label selectors, use the Kubernetes Attributes processor to enable labels, and then the Filter processor to remove unwanted data: ```yaml theme={} presets: kubernetesAttributes: enabled: true extractAllPodLabels: true logsCollection: enabled: true config: processors: filter: error_mode: ignore logs: log_record: - resource.attributes["app.kubernetes.io/component"] != "myapp1" exporters: otlp: endpoint: "api.honeycomb.io:443" # US instance #endpoint: "api.eu1.honeycomb.io:443" # EU instance headers: "x-honeycomb-team": "YOUR_API_KEY" "x-honeycomb-dataset": "myapp1-logs" service: pipelines: logs: receivers: - filelog processors: - memory_limiter - k8sattributes - filter - batch exporters: - otlp ``` ### Send Logs to Different Datasets To send specific logs to different datasets, use the [Filter processor](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/processor/filterprocessor) and multiple OTLP exporters: ```yaml theme={} presets: kubernetesAttributes: enabled: true extractAllPodLabels: true logsCollection: enabled: true config: processors: filter/myapp1: error_mode: ignore logs: log_record: - resource.attributes["app.kubernetes.io/component"] != "myapp1" filter/myapp2: error_mode: ignore logs: log_record: - resource.attributes["app.kubernetes.io/component"] != "myapp2" exporters: otlp/myapp1: endpoint: "api.honeycomb.io:443" # US instance #endpoint: "api.eu1.honeycomb.io:443" # EU instance headers: "x-honeycomb-team": "YOUR_API_KEY" "x-honeycomb-dataset": "myapp1-logs" otlp/myapp2: endpoint: "api.honeycomb.io:443" # US instance #endpoint: "api.eu1.honeycomb.io:443" # EU instance headers: "x-honeycomb-team": "YOUR_API_KEY" "x-honeycomb-dataset": "myapp2-logs" service: pipelines: logs: receivers: - filelog processors: - memory_limiter - k8sattributes - filter/myapp1 - batch exporters: - otlp/myapp1 logs/myapp2: receivers: - filelog processors: - memory_limiter - k8sattributes - filter/myapp2 - batch exporters: - otlp/myapp2 ``` # Send Logs from OpenTelemetry SDKs Source: https://docs.honeycomb.io/send-data/logs/opentelemetry/sdk Configure an OpenTelemetry SDK to produce structured logs directly from your application and send them to Honeycomb, correlated with your existing traces. This guide details how to send OpenTelemetry Logs from OpenTelemetry SDKs to Honeycomb. ## What are OpenTelemetry Logs? OpenTelemetry Logs are **structured logs** that wrap the bodies of existing logs and optionally correlate them with traces. For example, structured application logs from a logging framework in your application will be automatically correlated with any tracing you also add to that application. OpenTelemetry Logs also enable you to centrally process logs data along with traces and metrics within the OpenTelemetry Collector. ## Send Logs from Your Application to Honeycomb You can send your structured application logs via OpenTelemetry to an endpoint, such as Honeycomb's endpoint or the OpenTelemetry Collector. This option is especially useful if structured logging exists in your application, since it allows for automatic correlation of structured logs with traces later. When you use an OpenTelemetry SDK to create OpenTelemetry Logs, you send to Honeycomb directly or an OpenTelemetry Collector configured to export to Honeycomb. OpenTelemetry Logs are not supported in all languages yet. Refer to the [OpenTelemetry availability status for each language](https://opentelemetry.io/status/). Explore examples related to sending OpenTelemetry logs to Honeycomb using the OpenTelemetry .NET SDK. Explore examples related to sending OpenTelemetry logs to Honeycomb using the OpenTelemetry Python SDK. Explore examples related to sending OpenTelemetry logs to Honeycomb using the OpenTelemetry Java SDK. Explore examples related to sending OpenTelemetry logs to Honeycomb using the OpenTelemetry JavaScript SDK. Explore examples related to sending OpenTelemetry logs to Honeycomb using the OpenTelemetry Go SDK. # Example: Send OpenTelemetry Logs with the OpenTelemetry .NET SDK Source: https://docs.honeycomb.io/send-data/logs/opentelemetry/sdk/dotnet Configure the OpenTelemetry .NET SDK logger provider to send structured logs from your .NET application to Honeycomb or an OpenTelemetry Collector. This example shows how to configure the OpenTelemetry .NET SDK's logger provider to send logs from a .NET application to Honeycomb or to an OpenTelemetry Collector. Install the OpenTelemetry SDK and OTLP exporter packages: ```shell theme={} dotnet add package OpenTelemetry dotnet add package OpenTelemetry.Exporter.OpenTelemetryProtocol ``` During application setup, create and configure the logger provider: ```csharp theme={} using Microsoft.Extensions.Logging; using OpenTelemetry; using OpenTelemetry.Logs; // Configure a logger factory with OpenTelemetry and the OTLP log exporter using var loggerFactory = LoggerFactory.Create(builder => { builder.AddOpenTelemetry(options => { options.AddOtlpExporter(); }); }); // Create an ILogger instance from the logger factory var logger = loggerFactory.CreateLogger(); // Use the logger in your application logger.LogInformation("Something interesting happened"); ``` Set environment variables to configure the exporter and define your service name, then run your application. To send logs directly to Honeycomb: ```shell theme={} OTEL_SERVICE_NAME="my-service" \ OTEL_EXPORTER_OTLP_ENDPOINT="https://api.honeycomb.io" \ OTEL_EXPORTER_OTLP_HEADERS="x-honeycomb-team=" \ dotnet run ``` To send logs to an OpenTelemetry Collector instead: ```shell theme={} OTEL_SERVICE_NAME="my-service" \ OTEL_EXPORTER_OTLP_ENDPOINT="my-collector:4317" \ OTEL_EXPORTER_OTLP_INSECURE=true \ dotnet run ``` # Example: Send OpenTelemetry Logs with the OpenTelemetry Go SDK Source: https://docs.honeycomb.io/send-data/logs/opentelemetry/sdk/go Configure the OpenTelemetry Go SDK to send structured logs from your Go application to Honeycomb or a Collector. Logs support in the OpenTelemetry Go SDK is currently experimental and subject to change. To check the status for each language, refer to the [OpenTelemetry status page](https://opentelemetry.io/status/). This example shows how to configure the OpenTelemetry Go SDK with `slog` instrumentation to send logs from a Go application to Honeycomb or an OpenTelemetry Collector. Install the OpenTelemetry `otelconf/x` and `otelslog` bridge packages: ```shell theme={} go get \ go.opentelemetry.io/contrib/otelconf/x \ go.opentelemetry.io/contrib/bridges/otelslog ``` During application setup, initialize the SDK from the config file and set the global logger provider: ```go theme={} package main import ( "context" "go.opentelemetry.io/contrib/bridges/otelslog" otelconf "go.opentelemetry.io/contrib/otelconf/x" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/log/global" ) func main() { // Set up the OpenTelemetry SDK from the config file sdk, err := otelconf.NewSDK() if err != nil { panic("failed to initialize OTel SDK") } defer sdk.Shutdown(context.Background()) otel.SetTracerProvider(sdk.TracerProvider()) otel.SetTextMapPropagator(sdk.Propagator()) // Set the logger provider globally global.SetLoggerProvider(sdk.LoggerProvider()) // Create a new slog logger instance logger := otelslog.NewLogger() // Use the logger directly anywhere in your app logger.Debug("Something interesting happened") } ``` Create an `otelconfig.yaml` file to configure your exporter. To send logs to Honeycomb: ```yaml theme={} file_format: "1.1" resource: attributes: - name: service.name value: ${OTEL_SERVICE_NAME:-my-service} logger_provider: processors: - batch: exporter: otlp_http: endpoint: https://api.honeycomb.io/v1/logs headers: - name: x-honeycomb-team value: ${HONEYCOMB_API_KEY} ``` To send logs to an OpenTelemetry Collector instead: ```yaml theme={} file_format: "1.1" resource: attributes: - name: service.name value: ${OTEL_SERVICE_NAME:-my-service} logger_provider: processors: - batch: exporter: otlp_grpc: endpoint: http://my-collector:4317 ``` When `OTEL_CONFIG_FILE` is set, the configuration file is the single source of truth for the SDK. Other `OTEL_*` environment variables are ignored by design, so set all SDK options in the YAML file. You can still reference environment variables from inside the YAML using `${VAR_NAME}` substitution. Point the SDK at your configuration file using `OTEL_CONFIG_FILE`, then run your application: ```shell theme={} OTEL_CONFIG_FILE=./otelconfig.yaml go run app.go ``` # Example: Send OpenTelemetry Logs with the OpenTelemetry Java SDK Source: https://docs.honeycomb.io/send-data/logs/opentelemetry/sdk/java Configure the OpenTelemetry Java SDK or Java agent to intercept log messages from your logging framework and send them to Honeycomb as structured OTLP logs. OpenTelemetry Java uses log appenders to intercept log messages from popular logging frameworks and convert them into OTLP logs. Log appenders work with both the OpenTelemetry Java agent and the OpenTelemetry Java SDK. The following example shows how to configure a Java application using Gradle to send Log4j logs to Honeycomb or an OpenTelemetry Collector. Install the OpenTelemetry Java agent. The Log4j appender is bundled with the agent and installs automatically. ```groovy theme={} dependencies { // OpenTelemetry Java Agent agent "io.opentelemetry.javaagent:opentelemetry-javaagent:${otelAgentVersion}" } ``` Install Log4j and the OpenTelemetry SDK, OTLP exporter and Log4j appender packages: ```groovy theme={} dependencies { // Log4j implementation("org.apache.logging.log4j:log4j-api:2.17.2") implementation("org.apache.logging.log4j:log4j-core:2.17.2") // OpenTelemetry SDK & OTLP exporter implementation("io.opentelemetry:opentelemetry-sdk") implementation("io.opentelemetry:opentelemetry-exporter-otlp") // OpenTelemetry Log4j appender implementation("io.opentelemetry.instrumentation:opentelemetry-log4j-appender-2.17") } ``` The Log4j appender is bundled with the agent and requires no additional configuration. During application setup, install the OpenTelemetry Log4j appender when configuring the SDK: ```java theme={} import io.opentelemetry.instrumentation.log4j.appender.v2_17.OpenTelemetryAppender; import io.opentelemetry.sdk.OpenTelemetrySdk; // Setup OpenTelemetry SDK OpenTelemetrySdk sdk = OpenTelemetrySdk.builder() .build(); // Install the OpenTelemetry log4j log appender that intercepts log messages and create OTLP logs from them OpenTelemetryAppender.install(sdk); ``` Configure Log4j using a configuration file. The following example logs all messages to both the console and the OpenTelemetry log appender. The `packages` property on the top-level `Configuration` element tells Log4j to scan for custom appenders in the package. The OpenTelemetry appender is defined in `Appenders` and referenced in the root logger (`Loggers` > `Root`). ```xml theme={} ``` Then, in your application code you can use Log4j's `LogManager` to create loggers and emit log messages: ```java theme={} import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; // Create a logger and use it in your application Logger logger = LogManager.getLogger("my-logger") Map mapMessage = new HashMap<>(); mapMessage.put("app.message", "Something interesting happened"); logger.info(new ObjectMessage(mapMessage)); ``` Create an `otelconfig.yaml` file and point the agent at it using `OTEL_CONFIG_FILE`. When `OTEL_CONFIG_FILE` is set, the configuration file is the single source of truth for the SDK. Other `OTEL_*` environment variables are ignored by design, so set all SDK options in the YAML file. You can still reference environment variables from inside the YAML using `${VAR_NAME}` substitution. To send logs directly to Honeycomb: ```yaml theme={} file_format: "1.1" resource: attributes: - name: service.name value: ${OTEL_SERVICE_NAME:-my-service} logger_provider: processors: - batch: exporter: otlp_http: endpoint: https://api.honeycomb.io/v1/logs headers: - name: x-honeycomb-team value: ${HONEYCOMB_API_KEY} propagator: composite: - tracecontext: - baggage: ``` ```shell theme={} OTEL_CONFIG_FILE=./otelconfig.yaml ./gradlew run ``` To send logs to an OpenTelemetry Collector instead: ```yaml theme={} file_format: "1.1" resource: attributes: - name: service.name value: ${OTEL_SERVICE_NAME:-my-service} logger_provider: processors: - batch: exporter: otlp_grpc: endpoint: my-collector:4317 insecure: true propagator: composite: - tracecontext: - baggage: ``` ```shell theme={} OTEL_CONFIG_FILE=./otelconfig.yaml ./gradlew run ``` ## Available Log Appenders OpenTelemetry Java includes log appenders for popular logging frameworks. Each appender intercepts log messages and routes them through the OpenTelemetry export pipeline. Available log appenders include: * [Log4j Appender](https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/log4j/log4j-appender-2.17/library) * [Logback](https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/logback/logback-appender-1.0/library) * [JBoss Logmanager](https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/jboss-logmanager) (agent only) # Example: Send OpenTelemetry Logs with the OpenTelemetry JavaScript SDK Source: https://docs.honeycomb.io/send-data/logs/opentelemetry/sdk/javascript Configure the OpenTelemetry JavaScript SDK to send structured logs from your JavaScript application to Honeycomb or a Collector. Logs support in the OpenTelemetry JavaScript SDK is currently experimental and subject to change. To check the status for each language, refer to the [OpenTelemetry status page](https://opentelemetry.io/status/). This example shows how to configure the OpenTelemetry JavaScript SDK to capture Bunyan logging calls and send logs from a JavaScript application to Honeycomb or an OpenTelemetry Collector. Install the OpenTelemetry Node.js SDK, Bunyan instrumentation, and Bunyan logging framework packages: ```shell theme={} npm install --save @opentelemetry/sdk-node \ @opentelemetry/instrumentation-bunyan \ bunyan ``` Create an initialization file (for example, `telemetry.js`) that sets up the SDK with Bunyan instrumentation. The exporter configuration is provided by the `otelconfig.yaml` file at runtime. ```js theme={} const { startNodeSDK } = require('@opentelemetry/sdk-node'); const { BunyanInstrumentation } = require('@opentelemetry/instrumentation-bunyan'); const sdk = startNodeSDK({ instrumentations: [ new BunyanInstrumentation(), ] }); // Shut down the SDK gracefully before exiting to export all pending logs process.on('SIGTERM', () => { sdk .shutdown() .finally(() => process.exit(0)); }); ``` Then, in your application, create and use Bunyan loggers to capture interesting things: ```javascript theme={} const bunyan = require('bunyan'); // Create a logger and use it in your app const logger = bunyan.createLogger({name: 'myapp', level: 'info'}); logger.info({'app.message':'Something interesting happened'}); ``` Create an `otelconfig.yaml` file to configure your exporter. To send logs to Honeycomb: ```yaml theme={} file_format: "1.1" resource: attributes: - name: service.name value: ${OTEL_SERVICE_NAME:-my-service} logger_provider: processors: - batch: exporter: otlp_http: endpoint: https://api.honeycomb.io/v1/logs headers: - name: x-honeycomb-team value: ${HONEYCOMB_API_KEY} ``` To send logs to an OpenTelemetry Collector instead: ```yaml theme={} file_format: "1.1" resource: attributes: - name: service.name value: ${OTEL_SERVICE_NAME:-my-service} logger_provider: processors: - batch: exporter: otlp_grpc: endpoint: http://my-collector:4317 ``` When `OTEL_CONFIG_FILE` is set, the configuration file is the single source of truth for the SDK. Other `OTEL_*` environment variables are ignored by design, so set all SDK options in the YAML file. You can still reference environment variables from inside the YAML using `${VAR_NAME}` substitution. Point the SDK at your configuration file using `OTEL_CONFIG_FILE`, then run your application: ```shell theme={} OTEL_CONFIG_FILE=./otelconfig.yaml node -r ./telemetry.js app.js ``` ## Supported Logging Frameworks The OpenTelemetry JavaScript SDK can automatically create logs from these supported logging frameworks: * Bunyan * Winston # Example: Send OpenTelemetry Logs with the OpenTelemetry Python SDK Source: https://docs.honeycomb.io/send-data/logs/opentelemetry/sdk/python Configure the OpenTelemetry Python SDK logger provider to send structured logs from your Python application to Honeycomb or a Collector. Logs support in the OpenTelemetry Python SDK is currently experimental and subject to change. To check the status for each language, refer to the [OpenTelemetry status page](https://opentelemetry.io/status/). This example shows how to configure the OpenTelemetry Python SDK with declarative configuration to send logs from a Python application to Honeycomb or an OpenTelemetry Collector. Install the OpenTelemetry distro, instrumentation, and OTLP exporter packages: ```shell theme={} pip install opentelemetry-distro \ opentelemetry-instrumentation \ opentelemetry-exporter-otlp ``` Create an `otelconfig.yaml` file to configure your exporter. To send logs to Honeycomb: ```yaml theme={} file_format: "1.0" resource: attributes: - name: service.name value: ${OTEL_SERVICE_NAME:-my-service} logger_provider: processors: - batch: exporter: otlp_http: endpoint: https://api.honeycomb.io/v1/logs headers: - name: x-honeycomb-team value: ${HONEYCOMB_API_KEY} ``` To send logs to an OpenTelemetry Collector instead: ```yaml theme={} file_format: "1.0" resource: attributes: - name: service.name value: ${OTEL_SERVICE_NAME:-my-service} logger_provider: processors: - batch: exporter: otlp_grpc: endpoint: http://my-collector:4317 ``` When `OTEL_CONFIG_FILE` is set, the configuration file is the single source of truth for the SDK. Other `OTEL_*` environment variables are ignored by design, so set all SDK options in the YAML file. You can still reference environment variables from inside the YAML using `${VAR_NAME}` substitution. Attach the OpenTelemetry `LoggingHandler` to the root logger during application startup so that standard library `logging` records reach the configured logger provider: ```python theme={} import logging from opentelemetry._logs import get_logger_provider from opentelemetry.sdk._logs import LoggingHandler logging.getLogger().addHandler( LoggingHandler(logger_provider=get_logger_provider()) ) # Use logging directly anywhere in your app logging.warning("Something interesting happened") ``` This step is a temporary workaround. Under `OTEL_CONFIG_FILE`, the `OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED` variable is ignored, so the handler must be attached manually. It will not be required in a future release. Upstream work is tracked in [open-telemetry/opentelemetry-python#5352](https://github.com/open-telemetry/opentelemetry-python/issues/5352). Point the SDK at your configuration file using `OTEL_CONFIG_FILE`, then run your application: ```shell theme={} OTEL_CONFIG_FILE=./otelconfig.yaml opentelemetry-instrument python app.py ``` # Send Structured Logs with Honeytail Source: https://docs.honeycomb.io/send-data/logs/structured/honeytail Tail, parse, and send existing structured log files to Honeycomb with Honeytail, Honeycomb's lightweight log ingestion agent. We have written a lightweight tool called `honeytail`. Honeytail will tail your existing log files, parse the content, and send it up to Honeycomb. If you already have structured data in an existing log, this is the easiest method to get that data in to Honeycomb. **The quality of your dataset within Honeycomb depends entirely upon the quality of the data going into the log file.** To get the most useful insight out of Honeycomb, you must provide high quality data in your log file. In addition to as much detail about each event as you can include, it is best to always include some host-level information to give each event in the log context. For example, the host on which the log exists. Honeytail is designed to run as a daemon so that it can continuously consume new content as it appears in the log files as well as detect when a log file rotates. It must be configured with your team API key and the name of the Dataset to which you want to write data. You specify one of the available parser modules depending on how your log data is structured. Once running, `honeytail` will take care of uploading all the data in your log file and picking up new data as it comes in. Honeytail is open source—we encourage auditing the software you will run on your servers. We also happily consider pull requests with new log format parsers and other improvements. To see an example of Honeytail in action, try out our [Honeytail Example](https://github.com/honeycombio/honeytail/tree/main/examples/backfill). ## Installation `honeytail` will tail existing log files, parse the content, and send it up to Honeycomb. You can [view its source here](https://github.com/honeycombio/honeytail). Download and install the latest `honeytail` by running: Download the `honeytail_1.10.0_amd64.deb` package. ```shell theme={} wget -q https://honeycomb.io/download/honeytail/v1.10.0/honeytail_1.10.0_amd64.deb ``` Verify the package. ```shell theme={} echo '3db441215f97eaed068aa0531c986cf5405957e3e8e26b22c16b571091caf917 honeytail_1.10.0_amd64.deb' | sha256sum -c ``` Install the package. ```shell theme={} sudo dpkg -i honeytail_1.10.0_amd64.deb ``` The packages install `honeytail`, its config file `/etc/honeytail/honeytail.conf`, and some start scripts. Build `honeytail` from source if you need it in an unpackaged form or for ad-hoc use. Download the `honeytail_1.10.0_arm64.deb` package. ```shell theme={} wget -q https://honeycomb.io/download/honeytail/v1.10.0/honeytail_1.10.0_arm64.deb ``` Verify the package. ```shell theme={} echo '4220756e5a941cde6a484cb4cfde184eb189aaf29170df301a874eb143e960ed honeytail_1.10.0_arm64.deb' | sha256sum -c ``` Install the package. ```shell theme={} sudo dpkg -i honeytail_1.10.0_arm64.deb ``` The packages install `honeytail`, its config file `/etc/honeytail/honeytail.conf`, and some start scripts. Build `honeytail` from source if you need it in an unpackaged form or for ad-hoc use. Download the `honeytail_1.10.0-1.x86_64.rpm` package. ```shell theme={} wget -q https://honeycomb.io/download/honeytail/v1.10.0/honeytail_1.10.0-1.x86_64.rpm ``` Verify the package. ```shell theme={} echo 'b23215a9301b20b2e2262a0823c9e761e8b57e1a62fd5cec35f697fce41fa863 honeytail_1.10.0-1.x86_64.rpm' | sha256sum -c ``` Install the package. ```shell theme={} sudo rpm -i honeytail_1.10.0-1.x86_64.rpm ``` The packages install `honeytail`, its config file `/etc/honeytail/honeytail.conf`, and some start scripts. Build `honeytail` from source if you need it in an unpackaged form or for ad-hoc use. Download the 1.10.0 binary. ```shell theme={} wget -q -O honeytail https://honeycomb.io/download/honeytail/v1.10.0/honeytail-linux-amd64 ``` Verify the binary. ```shell theme={} echo 'c9cc7dd1aa2b12afeb30b089061870f3407d2df0119e7c2807fec648b603e2d5 honeytail' | shasum -a 256 -c ``` Set the permissions to allow execution. ```shell theme={} chmod 755 ./honeytail ``` Download the 1.10.0 binary. ```shell theme={} wget -q -O honeytail https://honeycomb.io/download/honeytail/v1.10.0/honeytail-linux-arm64 ``` Verify the binary. ```shell theme={} echo '1dd37227788548c4ed44592554e3c90e374c4d796c444dde9f372db8618bc7fa honeytail' | shasum -a 256 -c ``` Set the permissions to allow execution. ```shell theme={} chmod 755 ./honeytail ``` Download the 1.10.0 binary. ```shell theme={} wget -q -O honeytail https://honeycomb.io/download/honeytail/v1.10.0/honeytail-darwin-amd64 ``` Verify the binary. ```shell theme={} echo '9a3da0f48fe21b1e610ac6b63130dfb8118a9a0ec16abae13350edba02d85e4d honeytail' | shasum -a 256 -c ``` Set the permissions to allow execution. ```shell theme={} chmod 755 ./honeytail ``` Clone the [Honeytail](https://github.com/honeycombio/honeytail) repository. ```shell theme={} git clone https://github.com/honeycombio/honeytail ``` Install from source. ```shell theme={} cd honeytail; go install ``` An [example Dockerfile](https://github.com/honeycombio/honeytail/blob/master/Dockerfile) is also available on GitHub. Then, modify the configuration file. Uncomment and set the following variables: * `ParserName` to the appropriate one of `json`, `nginx`, `mysql`, `arangodb`, `regex` * `WriteKey` to your [API key](/configure/environments/manage-api-keys/#find-api-keys) * `LogFiles` to the path for the log file you want to ingest, or `-` for `stdin` * `Dataset` to the name of the dataset you wish to create with this log file. The docs pages for [JSON](/send-data/logs/structured/json/), [NGINX](/send-data/logs/structured/nginx/), [MySQL](/send-data/logs/structured/mysql/), [PostgreSQL](/send-data/logs/structured/postgresql/) and [regex](/send-data/logs/unstructured/honeytail-regex/) have more detail on additional options to set for each parser. The other available options are all described in the configuration file and below. Launch `honeytail` by hand with `honeytail -c /etc/honeytail/honeytail.conf` or using the standard `sudo initctl start honeytail` (upstart) or `sudo systemctl start honeytail` (systemd) commands. `honeytail` will automatically start back up after rebooting your system. To disable this, put the word `manual` in `/etc/init/honeytail.override` (upstart) or run `systemctl disable honeytail` (systemd). ## Launch the Agent Start up a `honeytail` process using `upstart` or `systemd`, or by launching the process by hand. This will tail the log file specified in the configuration and leave the process running as a daemon. ```shell theme={} sudo initctl start honeytail ``` ```shell theme={} sudo systemctl start honeytail ``` ```shell theme={} honeytail -c /etc/honeytail/honeytail.conf ``` In order to start successfully sending data, you will need to update the configuration file included with these packages to specify the parser (for example, `nginx`), its associated options, such as where the log files are found, and the API key. We enforce a rate limit in order to protect our servers from abuse. This can be raised on a case-by-case basis; please [contact us](https://www.honeycomb.io/support/) to lift your limit. ## Data Formats Honeytail has predefined formats for many different use cases. It has built-in support for many existing log formats, including popular services like: * [MySQL](/send-data/logs/structured/mysql/) * [PostgresSQL](/send-data/logs/structured/postgresql/) * [Nginx](/send-data/logs/structured/nginx/) * Mongo * ArangoDB It also has support for common data formats that many services and applications use or can be configured to use: * [JSON](/send-data/logs/structured/json/) * [Regex](/send-data/logs/unstructured/honeytail-regex/) * CSV * KeyVal * Syslog ## Reading from Standard Input (stdin) Honeytail can read directly from standard input (stdin) by setting the file as `-`. In this example, the `honeytail` invocation uses standard input as the data source: ```shell theme={} honeytail \ -c /etc/honeytail/honeytail.conf \ --file=- ``` ## Backfilling Existing Data If you have events in older log files that you would like to load into Honeycomb, use `honeytail` with the `--backfill` option. Honeytail does not unzip log files, so you will need to do this before backfilling. Here is an example `honeytail` invocation to pull in multiple existing logs and as much as the current log as possible. ```shell theme={} honeytail \ -c /etc/honeytail/honeytail.conf \ --file=/var/log/app/myapp.log.* \ --file=/var/log/app/myapp.log \ --backfill ``` Let us break down the various parts of this command: * `--parser=json`: For the purposes of this example, all logs are already JSON formatted. Take a look at [the timestamp section](/send-data/logs/structured/json/#timestamp-parsing) of the JSON connector to make sure your historical logs have their times interpreted correctly. * `--file=/var/log/app/myapp.log.*`: Honeycomb understands file globs and will ingest all of the files in series. * `--file=/var/log/app/myapp.log`: Specify the `--file` (or its short form, `-f`) as many times as necessary to include additional files that do not match a glob. Ingest as much of the current file as exists. * `--backfill`: This flag tells `honeytail` to read the specified files in their entirety, stop when finished reading, and to respond to rate limited responses ([HTTP 429](https://http.cat/429)) by slowing down the rate at which it sends events. Honeytail will read all the content in all the old logs and then stop. When it finishes, you are ready to send new log lines. By default, `honeytail` will keep track of its progress through a file, and if interrupted, will pick back up where it left off. By launching honeytail pointing at the main app log, it will find the state file it created while reading in the backlog and start up where it left off. Here is the second `honeytail` invocation, where it will tail the current log file and send in recent entries: ```shell theme={} honeytail \ --writekey=YOUR_API_KEY \ --parser=json \ --dataset='My App' \ --file=/var/log/app/myapp.log ``` ### Globs with Same File Names If using a glob that returns files with the same name in different directories, such as log files within multiple websites, use the `tail.hash_statefile_paths` option to ensure each tailed file gets its own state file. This option prevents a single state file from being used for multiple files, and avoids unnecessary file write contentions and load. ```shell theme={} honeytail \ --writekey=YOUR_API_KEY \ --parser=json \ --dataset='My App' \ --file=/var/www/*/log/daily/app.log --tail.hash_statefile_paths ``` ## Sampling High Volume Data Let us say you have an incredible volume of log content and your website gets hit frequently enough that you will still get excellent data quality even if you are only looking at 1/20th the traffic. Honeytail can sample the log file and for each 20 lines, only send one of them. It does so randomly, so you will not see every 20th line being sent - instead each line will have a 5% chance of being sent. When these log lines reach Honeycomb, they will include metadata indicating that each one represents 20 similar lines, so all your graphs will show accurate total counts. ```shell theme={} honeytail \ --writekey=YOUR_API_KEY \ --dataset='Webtier' \ --parser=nginx \ --file=/var/log/nginx/access.log \ --samplerate 20 \ --nginx.conf /etc/nginx/nginx.conf \ --nginx.format main ``` Adjusting the sample rate based on the content of your events can allow you to keep important infrequent events while discarding less important higher volume traffic. Honeytail has a dynamic sampler that will vary the sample rate based on the contents of the fields of your choice - more frequent occurrences of the content of the field will be sampled more heavily. For example, suppose that successful web traffic (HTTP status codes in the 200 range) is much more frequent than errored traffic (status codes in the 500s) - you might want to discard more of the successful traffic and keep more of the errored traffic. Applying the dynamic sampler to the `status` field in your nginx traffic will have this effect. The actual sample rate applied will vary based on the cardinality of the chosen field and the frequency of each value, but it will be in the ballpark of the `samplerate` specified. ```shell theme={} honeytail \ --writekey=YOUR_API_KEY \ --dataset='Webtier' \ --parser=nginx \ --file=/var/log/nginx/access.log \ --samplerate 20 \ --nginx.conf /etc/nginx/nginx.conf \ --nginx.format main \ --dynsampling status ``` You can specify the `dynsampling` flag multiple times and it will sample traffic based on the frequency and uniqueness of concatenating all the values of the fields you specify. ## Sampling Deterministically In addition to static and dynamic sampling support, Honeytail also has support for sampling data deterministically based on the value of a field. This is useful for making sampling decisions based on properties like a request ID or trace ID. Approximately 1/N events will be sampled (where N is the sample rate), and any events, which have the same value for the field passed to the `--deterministic_sampling` flag, will be sampled consistently. This flag must be used with `--samplerate` to specify the sampling rate. ```shell theme={} honeytail \ --writekey=YOUR_API_KEY \ --dataset='Deterministically Sampled Nginx Logs' \ --parser=nginx \ --file=/var/log/nginx/access.log \ --deterministic_sampling request_id \ --samplerate 2 ``` For instance, in the above example, about half of the requests would be sampled and if another Honeytail instance were running elsewhere with the same settings for `--samplerate` and `--deterministic_sampling`, it would sample the same subset of requests. ## Adding Extra Information into Your Events It is not unusual for a log to omit interesting information like the name of the machine on which the process is running. After all, you are on that machine, right? Why would you add the hostname? Log transports like `rsyslog` will prepend logs with the hostname sending them, but if you are sending logs from each host, this data may not exist. Honeytail lets you add in extra fields to each event sent up to Honeycomb with the `--add_field` flag. For this example, let us assume that you have nginx running as a web server in both your production and staging environments. Your shell sets `$ENV` with the environment (prod or staging). Here is how to run `honeytail` to consume your nginx log and insert the hostname and environment along with each log line: ```shell theme={} honeytail \ --writekey=YOUR_API_KEY \ --dataset='Webtier' \ --parser=nginx \ --file=/var/log/nginx/access.log \ --nginx.conf /etc/nginx/nginx.conf \ --nginx.format main \ --add_field hostname=$(hostname) \ --add_field env=$ENV ``` When it comes time to add additional fields based on the **content** of your log file, it is time to invoke the data augmentation flag, `--da_map_file`. As an example, your log file might contain the IP address of the host connecting to this service, but you would really like to include the hostname in your events. Or your log file contains user ID and you would like to add user name and group. If you can build a map of source values to new fields, then you can use the `--da_map_file` flag to augment your data. As our example, let us add hostname and AWS availability zone to a log file that contains a IP addresses. The IP address is stored in a field called `ip_addr` in the events we are processing. The first step is to build a JSON file containing the name of the source column (`ip_addr`), and a map of values to new fields (`10.0.0.6` should add a field `hostname` with the value `app21` and `aws_az` of `c`, `10.0.0.7` has different fields). ```json theme={} { "ip_addr": { "10.0.0.6": { "hostname": "app21", "aws_az": "c" }, "10.0.0.7": { "hostname": "app32", "aws_az": "b" } } } ``` When the log parser comes across an event that has `"ip_addr":"10.0.0.6"`, it will add the two additional fields `"hostname":"app21","aws_az":"c"`. Note that additional source column names may be specified (each with their own translation map) by extending the content of the JSON map file. The recommended method to deploy this is to generate a map of all the values to the new fields that should be added and distribute it to all the hosts that will be running Honeytail. Example use cases: * a mysql slow query log includes the IP address of the client; translate those IP addresses to names and host groups to identify unexpected servers connecting to your database * ssh can log the fingerprint of the key used to authenticate; distribute a mapping of key fingerprint to key owners to make it easier to see who is logging in to what servers * different users are sharded to different backend clusters; use the authenticated user ID to add information about which shard they are on, making it easier to spot problems that are localized to individual shards ## Dropping or Scrubbing Fields Sometimes you will have fields in your log file that you do not want to send to Honeycomb or that you want to obscure before letting them leave your servers. For this example, let us say that you have in your log a large text field with the contents of an email. It is large enough that you do not want it sent up to Honeycomb. Also in this log you have a some sensitive information like a person's birthday. You want to be able to ask questions about the most common birthdays, but you do not want to expose the actual birthdays outside your infrastructure. Honeytail has two flags that will help you accomplish these goals. `--drop_field` will remove a field before sending the event to Honeycomb and `--scrub_field` will subject the value of a field to a SHA256 hash before sending it along. You will still be able to do inclusion and frequency analysis on the hashed fields (as there will be a 1-1 mapping of value to hashed value) but the actual value will be obscured. Here is your honeytail invocation: ```shell theme={} honeytail \ --writekey=YOUR_API_KEY \ --dataset='My App' \ --parser=json \ --file=/var/log/app/myapp.log \ --drop_field email_content \ --scrub_field birthday ``` ## Versioning `honeytail` Configuration ### Convert Command Lines to YAML Configuration The `honeytail` binary supports reading its configuration from a YAML configuration file, as well as command line arguments. To get started, if you have already been using a few command line arguments, add an additional flag: `--write_current_yaml`. This flag will write your command line configuration as YAML to `STDOUT` so you can use it as a starting point. ```shell theme={} honeytail \ -p mysql \ -k YOUR_API_KEY \ -d YOUR_DATASET \ -f ./mysql-slow.log \ --mysql.host=my.fake.host.com \ --write_current_yaml > ./scrubbed_mysql.yaml ``` Display the output captured in `scrubbed_mysql.yaml`. ```shell theme={} cat ./scrubbed_mysql.yaml apihost: https://api.honeycomb.io/ # or if on our EU instance, https://api.eu1.honeycomb.io samplerate: 1 poolsize: 80 send_frequency_ms: 100 send_batch_size: 50 status_interval: 60 request_parse_query: whitelist dynsample_window: 30 dynsample_minimum: 1 required_options: parsername: mysql writekey: YOUR_API_KEY logfiles: - ./mysql-slow.log dataset: YOUR_DATASET mysql: host: my.fake.host.com user: "" pass: "" queryinterval: 0 ``` This flag can be particularly useful for versioning or productionizing `honeytail` use, or for providing additional configuration when using advanced `honeytail` features, like [scrubbing sensitive fields](#dropping-or-scrubbing-fields) or parsing custom URL structures. ### Convert from an INI configuration to YAML Previous versions of `honeytail` used the INI file format (`.ini`) for configuration, but this is now deprecated. To create a YAML configuration file that is equivalent to an existing INI configuration, use this command with your `.ini` configuration file name: ```shell theme={} honeytail --config EXISTING_CONFIG_FILENAME --write_current_yaml ``` This command will write the YAML for your current configuration file to `STDOUT`. ### Using a Configuration File Once the configuration file is created, run `honeytail` with a `--config_yaml` argument in lieu of all of the other flags: ```shell theme={} honeytail --config_yaml ./scrubbed_mysql.yaml ``` ### Notes on Using YAML Configuration * When using YAML configuration, any configuration flags specified on the command line are ignored. * The names of fields in the YAML file are the same "long" names you see in the Honeytail help file. For example, `honeytail -h` * Any field with help that notes "May have multiple values" is specified in YAML as an array. For example: ```yaml theme={} scrub_field: - field_name_1 - field_name_2 ``` * Any values with dotted names in help are specified as YAML objects, with appropriate indentation. For example, `--mysql.host=my.fake.host.com` becomes: ```yaml theme={} mysql: host: my.fake.host.com user: "" pass: "" queryinterval: 0 ``` ## Parsing URL Patterns `honeytail` can break URLs up into their component parts, storing extra information in additional columns. This behavior is turned on by default for the `request` field on `nginx` datasets, but can become more useful with a little bit of guidance from you. There are several flags that adjust the behavior of `honeytail` as it breaks apart URLs. ### Identifying the URL Field When using the `nginx` parser, `honeytail` looks for a field named `request`. When using a different parser (such as the [JSON](/send-data/logs/structured/json/) parser), you should specify the name of the field that contains the URL with the `--request_shape` flag. Using this flag creates a few generated fields. Given a `request` field containing a value like: ```nginx theme={} GET /alpha/beta/gamma?foo=1&bar=2 HTTP/1.1 ``` ... will produce `nginx` events for Honeycomb that look like: | field name | value | description | | :------------------------- | :------------------------------------------ | :------------------------------------------------------- | | request | GET /alpha/beta/gamma?foo=1\&bar=2 HTTP/1.1 | the full original request | | request\_method | GET | the HTTP method, if it exists | | request\_protocol\_version | HTTP/1.1 | the HTTP version string | | request\_uri | /alpha/beta/gamma?foo=1\&bar=2 | the unmodified URL (not including the method or version) | | request\_path | /alpha/beta/gamma | just the path portion of the URL | | request\_query | foo=1\&bar=2 | just the query string portion of the URL | | request\_shape | /alpha/beta/gamma?foo=?\&bar=? | a normalized version of the URL | | request\_pathshape | /alpha/beta/gamma | a normalized version of the path portion of the URL | | request\_queryshape | foo=?\&bar=? | a normalized version of the query portion of the URL | (The generated fields will all be prefixed by the field name specified by `--request_shape`— in the above example `request`. Use the `--shape_prefix` field to prepend an additional string to these generated fields.) If the URL field contains just the URL, the `request_method` and `request_protocol_version` fields will be omitted. ### URL Normalization The path portion of the URL (from the beginning `/` up to the `?` that separates the path from the query) can be grouped by common patterns, as is common for REST interfaces. For example, given a URL fragments like: ```url theme={} /books/978-0812536362 /books/978-9995788940 ``` We can break the fragments into a field containing the generic endpoint (`/books/:isbn`) and a separate field for the ISBN number itself by specifying a `--request_pattern` flag: ```shell theme={} honeytail ... \ # other arguments --parser=nginx \ --request_pattern=/books/:isbn ``` This will produce, among other fields: | request\_path | request\_shape | request\_path\_isbn | (other fields) | | :-------------------- | :------------- | :------------------ | :------------- | | /books/978-0812536362 | /books/:isbn | 978-0812536362 | ... | | /books/978-9995788940 | /books/:isbn | 978-9995788940 | ... | You can specify multiple `--request_pattern` flags and they will be considered in order. The first one to match a URL will be used. Patterns should represent the entire path portion of the URL - include a "\*" at the end to match arbitrary additional segments. For example, if we have a wider variety of URL fragments, like: ```url theme={} /books/978-0812536362 /books/978-3161484100/borrow /books/978-9995788940 /books/978-9995788940/borrow ``` We can provide our additional `--request_pattern` flags and track a wider variety of `request_shape`s: ```shell theme={} honeytail ... \ # other arguments --parser=nginx \ --request_pattern=/books/:isbn/borrow --request_pattern=/books/:isbn ``` We will see our `request_path_isbn` populated as before, as the `:isbn` parameter is respected in both patterns: | request\_path | request\_shape | request\_path\_isbn | (other fields) | | :--------------------------- | :------------------ | :------------------ | :------------- | | /books/978-0812536362 | /books/:isbn | 978-0812536362 | ... | | /books/978-3161484100/borrow | /books/:isbn/borrow | 978-3161484100 | ... | | /books/978-9995788940 | /books/:isbn | 978-9995788940 | ... | | /books/978-9995788940/borrow | /books/:isbn/borrow | 978-9995788940 | ... | A URL's query string can be broken apart similarly, with the `--request_query_keys` flag, with generated fields named like `_query_`. If, on top of our previous examples, our URL fragments had query strings like: ```url theme={} /books/978-0812536362?borrower_id=23597 ``` Providing `--request_query_keys=borrower_id` would return us a Honeycomb event with a `request_query_borrower_id` field with a value of `23597`. If you would like to automatically create a field for every key in the query string, you can use the flag `--request_parse_query=all`. This will automatically create a new field `_query_` for every query parameter encountered in the query string. For any publicly accessible web server, it is likely that this will quickly create many useless columns because of all the random traffic on the internet. For more detail and examples, see our [urlshaper](https://github.com/honeycombio/urlshaper) package on GitHub. # Send JSON Logs Source: https://docs.honeycomb.io/send-data/logs/structured/json Ingest and backfill JSON log files into Honeycomb using Honeytail. Learn how Honeycomb handles nested JSON structures. Learn how to use Honeytail to send JSON logs directly to Honeycomb. ## Data Expectations Honeycomb expects data with a flat structure. By default, any structure deeper than top level keys will be serialized and a string representation of the content will be used in the field. However, Honeycomb can automatically unpack nested JSON objects and flatten them into unique columns. This is a per-dataset setting, and it is off by default. You must be a team owner to change this setting. If you enable this setting, nested objects will be flattened with new fields and field names created based on the keys. For example, `{"outer": {"inner": 42}}` would become a field `outer.inner` with a value of 42. To tell Honeycomb to automatically unpack JSON objects: 1. In the left navigation menu, select **Manage Data**. 2. In the list, locate and select **Datasets** and select the dataset you want to configure. 3. Select the **Schema** view. 4. Enable the **Automatically unpack non-OpenTelemetry nested JSON** toggle. 5. Select your preferred **Maximum unpacking depth** for your data. Changes to this setting take effect within 60 seconds. If your objects are deeply-nested, unpacking may result in a very large number of columns in Honeycomb. Consider unpacking only to the level of columns you will find useful. Any objects nested more deeply than the depth you select here will be converted to strings under the last unpacked column. In particular, if nested structures in your data can be created/added by your users (for example, HTTP headers), consider not unpacking them to that level. ## Installation Download and install the latest `honeytail` by running: Download the `honeytail_1.10.0_amd64.deb` package. ```shell theme={} wget -q https://honeycomb.io/download/honeytail/v1.10.0/honeytail_1.10.0_amd64.deb ``` Verify the package. ```shell theme={} echo '3db441215f97eaed068aa0531c986cf5405957e3e8e26b22c16b571091caf917 honeytail_1.10.0_amd64.deb' | sha256sum -c ``` Install the package. ```shell theme={} sudo dpkg -i honeytail_1.10.0_amd64.deb ``` The packages install `honeytail`, its config file `/etc/honeytail/honeytail.conf`, and some start scripts. Build `honeytail` from source if you need it in an unpackaged form or for ad-hoc use. Download the `honeytail_1.10.0_arm64.deb` package. ```shell theme={} wget -q https://honeycomb.io/download/honeytail/v1.10.0/honeytail_1.10.0_arm64.deb ``` Verify the package. ```shell theme={} echo '4220756e5a941cde6a484cb4cfde184eb189aaf29170df301a874eb143e960ed honeytail_1.10.0_arm64.deb' | sha256sum -c ``` Install the package. ```shell theme={} sudo dpkg -i honeytail_1.10.0_arm64.deb ``` The packages install `honeytail`, its config file `/etc/honeytail/honeytail.conf`, and some start scripts. Build `honeytail` from source if you need it in an unpackaged form or for ad-hoc use. Download the `honeytail_1.10.0-1.x86_64.rpm` package. ```shell theme={} wget -q https://honeycomb.io/download/honeytail/v1.10.0/honeytail_1.10.0-1.x86_64.rpm ``` Verify the package. ```shell theme={} echo 'b23215a9301b20b2e2262a0823c9e761e8b57e1a62fd5cec35f697fce41fa863 honeytail_1.10.0-1.x86_64.rpm' | sha256sum -c ``` Install the package. ```shell theme={} sudo rpm -i honeytail_1.10.0-1.x86_64.rpm ``` The packages install `honeytail`, its config file `/etc/honeytail/honeytail.conf`, and some start scripts. Build `honeytail` from source if you need it in an unpackaged form or for ad-hoc use. Download the 1.10.0 binary. ```shell theme={} wget -q -O honeytail https://honeycomb.io/download/honeytail/v1.10.0/honeytail-linux-amd64 ``` Verify the binary. ```shell theme={} echo 'c9cc7dd1aa2b12afeb30b089061870f3407d2df0119e7c2807fec648b603e2d5 honeytail' | shasum -a 256 -c ``` Set the permissions to allow execution. ```shell theme={} chmod 755 ./honeytail ``` Download the 1.10.0 binary. ```shell theme={} wget -q -O honeytail https://honeycomb.io/download/honeytail/v1.10.0/honeytail-linux-arm64 ``` Verify the binary. ```shell theme={} echo '1dd37227788548c4ed44592554e3c90e374c4d796c444dde9f372db8618bc7fa honeytail' | shasum -a 256 -c ``` Set the permissions to allow execution. ```shell theme={} chmod 755 ./honeytail ``` Download the 1.10.0 binary. ```shell theme={} wget -q -O honeytail https://honeycomb.io/download/honeytail/v1.10.0/honeytail-darwin-amd64 ``` Verify the binary. ```shell theme={} echo '9a3da0f48fe21b1e610ac6b63130dfb8118a9a0ec16abae13350edba02d85e4d honeytail' | shasum -a 256 -c ``` Set the permissions to allow execution. ```shell theme={} chmod 755 ./honeytail ``` Clone the [Honeytail](https://github.com/honeycombio/honeytail) repository. ```shell theme={} git clone https://github.com/honeycombio/honeytail ``` Install from source. ```shell theme={} cd honeytail; go install ``` You should modify the config file and uncomment and set: * `ParserName` to `json` * `WriteKey` to your API key, available from [the account page](https://ui.honeycomb.io/account) * `LogFiles` to the path for the log file you want to ingest, or `-` for stdin * `Dataset` to the name of the dataset you wish to create with this log file. ## Launch the Agent Start up a `honeytail` process using `upstart` or `systemd` or by launching the process by hand. This will tail the log file specified in the config and leave the process running as a daemon. ```shell theme={} sudo initctl start honeytail ``` ```shell theme={} sudo systemctl start honeytail ``` ```shell theme={} honeytail -c /etc/honeytail/honeytail.conf ``` ## Backfilling Archived Logs To backfill existing data, run `honeytail` with `--backfill` the first time: ```shell theme={} honeytail -c /etc/honeytail/honeytail.conf \ --file /var/log/myapp/log12.json \ --backfill ``` This command can also be used at any point to backfill from older, rotated log files. You can read more about our [backfill behavior here](/send-data/logs/structured/honeytail/). If you have chosen to backfill from old JSON logs, do not forget to transition into the default streaming behavior to stream live logs to Honeycomb! ## Timestamp Parsing Honeycomb expects all events to contain a timestamp field; if one is not provided, the server will associate the current time of ingest with the given payload. By default, we look for a few candidate fields based on name (`"timestamp"`, `"time"`) and handle the following time formats: * RFC3339 (`2006-01-02T15:04:05Z07:00`) * RFC3339 with nanoseconds (`2006-01-02T15:04:05.999999999Z07:00`) * Unix string representation (`Mon Jan 2 15:04:05 MST 2006`) * Ruby string representation (`Mon Jan 02 15:04:05 -0700 2006`) * Golang string representation (`2006-01-02 15:04:05.999999999 -0700 MST`) If your timestamps are not correctly handled by the above formats, use the `--json.timefield` and `--json.format` flags to help `honeytail` understand where and how to extract the event's timestamp. For example, given a JSON log file with events like the following: ```javascript theme={} {"color":"orange","size":3,"server_time":"Aug 12 2016, 15:12:06 -0800"} {"color":"blue","server_time":"Sep 01 2016, 06:10:32 -0800","size":4} ``` The command to consume those log lines (while retaining the `"server_time"` field as the event's timestamp) would look something like: ```shell theme={} honeytail --writekey=YOUR_API_KEY --dataset="API Server Logs" --parser=json \ --file=/var/log/api_server.log \ --json.timefield="server_time" --json.format="%b %d %Y, %k:%M:%S %z" ``` The `--json.timefield="server_time"` argument tells `honeytail` to consider the `"server_time"` value to be the canonical timestamp for the events in the specified file. The `--json.format` argument specifies the timestamp format to be used while parsing. (It understands common [`strftime`](https://www.strfti.me/) formats.) Ultimately, the above command would would produce events with the fields (note the times below are represented in UTC; Honeycomb parses time zone information if provided). | time | color | size | | :------------------- | :----- | :--- | | 2016-08-12T23:12:06Z | orange | 3 | | 2016-09-01T14:10:32Z | blue | 4 | # Send MySQL Logs Source: https://docs.honeycomb.io/send-data/logs/structured/mysql Parse MySQL logs with Honeytail and send them to Honeycomb to analyze database query patterns, slow queries, and traffic across your application. Our connector pulls your MySQL logs into Honeycomb for analysis, so you can analyze MySQL traffic on your machines and finally get a quick handle on the database queries triggered by your application logic. It surfaces attributes like: * The **normalized** query shape * Time spent waiting to acquire lock * Number of rows examined to execute the query * Number of rows returned by MySQL * ... and more! Honeycomb is unique in its ability to calculate metrics and statistics on the fly, while retaining the full-resolution log lines (and the original MySQL query that started it all!). Once you have got data flowing, be sure to take a look at our starter queries! Our entry points will help you see how we recommend comparing lock retention by normalized query, scan efficiency by collection, or read vs. write distribution by host. This document is for running **MySQL directly**. If running [MySQL on RDS](https://aws.amazon.com/rds/mysql/), Honeycomb offers support for ingesting RDS MySQL logs via [CloudWatch Logs](/send-data/aws/aws-cloudformation/) with the option to convert these unstructured logs into structured logs. The agent used to translate logs to events and send them to Honeycomb is called `honeytail`. ## Configure MySQL Query Logging Before running `honeytail`, you will want to turn slow query logging on for all queries if possible. To turn on slow query logging for your MySQL host, run the following in your MySQL shell: ```mysql theme={} mysql> SET GLOBAL slow_query_log = 'ON'; ``` Set the threshold for a query to be considered a "slow" query to `0` (the default is `10`): ```mysql theme={} mysql> SET GLOBAL long_query_time = 0; ``` And verify the slow query log's location via: ```mysql theme={} mysql> SELECT @@GLOBAL.slow_query_log_file; ``` If this technique is a problem for you—specifically, you do not want to rely on slow query log output—let us know! We have got something in the works that might satisfy your needs. ## Install and Run Honeytail On your MySQL host, download and install the latest `honeytail` by running: Download the `honeytail_1.10.0_amd64.deb` package. ```shell theme={} wget -q https://honeycomb.io/download/honeytail/v1.10.0/honeytail_1.10.0_amd64.deb ``` Verify the package. ```shell theme={} echo '3db441215f97eaed068aa0531c986cf5405957e3e8e26b22c16b571091caf917 honeytail_1.10.0_amd64.deb' | sha256sum -c ``` Install the package. ```shell theme={} sudo dpkg -i honeytail_1.10.0_amd64.deb ``` The packages install `honeytail`, its config file `/etc/honeytail/honeytail.conf`, and some start scripts. Build `honeytail` from source if you need it in an unpackaged form or for ad-hoc use. Download the `honeytail_1.10.0_arm64.deb` package. ```shell theme={} wget -q https://honeycomb.io/download/honeytail/v1.10.0/honeytail_1.10.0_arm64.deb ``` Verify the package. ```shell theme={} echo '4220756e5a941cde6a484cb4cfde184eb189aaf29170df301a874eb143e960ed honeytail_1.10.0_arm64.deb' | sha256sum -c ``` Install the package. ```shell theme={} sudo dpkg -i honeytail_1.10.0_arm64.deb ``` The packages install `honeytail`, its config file `/etc/honeytail/honeytail.conf`, and some start scripts. Build `honeytail` from source if you need it in an unpackaged form or for ad-hoc use. Download the `honeytail_1.10.0-1.x86_64.rpm` package. ```shell theme={} wget -q https://honeycomb.io/download/honeytail/v1.10.0/honeytail_1.10.0-1.x86_64.rpm ``` Verify the package. ```shell theme={} echo 'b23215a9301b20b2e2262a0823c9e761e8b57e1a62fd5cec35f697fce41fa863 honeytail_1.10.0-1.x86_64.rpm' | sha256sum -c ``` Install the package. ```shell theme={} sudo rpm -i honeytail_1.10.0-1.x86_64.rpm ``` The packages install `honeytail`, its config file `/etc/honeytail/honeytail.conf`, and some start scripts. Build `honeytail` from source if you need it in an unpackaged form or for ad-hoc use. Download the 1.10.0 binary. ```shell theme={} wget -q -O honeytail https://honeycomb.io/download/honeytail/v1.10.0/honeytail-linux-amd64 ``` Verify the binary. ```shell theme={} echo 'c9cc7dd1aa2b12afeb30b089061870f3407d2df0119e7c2807fec648b603e2d5 honeytail' | shasum -a 256 -c ``` Set the permissions to allow execution. ```shell theme={} chmod 755 ./honeytail ``` Download the 1.10.0 binary. ```shell theme={} wget -q -O honeytail https://honeycomb.io/download/honeytail/v1.10.0/honeytail-linux-arm64 ``` Verify the binary. ```shell theme={} echo '1dd37227788548c4ed44592554e3c90e374c4d796c444dde9f372db8618bc7fa honeytail' | shasum -a 256 -c ``` Set the permissions to allow execution. ```shell theme={} chmod 755 ./honeytail ``` Download the 1.10.0 binary. ```shell theme={} wget -q -O honeytail https://honeycomb.io/download/honeytail/v1.10.0/honeytail-darwin-amd64 ``` Verify the binary. ```shell theme={} echo '9a3da0f48fe21b1e610ac6b63130dfb8118a9a0ec16abae13350edba02d85e4d honeytail' | shasum -a 256 -c ``` Set the permissions to allow execution. ```shell theme={} chmod 755 ./honeytail ``` Clone the [Honeytail](https://github.com/honeycombio/honeytail) repository. ```shell theme={} git clone https://github.com/honeycombio/honeytail ``` Install from source. ```shell theme={} cd honeytail; go install ``` Make sure you have enabled [MySQL query logging](#configure-mysql-query-logging) before running `honeytail`. To consume the current MySQL slow query log from the beginning, run: ```shell theme={} honeytail --writekey=YOUR_API_KEY --dataset=MySQL --parser=mysql \ --file=/usr/local/var/mysql/myhost-slow.log \ --tail.read_from=beginning ``` ## Troubleshooting Check out [`honeytail` Troubleshooting](/troubleshoot/common-issues/sending-data/#honeytail) for debugging tips. ## Run Honeytail Continuously To run `honeytail` continuously as a daemon process, first modify the config file `/etc/honeytail/honeytail.conf` and uncomment and set: * `ParserName` to `mysql` * `WriteKey` to your API key, available from [the account page](https://ui.honeycomb.io/account) * `LogFiles` to the path for your MySQL slow query log file, often located at `/usr/local/var/mysql/myhost-slow.log` * `Dataset` to the name of the dataset you wish to create with this log file. Then start `honeytail` using `upstart` or `systemd`: ```shell theme={} sudo initctl start honeytail ``` ```shell theme={} sudo systemctl start honeytail ``` ## Backfill Archived Logs You may have archived logs that you would like to import into Honeycomb. If you have a MySQL logfile located at `/usr/local/var/mysql/myhost-slow.16.log`, you can backfill using this command: ```shell theme={} honeytail --writekey=YOUR_API_KEY --dataset=MySQL --parser=mysql \ --file=/usr/local/var/mysql/myhost-slow.16.log \ --backfill ``` This command can be used at any point to backfill from archived log files. You can read more about `honeytail`'s backfill behavior [here](/send-data/logs/structured/honeytail/#backfilling-existing-data). `honeytail` does not unzip log files, so you will need to do this before backfilling. Once you have finished backfilling your old logs, we recommend transitioning to the default streaming behavior to stream live logs to Honeycomb. ## Scrub Personally Identifiable Information While we believe strongly in the value of being able to track down the precise query causing a problem, we understand the concerns of exporting log data, which may contain sensitive user information. With that in mind, we recommend using `honeytail`'s MySQL parser, but adding a `--scrub_field=query` flag to hash the concrete `query` value. The `normalized_query` attribute will still be representative of the **shape** of the query, and identifying patterns including specific queries will still be possible—but the sensitive information will be completely obscured before leaving your servers. More information about dropping or scrubbing sensitive fields can be [found here](/send-data/logs/structured/honeytail/#dropping-or-scrubbing-fields). ## Example Extracted MySQL Fields Ingesting a MySQL log line (resulting from a `SELECT` with a `JOIN`): ```mysql theme={} # Time: 161019 18:30:00 # User@Host: rdsadmin[rdsadmin] @ localhost [127.0.0.1] Id: 1 # Query_time: 1.294391 Lock_time: 0.000119 Rows_sent: 4049 Rows_examined: 4049 SET timestamp=1476901800; SELECT teams.* FROM teams INNER JOIN users_teams ON team_id=teams.id WHERE user_id=21782 AND slug='foobar' LIMIT 1 ``` will produce an event for Honeycomb that looks like: | field name | value | type | | :---------------- | :----- | :------------------------------------------------------------------------------------------------------------------- | | client | string | localhost | | client\_ip | string | 127.0.0.1 | | lock\_time | float | 0.000119 | | normalized\_query | string | `select teams._ from teams inner join users_teams on team_id = teams.id where user_id = ? and slug = ? limit ?` | | query | string | `SELECT teams.* FROM teams INNER JOIN users_teams ON team_id=teams.id WHERE user_id=21782 AND slug='foobar' LIMIT 1` | | query\_time | float | 1.294391 | | rows\_examined | float | 4049 | | rows\_sent | float | 4049 | | statement | string | select | | tables | string | teams users\_teams | | user | string | rdsadmin | Numbers are ingested as floats by default in Honeycomb, though you can coerce a field to integers in the Schema section of your dataset's Overview. You can find more on our MySQL query normalization in [our `mysqltools` repository](https://github.com/honeycombio/mysqltools). ## Open Source [Honeytail](https://github.com/honeycombio/honeytail) is open source and Apache 2.0 licensed. # Send NGINX Logs Source: https://docs.honeycomb.io/send-data/logs/structured/nginx Parse NGINX logs with Honeytail and send them to Honeycomb to analyze web traffic, request patterns, and service activity across your infrastructure. NGINX is one of the most popular web servers today. In a world driven by the web and connected APIs, its logs are a great candidate for surfacing a birds' eye view of activity in your service. Explore the [Honeytail NGINX Example App](https://github.com/honeycombio/honeytail/tree/main/examples/nginx) and read the [blog post with user tips on sending NGINX logs to Honeycomb](https://www.honeycomb.io/blog/sending-nginx-logs-honeycomb). ## Setup Capturing web logs for Honeycomb requires: 1. installing our agent, `honeytail` 2. configuring it to parse your NGINX logs correctly 3. launching honeytail ### Install the Agent Download and install the latest `honeytail` by running: Download the `honeytail_1.10.0_amd64.deb` package. ```shell theme={} wget -q https://honeycomb.io/download/honeytail/v1.10.0/honeytail_1.10.0_amd64.deb ``` Verify the package. ```shell theme={} echo '3db441215f97eaed068aa0531c986cf5405957e3e8e26b22c16b571091caf917 honeytail_1.10.0_amd64.deb' | sha256sum -c ``` Install the package. ```shell theme={} sudo dpkg -i honeytail_1.10.0_amd64.deb ``` The packages install `honeytail`, its config file `/etc/honeytail/honeytail.conf`, and some start scripts. Build `honeytail` from source if you need it in an unpackaged form or for ad-hoc use. Download the `honeytail_1.10.0_arm64.deb` package. ```shell theme={} wget -q https://honeycomb.io/download/honeytail/v1.10.0/honeytail_1.10.0_arm64.deb ``` Verify the package. ```shell theme={} echo '4220756e5a941cde6a484cb4cfde184eb189aaf29170df301a874eb143e960ed honeytail_1.10.0_arm64.deb' | sha256sum -c ``` Install the package. ```shell theme={} sudo dpkg -i honeytail_1.10.0_arm64.deb ``` The packages install `honeytail`, its config file `/etc/honeytail/honeytail.conf`, and some start scripts. Build `honeytail` from source if you need it in an unpackaged form or for ad-hoc use. Download the `honeytail_1.10.0-1.x86_64.rpm` package. ```shell theme={} wget -q https://honeycomb.io/download/honeytail/v1.10.0/honeytail_1.10.0-1.x86_64.rpm ``` Verify the package. ```shell theme={} echo 'b23215a9301b20b2e2262a0823c9e761e8b57e1a62fd5cec35f697fce41fa863 honeytail_1.10.0-1.x86_64.rpm' | sha256sum -c ``` Install the package. ```shell theme={} sudo rpm -i honeytail_1.10.0-1.x86_64.rpm ``` The packages install `honeytail`, its config file `/etc/honeytail/honeytail.conf`, and some start scripts. Build `honeytail` from source if you need it in an unpackaged form or for ad-hoc use. Download the 1.10.0 binary. ```shell theme={} wget -q -O honeytail https://honeycomb.io/download/honeytail/v1.10.0/honeytail-linux-amd64 ``` Verify the binary. ```shell theme={} echo 'c9cc7dd1aa2b12afeb30b089061870f3407d2df0119e7c2807fec648b603e2d5 honeytail' | shasum -a 256 -c ``` Set the permissions to allow execution. ```shell theme={} chmod 755 ./honeytail ``` Download the 1.10.0 binary. ```shell theme={} wget -q -O honeytail https://honeycomb.io/download/honeytail/v1.10.0/honeytail-linux-arm64 ``` Verify the binary. ```shell theme={} echo '1dd37227788548c4ed44592554e3c90e374c4d796c444dde9f372db8618bc7fa honeytail' | shasum -a 256 -c ``` Set the permissions to allow execution. ```shell theme={} chmod 755 ./honeytail ``` Download the 1.10.0 binary. ```shell theme={} wget -q -O honeytail https://honeycomb.io/download/honeytail/v1.10.0/honeytail-darwin-amd64 ``` Verify the binary. ```shell theme={} echo '9a3da0f48fe21b1e610ac6b63130dfb8118a9a0ec16abae13350edba02d85e4d honeytail' | shasum -a 256 -c ``` Set the permissions to allow execution. ```shell theme={} chmod 755 ./honeytail ``` Clone the [Honeytail](https://github.com/honeycombio/honeytail) repository. ```shell theme={} git clone https://github.com/honeycombio/honeytail ``` Install from source. ```shell theme={} cd honeytail; go install ``` You should modify the config file and uncomment and set: * `ParserName` to `nginx` * `WriteKey` to your API key, available from [the account page](https://ui.honeycomb.io/account) * `LogFiles` to the path for the log file you want to ingest. For NGINX, this is typically `/var/log/nginx/access.log`. * `Dataset` to the name of the dataset you wish to create with this log file. Honeytail also supports [configuration with YAML](/send-data/logs/structured/honeytail/#convert-command-lines-to-yaml-configuration). ### Identify Log Locations + Formats Make sure to run through [Optional Configuration](#optional-configuration) below before running `honeytail`, in order to get the richest metadata out of your web traffic and into your logs. In addition to the standard configuration captured in `/etc/honeytail/honeytail.conf`, you will want to set the two options in the `Nginx Parser Options` section: * `ConfigFile`: the path to your NGINX config file: whichever part of it contains the definition for the log format * `LogFormatName`: the name of the log format used to produce the NGINX access log file For example, if your nginx config file is at `/etc/nginx/nginx.conf` and has the following snippet: ```nginx theme={} log_format my_favorite_format '$remote_addr - $remote_user [$time_local] "$request" $status $bytes_sent'; access_log /var/log/nginx/access.log my_favorite_format; ``` ... then `ConfigFile` should be set to `/etc/nginx/nginx.conf` and your `LogFormatName` value should be set to `my_favorite_format`. Or configure `honeytail` to read the nginx logs using command line parameters: ```shell theme={} honeytail \ --parser=nginx \ --dataset=examples.honeytail-nginx \ --writekey=$HONEYCOMB_WRITE_KEY \ --nginx.conf=/etc/nginx/nginx.conf \ --nginx.format=my_favorite_format \ --file=/var/log/nginx/access.log ``` ### Launch the Agent Start up a `honeytail` process using `upstart` or `systemd` or by launching the process by hand. ```shell theme={} sudo initctl start honeytail ``` ```shell theme={} sudo systemctl start honeytail ``` ```shell theme={} honeytail -c /etc/honeytail/honeytail.conf ``` ## Backfilling Archived Logs In addition to getting current logs flowing, you can backfill old logs into Honeycomb to kickstart your dataset. By running `honeytail` from the command line, you can import old logs separate from tailing your current logs. Adding the `--backfill` flag to `honeytail` adjusts a number of settings to make it appropriate for backfilling old data, such as stopping when it gets to the end of the log file instead of the default behavior of waiting for new content (like `tail`). The specific locations on your system may vary from ours, but once you fill in your system's values instead of our examples, you can backfill using this command: ```shell theme={} honeytail --writekey=YOUR_API_KEY --dataset="nginx API logs" --parser=nginx \ --file=/var/log/nginx/access.16.log \ --nginx.conf=/etc/nginx/nginx.conf \ --nginx.format=api_fmt \ --backfill ``` This command can be used at any point to backfill from archived log files. You can read more about our [agent honeytail](/send-data/logs/structured/honeytail/) or its [backfill behavior](/send-data/logs/structured/honeytail/#backfilling-existing-data) here. `honeytail` does not unzip log files, so you will need to do this before backfilling. Easiest way—pipe to STDIN: `zcat *.gz | honeytail --file - --backfill --all-the-other-flags.` ## Troubleshooting Check out [`honeytail` Troubleshooting](/troubleshoot/common-issues/sending-data/#honeytail) for debugging tips. ## Optional Configuration Nginx logs can be an incredibly powerful, high-level view of your system—especially so if they are configured correctly and enriched with custom, application-specific information about each request. Below are two simple ways to pack those logs with more useful metadata. ### Missing Default Options Nginx comes with some fairly powerful optional log fields that are not included by default. This is the `log_format` we recommend for any configuration file (note the extra quotes around some fields): ```nginx theme={} log_format combined '$remote_addr - $remote_user [$time_local] $host ' '"$request" $status $bytes_sent $body_bytes_sent $request_time ' '"$http_referer" "$http_user_agent" $request_length "$http_authorization" ' '"$http_x_forwarded_proto" "$http_x_forwarded_for" $server_name'; access_log /var/log/nginx/access.log combined; ``` You may already have an `access_log` line, but by defining a `log_format` (`combined`, in the example above) and specifying the format name (`--nginx.format=combined`), you will be able to take advantage of all of these additional fields. Make sure that all fields that start `$http_` are quoted in your `log_format`: * `$bytes_sent`: the size of the response sent back to the client, including headers * `$host`: the requested Host header, identifying how your server was addressed * `$http_authorization`: authorization headers, for associating logs with individual users (must be quoted) * `$http_referer`: the referring site, if the client followed a link to your site (must be quoted) * `$http_user_agent`: the User-Agent header, useful in identifying your clients (must be quoted) * `$http_x_forwarded_for`: the origin IP address, if running behind a load balancer (must be quoted) * `$http_x_forwarded_proto`: the origin protocol, if terminating TLS in front of nginx (must be quoted) * `$remote_addr`: the IP address of the host making the connection to nginx * `$remote_user`: the user name supplied when/if using basic authentication * `$request_id`: an nginx-generated unique ID to every request (only available in nginx version 1.11 and later). * `$request_length`: the length of the client's request, including headers and body * `$request_time`: the time (in ms) the server took to respond to the request * `$request`: the HTTP method, request path, and protocol version * `$server_name`: the hostname of the machine accepting the request * `$status`: the HTTP status code returned for this request ### Embedding Custom Response Headers Nginx can also be configured to extract custom request and response headers. Of the two, response headers are the most powerful in this case—they can carry application-specific IDs or timers back through to the nginx log. Having all of the information pertinent to a single request, available in a single log line, can be an incredibly powerful tool in diagnosing the origin of a problem in your system. To include a specific response header in your `access.log`, add an [`$upstream_http_`](https://nginx.org/en/docs/http/ngx_http_upstream_module.html#var_upstream_http_) variable to your `log_format`—the response header values will be written out and ingested by our nginx parser! Make sure to put quotes around these variables to capture any embedded spaces. For example, an `X-RateLimit-Remaining` header can be output by adding `$upstream_http_x_ratelimit_remaining` to the `log_format` line. See the nginx docs for more about [extracting metadata from the HTTP response](https://nginx.org/en/docs/http/ngx_http_upstream_module.html#variables) or [request](https://nginx.org/en/docs/http/ngx_http_core_module.html#var_http_). As with other fields which may output strings (for example,`$http_user_agent`), be careful when logging strings—add an extra set of double quotes around values which might contain spaces, in order to ensure correct parsing. **A final trick**: sometimes, response headers may be set for logging that should not be exposed back to the user. In this case, the [`proxy_hide_header`](https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_hide_header) directive may be used to strip out specific headers by name: ```nginx theme={} log_format combined `... "$upstream_x_internal_top_secret" ...`; # Wrap string values with double quotes access_log /var/log/nginx/access.log combined; location / { proxy_pass http://127.0.0.1:8080; # Expose port 8080 proxy_hide_header X-Internal-Top-Secret; # Strip from client } ``` ## Scrubbing Personally Identifiable Information While we believe strongly in the value of being able to track down the precise query causing a problem, we understand the concerns of exporting log data which may contain sensitive user information. With that in mind, we recommend using `honeytail`'s nginx parser, but adding a `--scrub_field=sensitive_field_name` flag to hash the concrete `sensitive_field_name` value, or `--drop_field=sensitive_field_name` to drop it altogether and prevent it being sent to Honeycomb's servers. Find [more information about dropping or scrubbing sensitive field](/send-data/logs/structured/honeytail/#dropping-or-scrubbing-fields). ## Parsing URL Patterns `honeytail` can break URLs up into their component parts, storing extra information in additional columns. This behavior is turned on by default for the `request` field on `nginx` datasets, but can become more useful with a little bit of guidance from you. See [`honeytail`'s documentation](/send-data/logs/structured/honeytail/#parsing-url-patterns) for details on configuring our agent to parse URL strings. ## Open Source [Honeytail](https://github.com/honeycombio/honeytail) is open source and Apache 2.0 licensed. # Send Other Webserver Logs Source: https://docs.honeycomb.io/send-data/logs/structured/other-webserver Parse Apache, HAProxy, and other webserver logs with Honeytail using a customized NGINX parser configuration and send them to Honeycomb. To support a variety of webserver and related technologies, our [Honeytail agent](/send-data/logs/structured/honeytail/) has an [Nginx parser](/send-data/logs/structured/nginx/) that can be easily tricked in to parsing other webservers' logs. You will create a config that contains the log format of your web server and pass it to the Honeytail nginx parser. As an example, this page describes how to consume [HAProxy](https://www.haproxy.org) and [Apache](https://httpd.apache.org/) logs using the `honeytail` nginx parser. ## Overview To use the nginx parser to consume a non-nginx log file, we will create a config that looks something like nginx config and use it to define the log format. We will then run `honeytail` on the log using the config file containing the format. The config file will have one statement `log_format name '';` (maybe broken up in to multiple lines). The format will be a series of labels identifying each field - the character following each label is the field separator. For example, to collect the HAProxy name, pid, ip address, and port from a log snippet of `haproxy[291] 127.0.0.1:4715`, you would use `$process[$pid] $ip:$port` as your format string. You can use any names you like for the labels—they will be used as the column names in Honeycomb. Below are two examples—HAProxy's http log formats and the default apache log format. You will likely have to tailor these examples to your specific config depending on the version of the web server you are running and other options you may have in their configs. ## HAProxy Http Format The HAProxy's http format for logs has a wealth of detail packed in to a very compact form. Here is a sample log line (from the [HAProxy docs](https://docs.haproxy.org/2.6/configuration.html#8.2.3)): ```log theme={} Feb 6 12:12:56 localhost \ haproxy[14389]: 10.0.1.2:33317 [06/Feb/2009:12:14:14.655] http-in static/srv1 \ 10/0/30/69/109 200 2750 - - ---- 1/1/1/1/0 0/0 {1wt.eu} {}\ "GET /index.html HTTP/1.1" ``` Here is the description of those fields (again, from the haproxy docs): | Field | Format | Extract from the example above | | ----- | --------------------------------------------------------- | ------------------------------ | | 1 | `process_name '[' pid ']:'` | `haproxy[14389]:` | | 2 | `client_ip ':' client_port` | `10.0.1.2:33317` | | 3 | `'[' accept_date ']'` | `[06/Feb/2009:12:14:14.655]` | | 4 | `frontend_name` | `http-in` | | 5 | `backend_name '/' server_name` | `static/srv1` | | 6 | `Tq '/' Tw '/' Tc '/' Tr '/' Tt*` | `10/0/30/69/109` | | 7 | `status_code` | `200` | | 8 | `bytes_read*` | `2750` | | 9 | `captured_request_cookie` | `-` | | 10 | `captured_response_cookie` | `-` | | 11 | `termination_state` | `----` | | 12 | `actconn '/' feconn '/' beconn '/' srv_conn '/' retries*` | `1/1/1/1/0` | | 13 | `srv_queue '/' backend_queue` | `0/0` | | 14 | `'{' captured_request_headers* '}'` | `{haproxy.1wt.eu}` | | 15 | `'{' captured_response_headers* '}'` | `{}` | | 16 | `'"' http_request '"'` | `"GET /index.html HTTP/1.1"` | Here is the config snippet used to match that log line. Because there are two date fields, we are going to use the one in square brackets `[]` because it is easier to parse and it is in the correct format (`d/m/y:h:m:s.sss`). We will stub out the syslog-provided date at the beginning of the line by using dots (to match any character). We can split up the log\_format line into multiple lines for easier editing. Make sure the last line ends with a semicolon. For this example, let us call this file `hny-haproxy.conf` ```nginx theme={} log_format haproxy '... .. ..:..:.. $hostname $process[$pid]: ' '$client_ip:$client_port [$time_local] $frontend $backend/$backend_server ' '$time_client_connect/$time_queued/$time_backend_conn/$time_backend_resp/$time_total ' '$status_code $bytes_read $request_cookie $response_cookie $termination_state ' '$act_conn/$fe_conn/$be_conn/$srv_conn/$retries $srv_queue/$backend_queue ' '{$request_headers} {$response_headers} "$request"'; ``` To use this config, you would run [our agent `honeytail`](/send-data/logs/structured/honeytail/) like this: ```shell theme={} honeytail \ -k YOUR_API_KEY \ -p nginx \ -d haproxy \ -f /path/to/haproxy.log \ --nginx.conf hny-haproxy.conf \ --nginx.format haproxy ``` ## Apache Log Format Apache's configuration can truly go as far as you want to take it. For this example, let us just stick with the default log format. Here is an example log line (split into two for readability) ```log theme={} 207.46.1.2 - - [03/Nov/2016:16:11:43 -0700] "GET /robots.txt HTTP/1.1" 200 334 \ "-" "Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)" ``` From an Apache logging config like this: ```apache theme={} LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined ``` There is not nearly as much there as in the HAProxy log, but let us pull out what we can, taking a hint from the [Apache docs](https://httpd.apache.org/docs/current/mod/mod_log_config.html) to decipher the fields. Let us call this file `hny-apache.conf` ```nginx theme={} log_format apache '$remote_ip $identd $user [$time_local] "$request" $status_code ' '$bytes_sent "$referrer" "$user_agent"'; ``` To use this config, you would run [our agent `honeytail`](/send-data/logs/structured/honeytail/) like this: ```shell theme={} honeytail \ -k YOUR_API_KEY \ -p nginx \ -d apache \ -f /path/to/apache/access.log \ --nginx.conf hny-apache.conf \ --nginx.format apache ``` ## Details on The Log Format ### Timestamps The nginx parser can only interpret timestamps in one of the two formats that nginx itself uses. The field in the log format description **must be named correctly** in order for Honeycomb to use the timestamp for the event instead of considering it a normal string field. * `$time_local` : Time in the [Common Log Format](https://en.wikipedia.org/wiki/Common_Log_Format), `06/Feb/2009:12:14:14.655` for example * `$time_iso8601`: Time in the [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) standard format, `2009-02-06T12:14:14+00:00` for example ### Case and Allowed Characters The field names in the `log_format` specification have some restrictions - it must only contain characters in the set `[a-z_]`. In other words, they: * Must be all lower case * Must not contain spaces * May only contain letters and underscores (no numbers or other symbols) Any other characters will be considered a field delimiter in the log format. ## Suggested Queries in Honeycomb Just to whet your appetite, we would like to suggest a few graphs to explore with your haproxy dataset: * **Slowest endpoints**: breakdown by `http_request`, calculate p95(`time_duration`), order by p95(`time_duration`) descending * **Average connection time per backend server**: breakdown by `backend_name`, `server_name`, calculate avg(`time_backend_connect`) ## Scrubbing Personally Identifiable Information While we believe strongly in the value of being able to track down the precise query causing a problem, we understand the concerns of exporting log data, which may contain sensitive user information. With that in mind, we recommend using `honeytail`'s nginx parser, but adding a `--scrub_field=sensitive_field_name` flag to hash the concrete `sensitive_field_name` value, or `--drop_field=sensitive_field_name` to drop it altogether and prevent it being sent to Honeycomb's servers. More information about dropping or scrubbing sensitive fields can be [found here](/send-data/logs/structured/honeytail/#dropping-or-scrubbing-fields). ## Parsing URL Patterns `honeytail` can break URLs up into their component parts, storing extra information in additional columns. This behavior is turned on by default for the `request` field on `nginx` datasets, but can become more useful with a little bit of guidance from you. See \[`honeytail`'s documentation]/send-data/logs/structured/honeytail/#parsing-url-patterns) for details on configuring our agent to parse URL strings. # Send PostgreSQL Logs Source: https://docs.honeycomb.io/send-data/logs/structured/postgresql Parse PostgreSQL logs with Honeytail and send them to Honeycomb to analyze database query patterns, slow queries, and traffic across your application. Our connector pulls your PostgreSQL logs into Honeycomb for analysis, so you can analyze PostgreSQL traffic on your machines and finally get a quick handle on the database queries triggered by your application logic. It surfaces attributes like: * The **normalized** query shape * Time spent executing the query * Transaction ID * Client information * ... and more! Honeycomb is unique in its ability to calculate metrics and statistics on the fly, while retaining the full-resolution log lines (and the original query that started it all!). This document is for running **PostgreSQL directly**. If running [PostgreSQL on RDS](https://aws.amazon.com/rds/postgresql/), Honeycomb offers support for ingesting RDS PostgreSQL logs via [CloudWatch Logs](/send-data/aws/aws-cloudformation/) with the option to convert these unstructured logs into structured logs. The agent used to translate logs to events and send them to Honeycomb is called `honeytail`. ## Configure PostgreSQL Query Logging Before running `honeytail`, turn slow query logging on for all queries if possible. To turn on slow query logging, edit your `postgresql.conf` and set: ```sql theme={} log_min_duration_statement = 0 log_statement='none' ``` `log_statement` indicates which types of queries are logged, but is superseded when setting `log_min_duration_statement` to `0`, as this effectively logs all queries. Setting `log_statement` to any other value will change the format of the query logs in a way that is not currently supported by the Honeycomb PostgreSQL parser. Alternatively, you can set this from the `psql` shell by running ```sql theme={} ALTER SYSTEM SET log_min_duration_statement=0; ALTER SYSTEM SET log_statement='none'; SELECT pg_reload_conf(); ``` Finally, take note of the value of the `log_line_prefix` configuration line. It will look something like this: ```sql theme={} log_line_prefix = '%t [%p-%l] %q%u@%d ' ``` ## Install and Run Honeytail On your PostgreSQL host, download and install the latest `honeytail` by running: Download the `honeytail_1.10.0_amd64.deb` package. ```shell theme={} wget -q https://honeycomb.io/download/honeytail/v1.10.0/honeytail_1.10.0_amd64.deb ``` Verify the package. ```shell theme={} echo '3db441215f97eaed068aa0531c986cf5405957e3e8e26b22c16b571091caf917 honeytail_1.10.0_amd64.deb' | sha256sum -c ``` Install the package. ```shell theme={} sudo dpkg -i honeytail_1.10.0_amd64.deb ``` The packages install `honeytail`, its config file `/etc/honeytail/honeytail.conf`, and some start scripts. Build `honeytail` from source if you need it in an unpackaged form or for ad-hoc use. Download the `honeytail_1.10.0_arm64.deb` package. ```shell theme={} wget -q https://honeycomb.io/download/honeytail/v1.10.0/honeytail_1.10.0_arm64.deb ``` Verify the package. ```shell theme={} echo '4220756e5a941cde6a484cb4cfde184eb189aaf29170df301a874eb143e960ed honeytail_1.10.0_arm64.deb' | sha256sum -c ``` Install the package. ```shell theme={} sudo dpkg -i honeytail_1.10.0_arm64.deb ``` The packages install `honeytail`, its config file `/etc/honeytail/honeytail.conf`, and some start scripts. Build `honeytail` from source if you need it in an unpackaged form or for ad-hoc use. Download the `honeytail_1.10.0-1.x86_64.rpm` package. ```shell theme={} wget -q https://honeycomb.io/download/honeytail/v1.10.0/honeytail_1.10.0-1.x86_64.rpm ``` Verify the package. ```shell theme={} echo 'b23215a9301b20b2e2262a0823c9e761e8b57e1a62fd5cec35f697fce41fa863 honeytail_1.10.0-1.x86_64.rpm' | sha256sum -c ``` Install the package. ```shell theme={} sudo rpm -i honeytail_1.10.0-1.x86_64.rpm ``` The packages install `honeytail`, its config file `/etc/honeytail/honeytail.conf`, and some start scripts. Build `honeytail` from source if you need it in an unpackaged form or for ad-hoc use. Download the 1.10.0 binary. ```shell theme={} wget -q -O honeytail https://honeycomb.io/download/honeytail/v1.10.0/honeytail-linux-amd64 ``` Verify the binary. ```shell theme={} echo 'c9cc7dd1aa2b12afeb30b089061870f3407d2df0119e7c2807fec648b603e2d5 honeytail' | shasum -a 256 -c ``` Set the permissions to allow execution. ```shell theme={} chmod 755 ./honeytail ``` Download the 1.10.0 binary. ```shell theme={} wget -q -O honeytail https://honeycomb.io/download/honeytail/v1.10.0/honeytail-linux-arm64 ``` Verify the binary. ```shell theme={} echo '1dd37227788548c4ed44592554e3c90e374c4d796c444dde9f372db8618bc7fa honeytail' | shasum -a 256 -c ``` Set the permissions to allow execution. ```shell theme={} chmod 755 ./honeytail ``` Download the 1.10.0 binary. ```shell theme={} wget -q -O honeytail https://honeycomb.io/download/honeytail/v1.10.0/honeytail-darwin-amd64 ``` Verify the binary. ```shell theme={} echo '9a3da0f48fe21b1e610ac6b63130dfb8118a9a0ec16abae13350edba02d85e4d honeytail' | shasum -a 256 -c ``` Set the permissions to allow execution. ```shell theme={} chmod 755 ./honeytail ``` Clone the [Honeytail](https://github.com/honeycombio/honeytail) repository. ```shell theme={} git clone https://github.com/honeycombio/honeytail ``` Install from source. ```shell theme={} cd honeytail; go install ``` Make sure you have enabled [query logging](#configure-postgresql-query-logging) before running `honeytail`. To consume the current slow query log from the beginning, run: ```shell theme={} honeytail \ --writekey=YOUR_API_KEY \ --dataset=postgres-queries --parser=postgresql \ --postgresql.log_line_prefix=YOUR_LOG_LINE_PREFIX \ --file=/var/log/postgresql/postgresql-9.5-main.log \ --tail.read_from=beginning ``` ## Troubleshooting Check out [`honeytail` Troubleshooting](/troubleshoot/common-issues/sending-data/#honeytail) for debugging tips. ## Run Honeytail Continuously To run `honeytail` continuously as a daemon process, first modify the configuration file `/etc/honeytail/honeytail.conf` and uncomment and set: * `ParserName` to `postgresql` * `WriteKey` to your API key, available from [the account page](https://ui.honeycomb.io/account) * `LogFiles` to the path for your PostgreSQL log file. * `Dataset` to the name of the dataset you wish to create with this log file. Then start `honeytail` using `upstart` or `systemd`: ```shell theme={} sudo initctl start honeytail ``` ```shell theme={} sudo systemctl start honeytail ``` ## Backfill Archived Logs You may have archived logs that you would like to import into Honeycomb. If you have a log file located at `/var/log/postgresql/postgresql-main.log`, you can backfill using this command: ```shell theme={} honeytail \ --writekey=YOUR_API_KEY \ --dataset=PostgreSQL \ --parser=postgresql \ --file=/var/log/postgresql/postgresql-main.log \ --postgresql.log_line_prefix=YOUR_CONFIGURED_LOG_LINE_PREFIX \ --backfill ``` This command can be used at any point to backfill from archived log files. You can read more about `honeytail`'s backfill behavior [here](/send-data/logs/structured/honeytail/#backfilling-existing-data). `honeytail` does not unzip log files, so you will need to do this before backfilling. Once you have finished backfilling your old logs, we recommend transitioning to the default streaming behavior to stream live logs to Honeycomb. ## Scrub Personally Identifiable Information While we believe strongly in the value of being able to track down the precise query causing a problem, we understand the concerns of exporting log data, which may contain sensitive user information. With that in mind, we recommend using `honeytail`'s PostgreSQL parser, but adding a `--scrub_field=query` flag to hash the concrete `query` value. The `normalized_query` attribute will still be representative of the **shape** of the query, and identifying patterns including specific queries will still be possible—but the sensitive information will be completely obscured before leaving your servers. More information about dropping or scrubbing sensitive fields can be [found here](/send-data/logs/structured/honeytail/#dropping-or-scrubbing-fields). ## Open Source [Honeytail](https://github.com/honeycombio/honeytail) is open source and Apache 2.0 licensed. # Send Logs with the OpenTelemetry Collector Source: https://docs.honeycomb.io/send-data/logs/unstructured/collector Use the OpenTelemetry Collector to collect, parse, and structure unstructured logs from Fluentd, AWS, Azure, and other sources before sending them to Honeycomb. Collect and convert logs from different sources to OpenTelemetry's structured log format. The [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/) can collect logs from many different sources in common or custom formats. You can use a Collector as a logging agent, often as a drop-in replacement for other logging agents. This lets you process your logs, traces, and metrics in one place. ## Use a Receiver to Collect Logs The OpenTelemetry Collector supports a large number of [receivers](https://opentelemetry.io/docs/collector/configuration/#receivers) that can be used to collect logs from a variety of sources. ### Setup 1. Make sure you're using the [Collector Contrib distribution of the OpenTelemetry Collector](https://github.com/open-telemetry/opentelemetry-collector-contrib), which contains contributions that are not part of the core repository and core distribution of the OpenTelemetry Collector. 2. Prepare your collector configuration file by adding the following boilerplate: ```yaml theme={} receivers: # Add your receiver here # ... processors: batch: # Add any additional processors here # ... exporters: otlp/logs: endpoint: "api.honeycomb.io:443" headers: "x-honeycomb-team": "YOUR_API_KEY" "x-honeycomb-dataset": "YOUR_LOGS_DATASET_NAME" service: pipelines: logs: receivers: [receiver1,receiver2,etc] processors: [batch] exporters: [otlp/logs] ``` If you are sending OTLP logs from a service with a `service.name` defined, then the dataset for those logs will be the name of the service, and the `x-honeycomb-dataset` header will not be used. ## Collect any Log with the Filelog Receiver The [Filelog Receiver](https://github.com/open-telemetry/opentelemetry-collector-contrib/tree/main/receiver/filelogreceiver) supports reading and parsing any arbitrary log written to a file on a server. The Filelog Receiver is the most flexible receiver, but depending on the shape of your logs, it may require additional configuration to parse your logs correctly. For example, here is a configuration that reads an NGINX access log and parses it into a structured log: ```yaml theme={} receivers: filelog: include: ["/var/log/nginx/access.log"] operators: - type: "regex_parser" regex: "(?P[^ ]*) - - \\[(?P