Skip to content
Open
Show file tree
Hide file tree
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 Feb 17, 2026
36f88eb
Merge branch 'main' into feat/honeycomb-integration
gaga1307 Feb 17, 2026
a559d69
fix: Improve webhook token validation in Honeycomb integration
gaga1307 Feb 17, 2026
c0958ce
fix: Enhance error handling for webhook integration
gaga1307 Feb 17, 2026
55a3330
fix: correct webhook token comparison and variable redeclaration
gaga1307 Feb 17, 2026
b330bc2
fix: Update test assertions for Honeycomb event creation
gaga1307 Feb 17, 2026
91e7a2a
fix: Update Honeycomb event timestamp handling and tests
gaga1307 Feb 17, 2026
39139ce
chore: run prettier
gaga1307 Feb 17, 2026
4c2bef1
fix: Refine webhook token handling in Honeycomb integration
gaga1307 Feb 17, 2026
12a2e4e
refactor: Remove unused EU base URL from Honeycomb client
gaga1307 Feb 17, 2026
2a3e227
feat: Add Honeycomb integration components and mappers
gaga1307 Feb 22, 2026
39e739b
chore: Fix formatting in Honeycomb mappers
gaga1307 Feb 22, 2026
e600c1a
chore: Fix Honeycomb component docs formatting
gaga1307 Feb 22, 2026
77f1448
fix: Improve error handling in Honeycomb client configuration key
gaga1307 Feb 22, 2026
279ce3d
fix: Enhance field handling in Honeycomb event mapper
gaga1307 Feb 22, 2026
8d293da
fix: Improve error handling for configuration key in Honeycomb integr…
gaga1307 Feb 22, 2026
980e48a
chore: Fix Honeycomb docs missing newline at end of file
gaga1307 Feb 22, 2026
0aee77f
chore: Fix Honeycomb docs
gaga1307 Feb 22, 2026
0981c2c
Merge branch 'main' into feat/honeycomb-integration
gaga1307 Feb 22, 2026
12e2a5d
feat: Add API key validation and ingest key handling in Honeycomb client
gaga1307 Feb 22, 2026
2c6cb9e
refactor: Replace ingest header retrieval method in Honeycomb client
gaga1307 Feb 22, 2026
ed095d8
chore: Sync generated Honeycomb component docs
gaga1307 Feb 22, 2026
4025907
refactor: Simplify trigger field handling in Honeycomb client
gaga1307 Feb 22, 2026
d93e515
feat: Add metadata setting in OnAlertFired setup
gaga1307 Feb 22, 2026
78c85ab
feat: Add v1 ping check after ingest key creation in Honeycomb client
gaga1307 Feb 22, 2026
f726814
chore: remove comment from test
gaga1307 Feb 22, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
118 changes: 118 additions & 0 deletions docs/components/Honeycomb.mdx
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"
}
```

125 changes: 125 additions & 0 deletions pkg/integrations/honeycomb/client.go
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()))

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))
}
Loading