-
Notifications
You must be signed in to change notification settings - Fork 101
feat: Add Honeycomb integration #3149
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
gaga1307
wants to merge
26
commits into
superplanehq:main
Choose a base branch
from
gaga1307:feat/honeycomb-integration
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 1 commit
Commits
Show all changes
26 commits
Select commit
Hold shift + click to select a range
b818228
feat: Add Honeycomb integration with trigger and action
gaga1307 36f88eb
Merge branch 'main' into feat/honeycomb-integration
gaga1307 a559d69
fix: Improve webhook token validation in Honeycomb integration
gaga1307 c0958ce
fix: Enhance error handling for webhook integration
gaga1307 55a3330
fix: correct webhook token comparison and variable redeclaration
gaga1307 b330bc2
fix: Update test assertions for Honeycomb event creation
gaga1307 91e7a2a
fix: Update Honeycomb event timestamp handling and tests
gaga1307 39139ce
chore: run prettier
gaga1307 4c2bef1
fix: Refine webhook token handling in Honeycomb integration
gaga1307 12a2e4e
refactor: Remove unused EU base URL from Honeycomb client
gaga1307 2a3e227
feat: Add Honeycomb integration components and mappers
gaga1307 39e739b
chore: Fix formatting in Honeycomb mappers
gaga1307 e600c1a
chore: Fix Honeycomb component docs formatting
gaga1307 77f1448
fix: Improve error handling in Honeycomb client configuration key
gaga1307 279ce3d
fix: Enhance field handling in Honeycomb event mapper
gaga1307 8d293da
fix: Improve error handling for configuration key in Honeycomb integr…
gaga1307 980e48a
chore: Fix Honeycomb docs missing newline at end of file
gaga1307 0aee77f
chore: Fix Honeycomb docs
gaga1307 0981c2c
Merge branch 'main' into feat/honeycomb-integration
gaga1307 12e2a5d
feat: Add API key validation and ingest key handling in Honeycomb client
gaga1307 2c6cb9e
refactor: Replace ingest header retrieval method in Honeycomb client
gaga1307 ed095d8
chore: Sync generated Honeycomb component docs
gaga1307 4025907
refactor: Simplify trigger field handling in Honeycomb client
gaga1307 d93e515
feat: Add metadata setting in OnAlertFired setup
gaga1307 78c85ab
feat: Add v1 ping check after ingest key creation in Honeycomb client
gaga1307 f726814
chore: remove comment from test
gaga1307 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,118 @@ | ||
| --- | ||
| title: "Honeycomb" | ||
| --- | ||
|
|
||
| Triggers and actions for Honeycomb | ||
|
|
||
| ## Triggers | ||
|
|
||
| <CardGrid> | ||
| <LinkCard title="On Alert Fired" href="#on-alert-fired" description="Triggers when Honeycomb sends an alert webhook" /> | ||
| </CardGrid> | ||
|
|
||
| import { CardGrid, LinkCard } from "@astrojs/starlight/components"; | ||
|
|
||
| ## Actions | ||
|
|
||
| <CardGrid> | ||
| <LinkCard title="Create Event" href="#create-event" description="Send an event to Honeycomb" /> | ||
| </CardGrid> | ||
|
|
||
| ## Instructions | ||
|
|
||
| Connect Honeycomb to Superplane using a Honeycomb API key. | ||
|
|
||
| **Get your API key**: | ||
| Honeycomb → Account → Team Settings → API Keys → copy key → paste here. | ||
|
|
||
| **Trigger setup**: | ||
| After saving a Honeycomb trigger node, Superplane generates a Webhook URL and Shared Secret. | ||
| Add them in Honeycomb → Team Settings → Integrations → Webhooks. | ||
|
|
||
| Once configured, Honeycomb events will trigger your workflow automatically. | ||
|
|
||
| <a id="on-alert-fired"></a> | ||
|
|
||
| ## On Alert Fired | ||
|
|
||
| The On Alert Fired trigger starts a workflow execution when Honeycomb sends an alert webhook. | ||
|
|
||
| Setup: | ||
| 1) Add this trigger to a workflow | ||
| 2) Optionally set Alert Name (used to filter which node fires) | ||
| 3) SAVE the node | ||
| 4) Copy Webhook URL and Shared Secret into Honeycomb webhook integration | ||
|
|
||
| ### Example Data | ||
|
|
||
| ```json | ||
| { | ||
| "dataset": { | ||
| "name": "Production API", | ||
| "slug": "api-production" | ||
| }, | ||
| "description": "API error rate has exceeded the acceptable threshold", | ||
| "id": "01HQXYZ123ABC", | ||
| "name": "High Error Rate - Production API", | ||
| "query": { | ||
| "query_url": "https://ui.honeycomb.io/myteam/datasets/api-production/query/xyz789", | ||
| "time_range": 900 | ||
| }, | ||
| "result_groups": [ | ||
| { | ||
| "group": { | ||
| "endpoint": "/api/users" | ||
| }, | ||
| "result_value": 12.3 | ||
| }, | ||
| { | ||
| "group": { | ||
| "endpoint": "/api/orders" | ||
| }, | ||
| "result_value": 6.8 | ||
| } | ||
| ], | ||
| "result_value": 8.5, | ||
| "severity": "critical", | ||
| "status": "firing", | ||
| "summary": "Error rate is 8.5% (threshold: 5%)", | ||
| "threshold": { | ||
| "op": "above", | ||
| "value": 5 | ||
| }, | ||
| "trigger_url": "https://ui.honeycomb.io/myteam/triggers/abc123", | ||
| "triggered_at": "2026-02-15T10:30:00Z", | ||
| "version": "v1" | ||
| } | ||
| ``` | ||
|
|
||
| <a id="create-event"></a> | ||
|
|
||
| ## Create Event | ||
|
|
||
| Sends a custom event to Honeycomb using the Events API. | ||
|
|
||
| The component sends a single event as a JSON object where each key becomes a Honeycomb field. | ||
|
|
||
| Notes: | ||
| - The request body is the JSON object you provide in "Fields". | ||
| - If you do not include a "time" field, the current time is automatically set via request header. | ||
|
|
||
| ### Example Output | ||
|
|
||
| ```json | ||
| { | ||
| "dataset": "deployments", | ||
| "fields": { | ||
| "deployed_by": "github-actions", | ||
| "duration_seconds": 42, | ||
| "environment": "production", | ||
| "event_type": "deployment", | ||
| "service": "billing-api", | ||
| "success": true, | ||
| "version": "2.4.1" | ||
| }, | ||
| "status": "sent" | ||
| } | ||
| ``` | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,125 @@ | ||
| package honeycomb | ||
|
|
||
| import ( | ||
| "bytes" | ||
| "encoding/json" | ||
| "fmt" | ||
| "io" | ||
| "net/http" | ||
| "net/url" | ||
| "strings" | ||
| "time" | ||
|
|
||
| "github.com/superplanehq/superplane/pkg/core" | ||
| ) | ||
|
|
||
| const ( | ||
| BaseURLUS = "https://api.honeycomb.io" | ||
| BaseURLEU = "https://api.eu1.honeycomb.io" | ||
| ) | ||
|
|
||
| type Client struct { | ||
| APIKey string | ||
| BaseURL string | ||
| http core.HTTPContext | ||
| } | ||
|
|
||
| func NewClient(httpCtx core.HTTPContext, ctx core.IntegrationContext) (*Client, error) { | ||
| apiKeyAny, err := ctx.GetConfig("apiKey") | ||
| if err != nil { | ||
| return nil, fmt.Errorf("api key is required") | ||
| } | ||
| apiKey := strings.TrimSpace(string(apiKeyAny)) | ||
| if apiKey == "" { | ||
| return nil, fmt.Errorf("api key is required") | ||
| } | ||
|
|
||
| siteAny, err := ctx.GetConfig("site") | ||
| if err != nil { | ||
| siteAny = []byte("api.honeycomb.io") | ||
| } | ||
| site := strings.TrimSpace(string(siteAny)) | ||
| if site == "" { | ||
| site = strings.TrimPrefix(BaseURLUS, "https://") | ||
| } | ||
|
|
||
| baseURL := site | ||
| if !strings.HasPrefix(baseURL, "http://") && !strings.HasPrefix(baseURL, "https://") { | ||
| baseURL = "https://" + baseURL | ||
| } | ||
|
|
||
| return &Client{ | ||
| APIKey: apiKey, | ||
| BaseURL: baseURL, | ||
| http: httpCtx, | ||
| }, nil | ||
|
|
||
| } | ||
|
|
||
| func (c *Client) Validate() error { | ||
| req, err := http.NewRequest(http.MethodGet, c.BaseURL+"/1/auth", nil) | ||
| if err != nil { | ||
| return err | ||
| } | ||
|
|
||
| req.Header.Set("X-Honeycomb-Team", c.APIKey) | ||
|
|
||
| resp, err := c.http.Do(req) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to validate api key: %w", err) | ||
| } | ||
| defer resp.Body.Close() | ||
|
|
||
| if resp.StatusCode == http.StatusOK { | ||
| return nil | ||
| } | ||
|
|
||
| if resp.StatusCode == http.StatusUnauthorized { | ||
| return fmt.Errorf("invalid api key") | ||
| } | ||
|
|
||
| if resp.StatusCode == http.StatusForbidden { | ||
| return fmt.Errorf("api key is valid, but does not have permission for this account/team") | ||
| } | ||
|
|
||
| return fmt.Errorf("honeycomb authentication failed (http %d)", resp.StatusCode) | ||
| } | ||
|
|
||
| func (c *Client) CreateEvent(datasetSlug string, fields map[string]any) error { | ||
| datasetSlug = strings.TrimSpace(datasetSlug) | ||
| if datasetSlug == "" { | ||
| return fmt.Errorf("dataset is required") | ||
| } | ||
|
|
||
| u, _ := url.Parse(c.BaseURL) | ||
| u.Path = fmt.Sprintf("/1/events/%s", url.PathEscape(datasetSlug)) | ||
|
|
||
| body, err := json.Marshal(fields) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to marshal fields: %w", err) | ||
| } | ||
|
|
||
| req, err := http.NewRequest(http.MethodPost, u.String(), bytes.NewReader(body)) | ||
| if err != nil { | ||
| return fmt.Errorf("failed to create request: %w", err) | ||
| } | ||
|
|
||
| req.Header.Set("X-Honeycomb-Team", c.APIKey) | ||
| req.Header.Set("Content-Type", "application/json") | ||
|
|
||
| // Always set event timestamp header (Honeycomb uses the header for event time). | ||
| req.Header.Set("X-Honeycomb-Event-Time", fmt.Sprintf("%d", time.Now().Unix())) | ||
gaga1307 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| resp, err := c.http.Do(req) | ||
| if err != nil { | ||
| return fmt.Errorf("request failed: %w", err) | ||
| } | ||
| defer resp.Body.Close() | ||
|
|
||
| if resp.StatusCode >= 200 && resp.StatusCode < 300 { | ||
| return nil | ||
| } | ||
|
|
||
| b, _ := io.ReadAll(resp.Body) | ||
| return fmt.Errorf("honeycomb create event failed (status %d): %s", resp.StatusCode, string(b)) | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.