Coverage Report

Created: 2026-09-28 07:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/fluent-bit/lib/cmetrics/src/cmt_encode_text.c
Line
Count
Source
1
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
3
/*  CMetrics
4
 *  ========
5
 *  Copyright 2021-2022 The CMetrics Authors
6
 *
7
 *  Licensed under the Apache License, Version 2.0 (the "License");
8
 *  you may not use this file except in compliance with the License.
9
 *  You may obtain a copy of the License at
10
 *
11
 *      http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 *  Unless required by applicable law or agreed to in writing, software
14
 *  distributed under the License is distributed on an "AS IS" BASIS,
15
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 *  See the License for the specific language governing permissions and
17
 *  limitations under the License.
18
 */
19
20
#include <cmetrics/cmetrics.h>
21
#include <cmetrics/cmt_metric.h>
22
#include <cmetrics/cmt_map.h>
23
#include <cmetrics/cmt_counter.h>
24
#include <cmetrics/cmt_gauge.h>
25
#include <cmetrics/cmt_untyped.h>
26
#include <cmetrics/cmt_histogram.h>
27
#include <cmetrics/cmt_exp_histogram.h>
28
#include <cmetrics/cmt_summary.h>
29
#include <cmetrics/cmt_time.h>
30
#include <cmetrics/cmt_compat.h>
31
32
static const char *map_type_to_otlp_key(int map_type)
33
0
{
34
0
    switch (map_type) {
35
0
    case CMT_COUNTER:
36
0
        return "counter";
37
0
    case CMT_GAUGE:
38
0
        return "gauge";
39
0
    case CMT_UNTYPED:
40
0
        return "untyped";
41
0
    case CMT_SUMMARY:
42
0
        return "summary";
43
0
    case CMT_HISTOGRAM:
44
0
        return "histogram";
45
0
    case CMT_EXP_HISTOGRAM:
46
0
        return "exp_histogram";
47
0
    default:
48
0
        return NULL;
49
0
    }
50
0
}
51
52
static struct cfl_kvlist *fetch_metadata_kvlist_key(struct cfl_kvlist *kvlist, const char *key)
53
0
{
54
0
    struct cfl_variant *entry_variant;
55
56
0
    if (kvlist == NULL) {
57
0
        return NULL;
58
0
    }
59
60
0
    entry_variant = cfl_kvlist_fetch(kvlist, (char *) key);
61
0
    if (entry_variant == NULL || entry_variant->type != CFL_VARIANT_KVLIST) {
62
0
        return NULL;
63
0
    }
64
65
0
    return entry_variant->data.as_kvlist;
66
0
}
67
68
static void append_variant_value(cfl_sds_t *buf, struct cfl_variant *value);
69
70
static void append_kvlist_value(cfl_sds_t *buf, struct cfl_kvlist *kvlist)
71
0
{
72
0
    int count;
73
0
    struct cfl_list *head;
74
0
    struct cfl_kvpair *kvpair;
75
76
0
    cfl_sds_cat_safe(buf, "{", 1);
77
78
0
    count = 0;
79
0
    cfl_list_foreach(head, &kvlist->list) {
80
0
        kvpair = cfl_list_entry(head, struct cfl_kvpair, _head);
81
82
0
        if (count > 0) {
83
0
            cfl_sds_cat_safe(buf, ", ", 2);
84
0
        }
85
86
0
        cfl_sds_cat_safe(buf, kvpair->key, cfl_sds_len(kvpair->key));
87
0
        cfl_sds_cat_safe(buf, "=", 1);
88
0
        append_variant_value(buf, kvpair->val);
89
90
0
        count++;
91
0
    }
92
93
0
    cfl_sds_cat_safe(buf, "}", 1);
94
0
}
95
96
static void append_array_value(cfl_sds_t *buf, struct cfl_array *array)
97
0
{
98
0
    size_t index;
99
0
    struct cfl_variant *entry;
100
101
0
    cfl_sds_cat_safe(buf, "[", 1);
102
103
0
    for (index = 0; index < array->entry_count; index++) {
104
0
        entry = cfl_array_fetch_by_index(array, index);
105
0
        if (entry == NULL) {
106
0
            continue;
107
0
        }
108
109
0
        if (index > 0) {
110
0
            cfl_sds_cat_safe(buf, ", ", 2);
111
0
        }
112
113
0
        append_variant_value(buf, entry);
114
0
    }
115
116
0
    cfl_sds_cat_safe(buf, "]", 1);
117
0
}
118
119
static void append_bytes_value(cfl_sds_t *buf, char *bytes)
120
0
{
121
0
    size_t index;
122
0
    size_t length;
123
0
    char tmp[4];
124
0
    int len;
125
126
0
    length = cfl_sds_len(bytes);
127
128
0
    for (index = 0; index < length; index++) {
129
0
        len = snprintf(tmp, sizeof(tmp), "%02x", (unsigned char) bytes[index]);
130
0
        cfl_sds_cat_safe(buf, tmp, len);
131
0
    }
132
0
}
133
134
static void append_variant_value(cfl_sds_t *buf, struct cfl_variant *value)
135
0
{
136
0
    char tmp[128];
137
0
    int len;
138
139
0
    if (value == NULL) {
140
0
        cfl_sds_cat_safe(buf, "null", 4);
141
0
        return;
142
0
    }
143
144
0
    if (value->type == CFL_VARIANT_STRING || value->type == CFL_VARIANT_REFERENCE) {
145
0
        cfl_sds_cat_safe(buf, "\"", 1);
146
0
        cfl_sds_cat_safe(buf, value->data.as_string, cfl_sds_len(value->data.as_string));
147
0
        cfl_sds_cat_safe(buf, "\"", 1);
148
0
    }
149
0
    else if (value->type == CFL_VARIANT_BOOL) {
150
0
        cfl_sds_cat_safe(buf, value->data.as_bool ? "true" : "false",
151
0
                         value->data.as_bool ? 4 : 5);
152
0
    }
153
0
    else if (value->type == CFL_VARIANT_INT) {
154
0
        len = snprintf(tmp, sizeof(tmp), "%" PRId64, value->data.as_int64);
155
0
        cfl_sds_cat_safe(buf, tmp, len);
156
0
    }
157
0
    else if (value->type == CFL_VARIANT_UINT) {
158
0
        len = snprintf(tmp, sizeof(tmp), "%" PRIu64, value->data.as_uint64);
159
0
        cfl_sds_cat_safe(buf, tmp, len);
160
0
    }
161
0
    else if (value->type == CFL_VARIANT_DOUBLE) {
162
0
        len = snprintf(tmp, sizeof(tmp), "%.17g", value->data.as_double);
163
0
        cfl_sds_cat_safe(buf, tmp, len);
164
0
    }
165
0
    else if (value->type == CFL_VARIANT_BYTES) {
166
0
        append_bytes_value(buf, value->data.as_bytes);
167
0
    }
168
0
    else if (value->type == CFL_VARIANT_ARRAY) {
169
0
        append_array_value(buf, value->data.as_array);
170
0
    }
171
0
    else if (value->type == CFL_VARIANT_KVLIST) {
172
0
        append_kvlist_value(buf, value->data.as_kvlist);
173
0
    }
174
0
    else {
175
0
        cfl_sds_cat_safe(buf, "<unsupported>", 13);
176
0
    }
177
0
}
178
179
static struct cfl_kvlist *get_data_point_metadata_context(struct cmt *cmt,
180
                                                          struct cmt_map *map,
181
                                                          struct cmt_metric *metric)
