Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions docs/pages/references/configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ Global configurations are provided through env variables or a YAML file. ConfigM
| `IDGEN_ATTEMPT_PREFIX` | Prefix for attempt IDs, prepended with underscore (e.g., 'atm_123'). Default: empty (no prefix) | `nil` | No |
| `IDGEN_DESTINATION_PREFIX` | Prefix for destination IDs, prepended with underscore (e.g., 'dst_123'). Default: empty (no prefix) | `nil` | No |
| `IDGEN_EVENT_PREFIX` | Prefix for event IDs, prepended with underscore (e.g., 'evt_123'). Default: empty (no prefix) | `nil` | No |
| `IDGEN_OPERATOR_EVENT_PREFIX` | Prefix for operator event IDs, prepended with underscore (e.g., 'ope_123'). Default: empty (no prefix) | `nil` | No |
| `IDGEN_TYPE` | ID generation type for all entities: uuidv4, uuidv7, nanoid. Default: uuidv4 | `uuidv4` | No |
| `LOG_BATCH_SIZE` | Maximum number of log entries to batch together before writing to storage. | `1000` | No |
| `LOG_BATCH_THRESHOLD_SECONDS` | Maximum time in seconds to buffer logs before flushing them to storage, if batch size is not reached. | `10` | No |
Expand Down
12 changes: 7 additions & 5 deletions internal/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,13 +177,15 @@ func (a *App) configureIDGenerators() error {
zap.String("type", a.config.IDGen.Type),
zap.String("event_prefix", a.config.IDGen.EventPrefix),
zap.String("destination_prefix", a.config.IDGen.DestinationPrefix),
zap.String("attempt_prefix", a.config.IDGen.AttemptPrefix))
zap.String("attempt_prefix", a.config.IDGen.AttemptPrefix),
zap.String("operator_event_prefix", a.config.IDGen.OperatorEventPrefix))

