master
go 126 lines 2.76 KB
Raw
1 // Unless explicitly stated otherwise all files in this repository are licensed
2 // under the Apache License Version 2.0.
3 // This product includes software developed at Datadog (https://www.datadoghq.com/).
4 // Copyright 2026-present Datadog, Inc.
5
6 package ddprofiledefinition
7
8 import (
9 "fmt"
10 "maps"
11 "reflect"
12 )
13
14 type MappingMode string
15
16 const (
17 MappingModeExact MappingMode = "exact"
18 MappingModeBitmask MappingMode = "bitmask"
19 )
20
21 // MappingConfig defines mapping behavior for metric values, tags, and metadata.
22 // Legacy flat-map YAML remains supported and is interpreted as exact mode.
23 type MappingConfig struct {
24 Mode MappingMode `yaml:"mode,omitempty" json:"mode,omitempty"`
25 Items map[string]string `yaml:"items,omitempty" json:"items,omitempty"`
26 }
27
28 func NewExactMapping(items map[string]string) MappingConfig {
29 return MappingConfig{
30 Mode: MappingModeExact,
31 Items: maps.Clone(items),
32 }
33 }
34
35 func NewBitmaskMapping(items map[string]string) MappingConfig {
36 return MappingConfig{
37 Mode: MappingModeBitmask,
38 Items: maps.Clone(items),
39 }
40 }
41
42 func (m MappingConfig) Clone() MappingConfig {
43 return MappingConfig{
44 Mode: m.Mode,
45 Items: maps.Clone(m.Items),
46 }
47 }
48
49 func (m MappingConfig) HasItems() bool {
50 return len(m.Items) > 0
51 }
52
53 func (m MappingConfig) Lookup(key string) (string, bool) {
54 if len(m.Items) == 0 {
55 return "", false
56 }
57 v, ok := m.Items[key]
58 return v, ok
59 }
60
61 func (m MappingConfig) EffectiveMode() MappingMode {
62 if m.Mode == "" {
63 return MappingModeExact
64 }
65 return m.Mode
66 }
67
68 func (m MappingConfig) String() string {
69 if m.Mode == "" || m.Mode == MappingModeExact {
70 return fmt.Sprintf("%v", m.Items)
71 }
72 return fmt.Sprintf("{mode:%s items:%v}", m.Mode, m.Items)
73 }
74
75 // UnmarshalYAML supports both the legacy flat-map syntax and the structured object syntax.
76 func (m *MappingConfig) UnmarshalYAML(unmarshal func(any) error) error {
77 var raw map[string]any
78 if err := unmarshal(&raw); err == nil {
79 if items, ok := raw["items"]; ok && isStructuredMappingItems(items) {
80 return m.unmarshalStructured(unmarshal)
81 }
82 }
83
84 var items map[string]string
85 if err := unmarshal(&items); err != nil {
86 return err
87 }
88
89 if len(items) == 0 {
90 *m = MappingConfig{}
91 return nil
92 }
93
94 *m = MappingConfig{
95 Mode: MappingModeExact,
96 Items: items,
97 }
98
99 return nil
100 }
101
102 func (m *MappingConfig) unmarshalStructured(unmarshal func(any) error) error {
103 type plain MappingConfig
104
105 var cfg plain
106 if err := unmarshal(&cfg); err != nil {
107 return err
108 }
109
110 mode := MappingConfig(cfg).Mode
111 items := MappingConfig(cfg).Items
112 if len(items) == 0 {
113 items = nil
114 }
115 if len(items) > 0 && mode == "" {
116 mode = MappingModeExact
117 }
118
119 *m = MappingConfig{Mode: mode, Items: items}
120 return nil
121 }
122
123 func isStructuredMappingItems(v any) bool {
124 rv := reflect.ValueOf(v)
125 return rv.IsValid() && rv.Kind() == reflect.Map
126 }