182
0
{
183
0
    struct cfl_kvlist *otlp_root;
184
0
    struct cfl_kvlist *metrics_root;
185
0
    struct cfl_kvlist *type_root;
186
0
    struct cfl_kvlist *metric_context;
187
0
    struct cfl_kvlist *datapoints_context;
188
0
    const char *type_key;
189
0
    char key[128];
190
191
0
    type_key = map_type_to_otlp_key(map->type);
192
0
    if (type_key == NULL) {
193
0
        return NULL;
194
0
    }
195
196
0
    otlp_root = fetch_metadata_kvlist_key(cmt->external_metadata, "otlp");
197
0
    if (otlp_root == NULL) {
198
0
        return NULL;
199
0
    }
200
201
0
    metrics_root = fetch_metadata_kvlist_key(otlp_root, "metrics");
202
0
    if (metrics_root == NULL) {
203
0
        return NULL;
204
0
    }
205
206
0
    type_root = fetch_metadata_kvlist_key(metrics_root, type_key);
207
0
    if (type_root == NULL) {
208
0
        return NULL;
209
0
    }
210
211
0
    metric_context = fetch_metadata_kvlist_key(type_root, map->opts->fqname);
212
0
    if (metric_context == NULL) {
213
0
        return NULL;
214
0
    }
215
216
0
    datapoints_context = fetch_metadata_kvlist_key(metric_context, "datapoints");
217
0
    if (datapoints_context == NULL) {
218
0
        return NULL;
219
0
    }
220
221
0
    snprintf(key, sizeof(key) - 1, "%" PRIx64 ":%" PRIu64,
222
0
             metric != NULL ? metric->hash : 0,
223
0
             metric != NULL ? cmt_metric_get_timestamp(metric) : 0);
224
225
0
    return fetch_metadata_kvlist_key(datapoints_context, key);
226
0
}
227
228
static void append_metric_exemplars(struct cmt *cmt,
229
                                    cfl_sds_t *buf,
230
                                    struct cmt_map *map,
231
                                    struct cmt_metric *metric)
