GetBuffersForDimensions takes advantage of the fact that the configuration for a tracker changes slowly. Reuses buffers from the previous call when the dimensions are the same.
(dimensions map[string]string)
| 91 | // GetBuffersForDimensions takes advantage of the fact that the configuration for a tracker |
| 92 | // changes slowly. Reuses buffers from the previous call when the dimensions are the same. |
| 93 | func (t *tenantUsage) GetBuffersForDimensions(dimensions map[string]string) ([]mapping, []string, []string, []string) { |
| 94 | if maps.Equal(dimensions, t.dimensions) { |
| 95 | // configuration has not changed, so return the mapping and buffers we already have. |
| 96 | return t.mapping, t.buffer1, t.buffer2, t.buffer3 |
| 97 | } |
| 98 | |
| 99 | // The configuration changed, recompute the mapping and buffers |
| 100 | |
| 101 | // Step 1 |
| 102 | // Gather all configured dimensions and their sanitized output, attribute |
| 103 | // and the scope of the configured dimensions |
| 104 | t.dimensions = dimensions |
| 105 | sanitizedDimensions := make(map[string]string, len(dimensions)) |
| 106 | dimensionsScope := make(map[string]Scope, len(dimensions)) |
| 107 | dimensionsAttr := make(map[string]string, len(dimensions)) |
| 108 | for k, v := range dimensions { |
| 109 | // parse the dimensions key to get the attribute name and the scope |
| 110 | // and build the keys for the lookup |
| 111 | attr, scope := ParseDimensionKey(k) |
| 112 | dimensionsScope[k] = scope |
| 113 | dimensionsAttr[k] = attr |
| 114 | |
| 115 | // Get the final sanitized output label for this dimension. |
| 116 | // Dimensions are key-value pairs with optional value. |
| 117 | // If value is empty string, then we use just the key. |
| 118 | // Regardless the output is always the sanitized version. |
| 119 | // Example: |
| 120 | // service.name="" => "service_name" |
| 121 | // service.name="foo.bar" => "foo_bar" |
| 122 | // service.name="service" => "service" |
| 123 | // resource.service.name="" => "service_name" |
| 124 | // span.attr="" => "attr" |
| 125 | var sanitized string |
| 126 | if v == "" { |
| 127 | // The dimension is using default mapping, map it to attribute (without scope prefix) |
| 128 | v = attr |
| 129 | } |
| 130 | sanitized = strutil.SanitizeFullLabelName(v) |
| 131 | sanitizedDimensions[k] = sanitized |
| 132 | } |
| 133 | |
| 134 | // Step 2 |
| 135 | // Build the final list of sorted/distinct outputs |
| 136 | t.sortedKeys = t.sortedKeys[:0] |
| 137 | for _, v := range sanitizedDimensions { |
| 138 | if !slices.Contains(t.sortedKeys, v) { |
| 139 | t.sortedKeys = append(t.sortedKeys, v) |
| 140 | } |
| 141 | } |
| 142 | slices.Sort(t.sortedKeys) |
| 143 | |
| 144 | // Step 3 |
| 145 | // Prepare the mapping from raw attribute names to the final location of |
| 146 | // where it goes in the output buffers. This avoids another layer of indirection. |
| 147 | t.mapping = t.mapping[:0] |
| 148 | for k := range dimensions { |
| 149 | i := slices.Index(t.sortedKeys, sanitizedDimensions[k]) |
| 150 | t.mapping = append(t.mapping, mapping{ |
no test coverage detected