if err := idgen.Configure(idgen.IDGenConfig{
Type: a.config.IDGen.Type,
EventPrefix: a.config.IDGen.EventPrefix,
DestinationPrefix: a.config.IDGen.DestinationPrefix,
AttemptPrefix: a.config.IDGen.AttemptPrefix,
Type: a.config.IDGen.Type,
EventPrefix: a.config.IDGen.EventPrefix,
DestinationPrefix: a.config.IDGen.DestinationPrefix,
AttemptPrefix: a.config.IDGen.AttemptPrefix,
OperatorEventPrefix: a.config.IDGen.OperatorEventPrefix,
}); err != nil {
a.logger.Error("failed to configure ID generators", zap.Error(err))
return err
Expand Down
3 changes: 2 additions & 1 deletion internal/config/id_gen.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ type IDGenConfig struct {
Type string `yaml:"type" env:"IDGEN_TYPE" desc:"ID generation type for all entities: uuidv4, uuidv7, nanoid. Default: uuidv4" required:"N"`
AttemptPrefix string `yaml:"attempt_prefix" env:"IDGEN_ATTEMPT_PREFIX" desc:"Prefix for attempt IDs, prepended with underscore (e.g., 'atm_123'). Default: empty (no prefix)" required:"N"`
DestinationPrefix string `yaml:"destination_prefix" env:"IDGEN_DESTINATION_PREFIX" desc:"Prefix for destination IDs, prepended with underscore (e.g., 'dst_123'). Default: empty (no prefix)" required:"N"`
EventPrefix string `yaml:"event_prefix" env:"IDGEN_EVENT_PREFIX" desc:"Prefix for event IDs, prepended with underscore (e.g., 'evt_123'). Default: empty (no prefix)" required:"N"`
EventPrefix string `yaml:"event_prefix" env:"IDGEN_EVENT_PREFIX" desc:"Prefix for event IDs, prepended with underscore (e.g., 'evt_123'). Default: empty (no prefix)" required:"N"`
OperatorEventPrefix string `yaml:"operator_event_prefix" env:"IDGEN_OPERATOR_EVENT_PREFIX" desc:"Prefix for operator event IDs, prepended with underscore (e.g., 'ope_123'). Default: empty (no prefix)" required:"N"`
}
1 change: 1 addition & 0 deletions internal/config/logging.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ func (c *Config) LogConfigurationSummary() []zap.Field {
// ID Generation
zap.String("idgen_type", c.IDGen.Type),
zap.String("idgen_event_prefix", c.IDGen.EventPrefix),
zap.String("idgen_operator_event_prefix", c.IDGen.OperatorEventPrefix),

// Retention
zap.Int("clickhouse_log_retention_ttl_days", c.ClickHouseLogRetentionTTLDays),
Expand Down
44 changes: 28 additions & 16 deletions internal/idgen/idgen.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ var (
func init() {
// Initialize with default UUID v4 generator
globalGenerator = &IDGenerator{
generator: &uuidv4Generator{},
eventPrefix: "",
destinationPrefix: "",
attemptPrefix: "",
generator: &uuidv4Generator{},
eventPrefix: "",
destinationPrefix: "",
attemptPrefix: "",
operatorEventPrefix: "",
}
}

Expand All @@ -26,10 +27,11 @@ type idGenerator interface {
}

type IDGenerator struct {
generator idGenerator
eventPrefix string
destinationPrefix string
attemptPrefix string
generator idGenerator
eventPrefix string
destinationPrefix string
attemptPrefix string
operatorEventPrefix string
}

func (g *IDGenerator) Event() string {
Expand All @@ -44,6 +46,10 @@ func (g *IDGenerator) Attempt() string {
return g.generate(g.attemptPrefix)
}

func (g *IDGenerator) OperatorEvent() string {
return g.generate(g.operatorEventPrefix)
}

func (g *IDGenerator) Installation() string {
return g.generate("")
}
Expand Down Expand Up @@ -106,10 +112,11 @@ func (g *nanoidGenerator) generate() string {
}

type IDGenConfig struct {
Type string
EventPrefix string
DestinationPrefix string
AttemptPrefix string
Type string
EventPrefix string
DestinationPrefix string
AttemptPrefix string
OperatorEventPrefix string
}

func Configure(cfg IDGenConfig) error {
Expand All @@ -119,10 +126,11 @@ func Configure(cfg IDGenConfig) error {
}

globalGenerator = &IDGenerator{
generator: gen,
eventPrefix: cfg.EventPrefix,
destinationPrefix: cfg.DestinationPrefix,
attemptPrefix: cfg.AttemptPrefix,
generator: gen,
eventPrefix: cfg.EventPrefix,
destinationPrefix: cfg.DestinationPrefix,
attemptPrefix: cfg.AttemptPrefix,
operatorEventPrefix: cfg.OperatorEventPrefix,
}

return nil
Expand All @@ -140,6 +148,10 @@ func Attempt() string {
return globalGenerator.Attempt()
}

func OperatorEvent() string {
return globalGenerator.OperatorEvent()
}

func Installation() string {
return globalGenerator.Installation()
}
Expand Down
79 changes: 79 additions & 0 deletions internal/idgen/idgen_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,85 @@ func TestEvent(t *testing.T) {
})
}

func TestOperatorEvent(t *testing.T) {
t.Run("generates UUID v4 by default", func(t *testing.T) {
err := Configure(IDGenConfig{
Type: "uuidv4",
OperatorEventPrefix: "",
})
if err != nil {
t.Fatalf("Configure() error = %v", err)
}

id := OperatorEvent()
if id == "" {
t.Error("OperatorEvent() returned empty string")
}
if _, err := uuid.Parse(id); err != nil {
t.Errorf("OperatorEvent() returned invalid UUID: %s", id)
}
})

t.Run("uses configured prefix", func(t *testing.T) {
err := Configure(IDGenConfig{
Type: "uuidv4",
OperatorEventPrefix: "ope_",
})
if err != nil {
t.Fatalf("Configure() error = %v", err)
}

id := OperatorEvent()
if !strings.HasPrefix(id, "ope_") {
t.Errorf("OperatorEvent() = %v, want prefix 'ope_'", id)
}
uuidPart := strings.TrimPrefix(id, "ope_")
if _, err := uuid.Parse(uuidPart); err != nil {
t.Errorf("UUID part is not valid: %s", uuidPart)
}
})

t.Run("nanoid with prefix", func(t *testing.T) {
err := Configure(IDGenConfig{
Type: "nanoid",
OperatorEventPrefix: "ope_",
})
if err != nil {
t.Fatalf("Configure() error = %v", err)
}

id := OperatorEvent()
if !strings.HasPrefix(id, "ope_") {
t.Errorf("OperatorEvent() = %v, want prefix 'ope_'", id)
}
nanoidPart := strings.TrimPrefix(id, "ope_")
if len(nanoidPart) != 26 {
t.Errorf("Nanoid part should be 26 characters, got %d: %s", len(nanoidPart), nanoidPart)
}
})

t.Run("independent from event prefix", func(t *testing.T) {
err := Configure(IDGenConfig{
Type: "uuidv4",
EventPrefix: "evt_",
OperatorEventPrefix: "ope_",
})
if err != nil {
t.Fatalf("Configure() error = %v", err)
}

eventID := Event()
operatorEventID := OperatorEvent()

if !strings.HasPrefix(eventID, "evt_") {
t.Errorf("Event() = %v, want prefix 'evt_'", eventID)
}
if !strings.HasPrefix(operatorEventID, "ope_") {
t.Errorf("OperatorEvent() = %v, want prefix 'ope_'", operatorEventID)
}
})
}

func BenchmarkEvent_UUIDv4(b *testing.B) {
Configure(IDGenConfig{Type: "uuidv4", EventPrefix: ""})
b.ResetTimer()
Expand Down
2 changes: 1 addition & 1 deletion internal/opevents/emitter.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func (e *emitter) Emit(ctx context.Context, topic string, tenantID string, data
}

event := &OperatorEvent{
ID: idgen.String(),
ID: idgen.OperatorEvent(),
Topic: topic,
Time: time.Now(),
DeploymentID: e.deploymentID,
Expand Down
Loading