232
0
{
233
0
    struct cfl_kvlist *point_metadata;
234
0
    struct cfl_variant *exemplars_variant;
235
0
    struct cfl_array *exemplars;
236
0
    struct cfl_variant *entry;
237
0
    size_t index;
238
239
0
    point_metadata = get_data_point_metadata_context(cmt, map, metric);
240
0
    if (point_metadata == NULL) {
241
0
        return;
242
0
    }
243
244
0
    exemplars_variant = cfl_kvlist_fetch(point_metadata, "exemplars");
245
0
    if (exemplars_variant == NULL || exemplars_variant->type != CFL_VARIANT_ARRAY) {
246
0
        return;
247
0
    }
248
249
0
    exemplars = exemplars_variant->data.as_array;
250
0
    if (exemplars == NULL || exemplars->entry_count == 0) {
251
0
        return;
252
0
    }
253
254
0
    cfl_sds_cat_safe(buf, "  exemplars=[", 13);
255
256
0
    for (index = 0; index < exemplars->entry_count; index++) {
257
0
        entry = cfl_array_fetch_by_index(exemplars, index);
258
259
0
        if (entry == NULL || entry->type != CFL_VARIANT_KVLIST) {
260
0
            continue;
261
0
        }
262
263
0
        if (index > 0) {
264
0
            cfl_sds_cat_safe(buf, ", ", 2);
265
0
        }
266
267
0
        append_kvlist_value(buf, entry->data.as_kvlist);
268
0
    }
269
270
0
    cfl_sds_cat_safe(buf, "]\n", 2);
271
0
}
272
273
static void append_histogram_metric_value(cfl_sds_t *buf,
274
                                          struct cmt_map *map,
275
                                          struct cmt_metric *metric)
276
0
{
277
0
    char                         *bucket_value_format_string;
278
0
    size_t                        entry_buffer_length;
279
0
    size_t                        entry_buffer_index;
280
0
    char                          entry_buffer[256];
281
0
    struct cmt_histogram         *histogram;
282
0
    struct cmt_histogram_buckets *buckets;
283
0
    size_t                        index;
284
285
0
    histogram = (struct cmt_histogram *) map->parent;
286
0
    buckets = histogram->buckets;
287
288
0
    cfl_sds_cat_safe(buf, " = { buckets = { ", 17);
289
290
0
    for (index = 0 ; index <= buckets->count ; index++) {
291
0
        if (index < buckets->count) {
292
0
            entry_buffer_index = snprintf(entry_buffer,
293
0
                                           sizeof(entry_buffer) - 1,
294
0
                                           "%g",
295
0
                                           buckets->upper_bounds[index]);
296
297
0
            bucket_value_format_string = "=%" PRIu64 ", ";
298
0
        }
299
0
        else {
300
0
            entry_buffer_index = snprintf(entry_buffer,
301
0
                                           sizeof(entry_buffer) - 1,
302
0
                                           "+Inf");
303
304
0
            bucket_value_format_string = "=%" PRIu64 " ";
305
0
        }
306
307
0
        entry_buffer_length = entry_buffer_index;
308
309
0
        entry_buffer_length += snprintf(&entry_buffer[entry_buffer_index],
310
0
                                        sizeof(entry_buffer) - 1 -
311
0
                                        entry_buffer_index,
312
0
                                        bucket_value_format_string,
313
0
                                        cmt_metric_hist_get_value(metric,
314
0
                                                                  index));
315
316
0
        cfl_sds_cat_safe(buf, entry_buffer, entry_buffer_length);
317
0
    }
318
319
0
    cfl_sds_cat_safe(buf, "}, ", 3);
320
321
0
    entry_buffer_length = snprintf(entry_buffer,
322
0
                                   sizeof(entry_buffer) - 1 ,
323
0
                                   "sum=%g, ",
324
0
                                   cmt_metric_hist_get_sum_value(metric));
325
326
0
    cfl_sds_cat_safe(buf, entry_buffer, entry_buffer_length);
327
328
0
    entry_buffer_length = snprintf(entry_buffer,
329
0
                                   sizeof(entry_buffer) - 1 ,
330
0
                                   "count=%" PRIu64 ,
331
0
                                   cmt_metric_hist_get_count_value(metric));
332
333
0
    cfl_sds_cat_safe(buf, entry_buffer, entry_buffer_length);
334
335
0
    cfl_sds_cat_safe(buf, " }\n", 3);
336
0
}
337
338
static void append_summary_metric_value(cfl_sds_t *buf,
339
                                        struct cmt_map *map,
340
                                        struct cmt_metric *metric)
