1
1
// Copyright The OpenTelemetry Authors
2
2
// SPDX-License-Identifier: Apache-2.0
3
3
4
+ #include < regex>
4
5
#include < sstream>
6
+ #include < string>
5
7
#include < utility>
6
8
#include < vector>
7
9
#include " prometheus/metric_family.h"
@@ -38,13 +40,7 @@ std::vector<prometheus_client::MetricFamily> PrometheusExporterUtils::TranslateT
38
40
{
39
41
for (const auto &metric_data : instrumentation_info.metric_data_ )
40
42
{
41
- auto origin_name = metric_data.instrument_descriptor .name_ ;
42
- auto unit = metric_data.instrument_descriptor .unit_ ;
43
- auto sanitized = SanitizeNames (origin_name);
44
- prometheus_client::MetricFamily metric_family;
45
- metric_family.name = sanitized + " _" + unit;
46
- metric_family.help = metric_data.instrument_descriptor .description_ ;
47
- auto time = metric_data.end_ts .time_since_epoch ();
43
+ auto time = metric_data.end_ts .time_since_epoch ();
48
44
for (const auto &point_data_attr : metric_data.point_data_attr_ )
49
45
{
50
46
auto kind = getAggregationType (point_data_attr.point_data );
@@ -55,7 +51,11 @@ std::vector<prometheus_client::MetricFamily> PrometheusExporterUtils::TranslateT
55
51
nostd::get<sdk::metrics::SumPointData>(point_data_attr.point_data ).is_monotonic_ ;
56
52
}
57
53
const prometheus_client::MetricType type = TranslateType (kind, is_monotonic);
58
- metric_family.type = type;
54
+ prometheus_client::MetricFamily metric_family;
55
+ metric_family.type = type;
56
+ metric_family.name = MapToPrometheusName (metric_data.instrument_descriptor .name_ ,
57
+ metric_data.instrument_descriptor .unit_ , type);
58
+ metric_family.help = metric_data.instrument_descriptor .description_ ;
59
59
if (type == prometheus_client::MetricType::Histogram) // Histogram
60
60
{
61
61
auto histogram_point_data =
@@ -114,8 +114,8 @@ std::vector<prometheus_client::MetricFamily> PrometheusExporterUtils::TranslateT
114
114
" invalid SumPointData type" );
115
115
}
116
116
}
117
+ output.emplace_back (metric_family);
117
118
}
118
- output.emplace_back (metric_family);
119
119
}
120
120
}
121
121
return output;
@@ -167,6 +167,156 @@ std::string PrometheusExporterUtils::SanitizeNames(std::string name)
167
167
return name;
168
168
}
169
169
170
+ std::regex INVALID_CHARACTERS_PATTERN (" [^a-zA-Z0-9]" );
171
+ std::regex CHARACTERS_BETWEEN_BRACES_PATTERN (" \\ {(.*?)\\ }" );
172
+ std::regex SANITIZE_LEADING_UNDERSCORES (" ^_+" );
173
+ std::regex SANITIZE_TRAILING_UNDERSCORES (" _+$" );
174
+ std::regex SANITIZE_CONSECUTIVE_UNDERSCORES (" [_]{2,}" );
175
+
176
+ std::string PrometheusExporterUtils::GetEquivalentPrometheusUnit (
177
+ const std::string &raw_metric_unit_name)
178
+ {
179
+ if (raw_metric_unit_name.empty ())
180
+ {
181
+ return raw_metric_unit_name;
182
+ }
183
+
184
+ std::string converted_metric_unit_name = RemoveUnitPortionInBraces (raw_metric_unit_name);
185
+ converted_metric_unit_name = ConvertRateExpressedToPrometheusUnit (converted_metric_unit_name);
186
+
187
+ return CleanUpString (GetPrometheusUnit (converted_metric_unit_name));
188
+ }
189
+
190
+ std::string PrometheusExporterUtils::GetPrometheusUnit (const std::string &unit_abbreviation)
191
+ {
192
+ static std::map<std::string, std::string> units{// Time
193
+ {" d" , " days" },
194
+ {" h" , " hours" },
195
+ {" min" , " minutes" },
196
+ {" s" , " seconds" },
197
+ {" ms" , " milliseconds" },
198
+ {" us" , " microseconds" },
199
+ {" ns" , " nanoseconds" },
200
+ // Bytes
201
+ {" By" , " bytes" },
202
+ {" KiBy" , " kibibytes" },
203
+ {" MiBy" , " mebibytes" },
204
+ {" GiBy" , " gibibytes" },
205
+ {" TiBy" , " tibibytes" },
206
+ {" KBy" , " kilobytes" },
207
+ {" MBy" , " megabytes" },
208
+ {" GBy" , " gigabytes" },
209
+ {" TBy" , " terabytes" },
210
+ {" B" , " bytes" },
211
+ {" KB" , " kilobytes" },
212
+ {" MB" , " megabytes" },
213
+ {" GB" , " gigabytes" },
214
+ {" TB" , " terabytes" },
215
+ // SI
216
+ {" m" , " meters" },
217
+ {" V" , " volts" },
218
+ {" A" , " amperes" },
219
+ {" J" , " joules" },
220
+ {" W" , " watts" },
221
+ {" g" , " grams" },
222
+ // Misc
223
+ {" Cel" , " celsius" },
224
+ {" Hz" , " hertz" },
225
+ {" 1" , " " },
226
+ {" %" , " percent" },
227
+ {" $" , " dollars" }};
228
+ auto res_it = units.find (unit_abbreviation);
229
+ if (res_it == units.end ())
230
+ {
231
+ return unit_abbreviation;
232
+ }
233
+ return res_it->second ;
234
+ }
235
+
236
+ std::string PrometheusExporterUtils::GetPrometheusPerUnit (const std::string &per_unit_abbreviation)
237
+ {
238
+ static std::map<std::string, std::string> per_units{
239
+ {" s" , " second" }, {" m" , " minute" }, {" h" , " hour" }, {" d" , " day" },
240
+ {" w" , " week" }, {" mo" , " month" }, {" y" , " year" }};
241
+ auto res_it = per_units.find (per_unit_abbreviation);
242
+ if (res_it == per_units.end ())
243
+ {
244
+ return per_unit_abbreviation;
245
+ }
246
+ return res_it->second ;
247
+ }
248
+
249
+ std::string PrometheusExporterUtils::RemoveUnitPortionInBraces (const std::string &unit)
250
+ {
251
+ return std::regex_replace (unit, CHARACTERS_BETWEEN_BRACES_PATTERN, " " );
252
+ }
253
+
254
+ std::string PrometheusExporterUtils::ConvertRateExpressedToPrometheusUnit (
255
+ const std::string &rate_expressed_unit)
256
+ {
257
+ if (rate_expressed_unit.find (" /" ) == std::string::npos)
258
+ {
259
+ return rate_expressed_unit;
260
+ }
261
+
262
+ std::vector<std::string> rate_entities;
263
+ size_t pos = rate_expressed_unit.find (" /" );
264
+ rate_entities.push_back (rate_expressed_unit.substr (0 , pos));
265
+ rate_entities.push_back (rate_expressed_unit.substr (pos + 1 ));
266
+
267
+ if (rate_entities[1 ].empty ())
268
+ {
269
+ return rate_expressed_unit;
270
+ }
271
+
272
+ std::string prometheus_unit = GetPrometheusUnit (rate_entities[0 ]);
273
+ std::string prometheus_per_unit = GetPrometheusPerUnit (rate_entities[1 ]);
274
+
275
+ return prometheus_unit + " _per_" + prometheus_per_unit;
276
+ }
277
+
278
+ std::string PrometheusExporterUtils::CleanUpString (const std::string &str)
279
+ {
280
+ std::string cleaned_string = std::regex_replace (str, INVALID_CHARACTERS_PATTERN, " _" );
281
+ cleaned_string = std::regex_replace (cleaned_string, SANITIZE_CONSECUTIVE_UNDERSCORES, " _" );
282
+ cleaned_string = std::regex_replace (cleaned_string, SANITIZE_TRAILING_UNDERSCORES, " " );
283
+ cleaned_string = std::regex_replace (cleaned_string, SANITIZE_LEADING_UNDERSCORES, " " );
284
+
285
+ return cleaned_string;
286
+ }
287
+
288
+ std::string PrometheusExporterUtils::MapToPrometheusName (
289
+ const std::string &name,
290
+ const std::string &unit,
291
+ prometheus_client::MetricType prometheus_type)
292
+ {
293
+ auto sanitized_name = SanitizeNames (name);
294
+ std::string prometheus_equivalent_unit = GetEquivalentPrometheusUnit (unit);
295
+
296
+ // Append prometheus unit if not null or empty.
297
+ if (!prometheus_equivalent_unit.empty () &&
298
+ sanitized_name.find (prometheus_equivalent_unit) == std::string::npos)
299
+ {
300
+ sanitized_name += " _" + prometheus_equivalent_unit;
301
+ }
302
+
303
+ // Special case - counter
304
+ if (prometheus_type == prometheus_client::MetricType::Counter &&
305
+ sanitized_name.find (" total" ) == std::string::npos)
306
+ {
307
+ sanitized_name += " _total" ;
308
+ }
309
+
310
+ // Special case - gauge
311
+ if (unit == " 1" && prometheus_type == prometheus_client::MetricType::Gauge &&
312
+ sanitized_name.find (" ratio" ) == std::string::npos)
313
+ {
314
+ sanitized_name += " _ratio" ;
315
+ }
316
+
317
+ return CleanUpString (SanitizeNames (sanitized_name));
318
+ }
319
+
170
320
metric_sdk::AggregationType PrometheusExporterUtils::getAggregationType (
171
321
const metric_sdk::PointType &point_type)
172
322
{
0 commit comments