Files
zeekay 5c4dad5ad8 debrand: drop signoz — o11y only across collector code
Finish the signoz -> o11y debrand that the debrand branch left partial:
- repoint SigNoz/signoz-otel-collector/{utils,constants,keycheck,metadataexporter,
  processor/*} imports to the local hanzoai/otel-collector/* copies (already folded)
- rename package signozllmpricingprocessor -> o11yllmpricingprocessor (dir+pkg+typeStr)
- rename component type IDs: signozclickhouse{metrics,meter} -> o11yclickhouse*,
  signozlogspipeline -> o11ylogspipeline, signozllmpricing -> o11yllmpricing
- rename files: schema-signoz.go -> schema.go, signoz_attributes.go -> o11y_attributes.go
- vendor SigNoz/grok's mutex-patched fork in-tree as pkg/grok (Apache-2.0, self-contained)
  and drop the segmentio/ksuid->signoz/ksuid + vjeantet/grok->signoz/grok replaces
- restore constants.DistributedFieldKeysTable dropped in the earlier fold
- go.mod/go.sum: SigNoz/signoz-otel-collector require gone; 0 signoz in code

Full ./... build passes. LICENSE keeps upstream Apache attribution (legal).
Residual: ClickHouse dd-sketch driver forks (ch-go, clickhouse-go/v2) — next.
2026-07-12 18:04:52 -07:00

107 lines
3.3 KiB
Go

package o11yllmpricingprocessor // import "github.com/hanzoai/otel-collector/processor/o11yllmpricingprocessor"
import (
"fmt"
"path"
)
type CacheMode string
const (
CacheModeSubtract CacheMode = "subtract" // cache_read is already counted inside input_tokens (e.g. OpenAI)
CacheModeAdditive CacheMode = "additive" // cache_read is separate from input_tokens (e.g. Anthropic)
)
// Config is the top-level processor configuration.
type Config struct {
// Attrs maps logical token-field names to the actual span attribute keys.
Attrs AttrMapping `mapstructure:"attrs"`
DefaultPricing PricingConfig `mapstructure:"default_pricing"`
// OutputAttrs maps logical cost-field names to the span attribute keys
// where computed costs are written.
OutputAttrs OutputMapping `mapstructure:"output_attrs"`
}
type AttrMapping struct {
Model string `mapstructure:"model"`
In string `mapstructure:"in"`
Out string `mapstructure:"out"`
CacheRead string `mapstructure:"cache_read"`
CacheWrite string `mapstructure:"cache_write"`
}
type PricingConfig struct {
Rules []PricingRule `mapstructure:"rules"`
}
type PricingRule struct {
Name string `mapstructure:"name"`
Pattern []string `mapstructure:"pattern"`
Cache PricingRuleCache `mapstructure:"cache"`
In float64 `mapstructure:"in"`
Out float64 `mapstructure:"out"`
}
type PricingRuleCache struct {
// Mode controls how cache tokens are factored into the cost:
// "subtract" — cache read tokens are already counted inside input_tokens;
// billed_input = input_tokens - cache_read.
// "additive" — cache read/write are separate from input_tokens;
// all four buckets are billed independently.
Mode CacheMode `mapstructure:"mode"`
// Per-million-token prices (USD) for cached reads/writes.
Read float64 `mapstructure:"read"`
Write float64 `mapstructure:"write"`
}
type OutputMapping struct {
In string `mapstructure:"in"`
Out string `mapstructure:"out"`
CacheRead string `mapstructure:"cache_read"`
CacheWrite string `mapstructure:"cache_write"`
Total string `mapstructure:"total"`
}
func (c *CacheMode) String() string {
if c == nil {
return ""
}
return string(*c)
}
func (c *Config) Validate() error {
if c.Attrs.Model == "" {
return fmt.Errorf("attrs.model must not be empty")
}
for i, r := range c.DefaultPricing.Rules {
if len(r.Pattern) == 0 {
return fmt.Errorf("default_pricing.rules[%d]: pattern must not be empty", i)
}
for j, p := range r.Pattern {
if p == "" {
return fmt.Errorf("default_pricing.rules[%d].pattern[%d]: pattern must not be empty", i, j)
}
if _, err := path.Match(p, ""); err != nil {
return fmt.Errorf("default_pricing.rules[%d].pattern[%d]: invalid glob pattern %q: %w", i, j, p, err)
}
}
if r.Cache.Mode != CacheModeSubtract && r.Cache.Mode != CacheModeAdditive {
return fmt.Errorf("default_pricing.rules[%d] (pattern=%v): cache.mode must be %q or %q, got %q",
i, r.Pattern, CacheModeSubtract, CacheModeAdditive, r.Cache.Mode)
}
if r.In < 0 || r.Out < 0 || r.Cache.Read < 0 || r.Cache.Write < 0 {
return fmt.Errorf("default_pricing.rules[%d] (pattern=%v): prices must be non-negative", i, r.Pattern)
}
}
if c.OutputAttrs.Total == "" {
return fmt.Errorf("output_attrs.total must not be empty")
}
return nil
}