341
0
{
342
0
    char               *quantile_pair_format_string;
343
0
    size_t              entry_buffer_length;
344
0
    char                entry_buffer[256];
345
0
    struct cmt_summary *summary;
346
0
    size_t              index;
347
348
0
    summary = (struct cmt_summary *) map->parent;
349
350
0
    cfl_sds_cat_safe(buf, " = { quantiles = { ", 19);
351
352
0
    for (index = 0 ; index < summary->quantiles_count ; index++) {
353
0
        if (index < summary->quantiles_count - 1) {
354
0
            quantile_pair_format_string = "%g=%g, ";
355
0
        }
356
0
        else {
357
0
            quantile_pair_format_string = "%g=%g ";
358
0
        }
359
360
0
        entry_buffer_length = snprintf(entry_buffer,
361
0
                                       sizeof(entry_buffer) - 1,
362
0
                                       quantile_pair_format_string,
363
0
                                       summary->quantiles[index],
364
0
                                       cmt_summary_quantile_get_value(metric,
365
0
                                                                      index));
366
367
0
        cfl_sds_cat_safe(buf, entry_buffer, entry_buffer_length);
368
0
    }
369
370
0
    cfl_sds_cat_safe(buf, "}, ", 3);
371
372
0
    entry_buffer_length = snprintf(entry_buffer,
373
0
                                   sizeof(entry_buffer) - 1 ,
374
0
                                   "sum=%g, ",
375
0
                                   cmt_summary_get_sum_value(metric));
376
377
0
    cfl_sds_cat_safe(buf, entry_buffer, entry_buffer_length);
378
379
0
    entry_buffer_length = snprintf(entry_buffer,
380
0
                                   sizeof(entry_buffer) - 1 ,
381
0
                                   "count=%" PRIu64,
382
0
                                   cmt_summary_get_count_value(metric));
383
384
0
    cfl_sds_cat_safe(buf, entry_buffer, entry_buffer_length);
385
386
0
    cfl_sds_cat_safe(buf, " }\n", 3);
387
0
}
388
389
static void append_exp_histogram_metric_value(cfl_sds_t *buf,
390
                                              struct cmt_metric *metric)
391
0
{
392
0
    struct cmt_exp_histogram_snapshot snapshot;
393
0
    size_t entry_buffer_length;
394
0
    char entry_buffer[256];
395
0
    size_t index;
396
397
0
    if (cmt_metric_exp_hist_get_snapshot(metric, &snapshot) != 0) {
398
0
        return;
399
0
    }
400
401
0
    cfl_sds_cat_safe(buf, " = { ", 5);
402
403
0
    entry_buffer_length = snprintf(entry_buffer,
404
0
                                   sizeof(entry_buffer) - 1,
405
0
                                   "scale=%d, zero_count=%" PRIu64 ", zero_threshold=%.17g, ",
406
0
                                   snapshot.scale,
407
0
                                   snapshot.zero_count,
408
0
                                   snapshot.zero_threshold);
409
0
    cfl_sds_cat_safe(buf, entry_buffer, entry_buffer_length);
410
411
0
    entry_buffer_length = snprintf(entry_buffer,
412
0
                                   sizeof(entry_buffer) - 1,
413
0
                                   "positive={offset=%d, bucket_counts=[",
414
0
                                   snapshot.positive_offset);
415
0
    cfl_sds_cat_safe(buf, entry_buffer, entry_buffer_length);
416
417
0
    for (index = 0; index < snapshot.positive_count; index++) {
418
0
        entry_buffer_length = snprintf(entry_buffer,
419
0
                                       sizeof(entry_buffer) - 1,
420
0
                                       "%" PRIu64 "%s",
421
0
                                       snapshot.positive_buckets[index],
422
0
                                       (index + 1 < snapshot.positive_count) ? ", " : "");
423
0
        cfl_sds_cat_safe(buf, entry_buffer, entry_buffer_length);
424
0
    }
425
426
0
    cfl_sds_cat_safe(buf, "]}, ", 4);
427
428
0
    entry_buffer_length = snprintf(entry_buffer,
429
0
                                   sizeof(entry_buffer) - 1,
430
0
                                   "negative={offset=%d, bucket_counts=[",
431
0
                                   snapshot.negative_offset);
432
0
    cfl_sds_cat_safe(buf, entry_buffer, entry_buffer_length);
433
434
0
    for (index = 0; index < snapshot.negative_count; index++) {
435
0
        entry_buffer_length = snprintf(entry_buffer,
436
0
                                       sizeof(entry_buffer) - 1,
437
0
                                       "%" PRIu64 "%s",
438
0
                                       snapshot.negative_buckets[index],
439
0
                                       (index + 1 < snapshot.negative_count) ? ", " : "");
440
0
        cfl_sds_cat_safe(buf, entry_buffer, entry_buffer_length);
441
0
    }
442
443
0
    cfl_sds_cat_safe(buf, "]}, ", 4);
444
445
0
    entry_buffer_length = snprintf(entry_buffer,
446
0
                                   sizeof(entry_buffer) - 1,
447
0
                                   "count=%" PRIu64,
448
0
                                   snapshot.count);
449
0
    cfl_sds_cat_safe(buf, entry_buffer, entry_buffer_length);
450
451
0
    if (snapshot.sum_set) {
452
0
        entry_buffer_length = snprintf(entry_buffer,
453
0
                                       sizeof(entry_buffer) - 1,
454
0
                                       ", sum=%.17g",
455
0
                                       cmt_math_uint64_to_d64(snapshot.sum));
456
0
    }
457
0
    else {
458
0
        entry_buffer_length = snprintf(entry_buffer,
459
0
                                       sizeof(entry_buffer) - 1,
460
0
                                       ", sum=unset");
461
0
    }
462
0
    cfl_sds_cat_safe(buf, entry_buffer, entry_buffer_length);
463
464
0
    cfl_sds_cat_safe(buf, " }\n", 3);
465
0
    cmt_metric_exp_hist_snapshot_destroy(&snapshot);
466
0
}
467
468
static void append_metric_value(cfl_sds_t *buf, struct cmt_map *map,
469
                                struct cmt_metric *metric)
470
0
{
471
0
    int len;
472
0
    double val;
473
0
    char tmp[128];
474
475
0
    if (map->type == CMT_HISTOGRAM) {
476
0
        return append_histogram_metric_value(buf, map, metric);
477
0
    }
478
0
    else if (map->type == CMT_EXP_HISTOGRAM) {
479
0
        return append_exp_histogram_metric_value(buf, metric);
480
0
    }
481
0
    else if (map->type == CMT_SUMMARY) {
482
0
        return append_summary_metric_value(buf, map, metric);
483
0
    }
484
485
    /* Retrieve metric value */
486
0
    val = cmt_metric_get_value(metric);
487
488
0
    len = snprintf(tmp, sizeof(tmp) - 1, " = %.17g\n", val);
489
0
    cfl_sds_cat_safe(buf, tmp, len);
490
0
}
491
492
static void format_metric(struct cmt *cmt, cfl_sds_t *buf, struct cmt_map *map,
493
                          struct cmt_metric *metric)
494
0
{
495
0
    int i;
496
0
    int n;
497
0
    int len;
498
0
    int count = 0;
499
0
    int static_labels = 0;
500
0
    int label_key_count;
501
0
    int label_index;
502
0
    char tmp[128];
503
0
    uint64_t ts;
504
0
    struct tm tm;
505
0
    struct timespec tms;
506
0
    struct cmt_map_label *label_k;
507
0
    struct cmt_map_label *label_v;
508
0
    struct cfl_list *head;
509
0
    struct cmt_opts *opts;
510
0
    struct cmt_label *slabel;
511
512
0
    opts = map->opts;
513
514
    /* timestamp (RFC3339Nano) */
515
0
    ts = cmt_metric_get_timestamp(metric);
516
517
0
    cmt_time_from_ns(&tms, ts);
518
519
0
    cmt_platform_gmtime_r(&tms.tv_sec, &tm);
520
0
    len = strftime(tmp, sizeof(tmp) - 1, "%Y-%m-%dT%H:%M:%S.", &tm);
521
0
    cfl_sds_cat_safe(buf, tmp, len);
522
523
0
    len = snprintf(tmp, sizeof(tmp) - 1, "%09luZ ", tms.tv_nsec);
524
0
    cfl_sds_cat_safe(buf, tmp, len);
525
526
    /* Metric info */
527
0
    cfl_sds_cat_safe(buf, opts->fqname, cfl_sds_len(opts->fqname));
528
529
    /* Static labels */
530
0
    static_labels = cmt_labels_count(cmt->static_labels);
531
0
    if (static_labels > 0) {
532
0
        cfl_sds_cat_safe(buf, "{", 1);
533
0
        cfl_list_foreach(head, &cmt->static_labels->list) {
534
0
            count++;
535
0
            slabel = cfl_list_entry(head, struct cmt_label, _head);
536
0
            cfl_sds_cat_safe(buf, slabel->key, cfl_sds_len(slabel->key));
537
0
            cfl_sds_cat_safe(buf, "=\"", 2);
538
0
            cfl_sds_cat_safe(buf, slabel->val, cfl_sds_len(slabel->val));
539
0
            cfl_sds_cat_safe(buf, "\"", 1);
540
541
0
            if (count < static_labels) {
542
0
                cfl_sds_cat_safe(buf, ",", 1);
543
0
            }
544
0
        }
545
0
    }
546
547
0
    n = 0;
548
0
    label_key_count = map->label_count;
549
0
    label_index = 0;
550
0
    if (label_key_count > 0) {
551
0
        label_k = cfl_list_entry_first(&map->label_keys, struct cmt_map_label, _head);
552
0
    }
553
0
    cfl_list_foreach(head, &metric->labels) {
554
0
        if (label_index >= label_key_count) {
555
0
            break;
556
0
        }
557
558
0
        label_v = cfl_list_entry(head, struct cmt_map_label, _head);
559
560
0
        if (label_k->name != NULL && label_v->name != NULL) {
561
0
            n++;
562
0
        }
563
564
0
        label_index++;
565
0
        label_k = cfl_list_entry_next(&label_k->_head, struct cmt_map_label,
566
0
                                      _head, &map->label_keys);
567
0
    }
568
569
0
    if (n > 0) {
570
0
        if (static_labels > 0) {
571
0
            cfl_sds_cat_safe(buf, ",", 1);
572
0
        }
573
0
        else {
574
0
            cfl_sds_cat_safe(buf, "{", 1);
575
0
        }
576
577
0
        label_index = 0;
578
0
        label_k = cfl_list_entry_first(&map->label_keys, struct cmt_map_label, _head);
579
580
0
        i = 1;
581
0
        cfl_list_foreach(head, &metric->labels) {
582
0
            if (label_index >= label_key_count) {
583
0
                break;
584
0
            }
585
586
0
            label_v = cfl_list_entry(head, struct cmt_map_label, _head);
587
588
0
            if (label_k->name == NULL || label_v->name == NULL) {
589
0
                label_index++;
590
0
                label_k = cfl_list_entry_next(&label_k->_head, struct cmt_map_label,
591
0
                                              _head, &map->label_keys);
592
0
                continue;
593
0
            }
594
595
0
            cfl_sds_cat_safe(buf, label_k->name, cfl_sds_len(label_k->name));
596
0
            cfl_sds_cat_safe(buf, "=\"", 2);
597
0
            cfl_sds_cat_safe(buf, label_v->name, cfl_sds_len(label_v->name));
598
599
0
            if (i < n) {
600
0
                cfl_sds_cat_safe(buf, "\",", 2);
601
0
            }
602
0
            else {
603
0
                cfl_sds_cat_safe(buf, "\"", 1);
604
0
            }
605
0
            i++;
606
607
0
            label_index++;
608
0
            label_k = cfl_list_entry_next(&label_k->_head, struct cmt_map_label,
609
0
                                          _head, &map->label_keys);
610
0
        }
611
0
        cfl_sds_cat_safe(buf, "}", 1);
612
613
0
        append_metric_value(buf, map, metric);
614
0
        append_metric_exemplars(cmt, buf, map, metric);
615
0
    }
616
0
    else {
617
0
        if (static_labels > 0) {
618
0
            cfl_sds_cat_safe(buf, "}", 1);
619
0
        }
620
0
        append_metric_value(buf, map, metric);
621
0
        append_metric_exemplars(cmt, buf, map, metric);
622
0
    }
623
0
}
624
625
static void format_metrics(struct cmt *cmt, cfl_sds_t *buf, struct cmt_map *map)
626
0
{
627
0
    struct cfl_list *head;
628
0
    struct cmt_metric *metric;
629
630
    /* Simple metric, no labels */
631
0
    if (map->metric_static_set == 1) {
632
0
        format_metric(cmt, buf, map, &map->metric);
633
0
    }
634
635
0
    cfl_list_foreach(head, &map->metrics) {
636
0
        metric = cfl_list_entry(head, struct cmt_metric, _head);
637
0
        format_metric(cmt, buf, map, metric);
638
0
    }
639
0
}
640
641
/* Format all the registered metrics in Prometheus Text format */
642
cfl_sds_t cmt_encode_text_create(struct cmt *cmt)
643
0
{
644
0
    cfl_sds_t buf;
645
0
    struct cfl_list *head;
646
0
    struct cmt_counter *counter;
647
0
    struct cmt_gauge *gauge;
648
0
    struct cmt_untyped *untyped;
649
0
    struct cmt_summary *summary;
650
0
    struct cmt_histogram *histogram;
651
0
    struct cmt_exp_histogram *exp_histogram;
652
653
    /* Allocate a 1KB of buffer */
654
0
    buf = cfl_sds_create_size(1024);
655
0
    if (!buf) {
656
0
        return NULL;
657
0
    }
658
659
    /* Counters */
660
0
    cfl_list_foreach(head, &cmt->counters) {
661
0
        counter = cfl_list_entry(head, struct cmt_counter, _head);
662
0
        format_metrics(cmt, &buf, counter->map);
663
0
    }
664
665
    /* Gauges */
666
0
    cfl_list_foreach(head, &cmt->gauges) {
667
0
        gauge = cfl_list_entry(head, struct cmt_gauge, _head);
668
0
        format_metrics(cmt, &buf, gauge->map);
669
0
    }
670
671
    /* Summaries */
672
0
    cfl_list_foreach(head, &cmt->summaries) {
673
0
        summary = cfl_list_entry(head, struct cmt_summary, _head);
674
0
        format_metrics(cmt, &buf, summary->map);
675
0
    }
676
677
    /* Histograms */
678
0
    cfl_list_foreach(head, &cmt->histograms) {
679
0
        histogram = cfl_list_entry(head, struct cmt_histogram, _head);
680
0
        format_metrics(cmt, &buf, histogram->map);
681
0
    }
682
683
    /* Exponential Histograms */
684
0
    cfl_list_foreach(head, &cmt->exp_histograms) {
685
0
        exp_histogram = cfl_list_entry(head, struct cmt_exp_histogram, _head);
686
0
        format_metrics(cmt, &buf, exp_histogram->map);
687
0
    }
688
689
    /* Untyped */
690
0
    cfl_list_foreach(head, &cmt->untypeds) {
691
0
        untyped = cfl_list_entry(head, struct cmt_untyped, _head);
692
0
        format_metrics(cmt, &buf, untyped->map);
693
0
    }
694
695
0
    return buf;
696
0
}
697
698
void cmt_encode_text_destroy(cfl_sds_t text)
699
0
{
700
0
    cfl_sds_destroy(text);
701
0
}