1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 
3 /*  CMetrics
4  *  ========
5  *  Copyright 2021 Eduardo Silva <eduardo@calyptia.com>
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_log.h>
22 #include <cmetrics/cmt_map.h>
23 #include <cmetrics/cmt_metric.h>
24 #include <cmetrics/cmt_counter.h>
25 
cmt_counter_create(struct cmt * cmt,char * ns,char * subsystem,char * name,char * help,int label_count,char ** label_keys)26 struct cmt_counter *cmt_counter_create(struct cmt *cmt,
27                                        char *ns, char *subsystem,
28                                        char *name, char *help,
29                                        int label_count, char **label_keys)
30 {
31     int ret;
32     struct cmt_counter *counter;
33 
34     if (!ns) {
35         cmt_log_error(cmt, "null ns not allowed");
36         return NULL;
37     }
38 
39     if (!subsystem) {
40         cmt_log_error(cmt, "null subsystem not allowed");
41         return NULL;
42     }
43 
44     if (!name || strlen(name) == 0) {
45         cmt_log_error(cmt, "undefined name");
46         return NULL;
47     }
48 
49     if (!help || strlen(help) == 0) {
50         cmt_log_error(cmt, "undefined help");
51         return NULL;
52     }
53 
54     counter = calloc(1, sizeof(struct cmt_counter));
55     if (!counter) {
56         cmt_errno();
57         return NULL;
58     }
59     mk_list_add(&counter->_head, &cmt->counters);
60 
61     ret = cmt_opts_init(&counter->opts, ns, subsystem, name, help);
62     if (ret == -1) {
63         cmt_log_error(cmt, "unable to initialize options for counter");
64         cmt_counter_destroy(counter);
65         return NULL;
66     }
67 
68     /* Create the map */
69     counter->map = cmt_map_create(CMT_COUNTER, &counter->opts, label_count, label_keys);
70     if (!counter->map) {
71         cmt_log_error(cmt, "unable to allocate map for counter");
72         cmt_counter_destroy(counter);
73         return NULL;
74     }
75 
76     counter->cmt = cmt;
77     return counter;
78 }
79 
cmt_counter_allow_reset(struct cmt_counter * counter)80 void cmt_counter_allow_reset(struct cmt_counter *counter)
81 {
82     counter->allow_reset = 1;
83 }
84 
cmt_counter_destroy(struct cmt_counter * counter)85 int cmt_counter_destroy(struct cmt_counter *counter)
86 {
87     mk_list_del(&counter->_head);
88     cmt_opts_exit(&counter->opts);
89 
90     if (counter->map) {
91         cmt_map_destroy(counter->map);
92     }
93     free(counter);
94     return 0;
95 }
96 
cmt_counter_inc(struct cmt_counter * counter,uint64_t timestamp,int labels_count,char ** label_vals)97 int cmt_counter_inc(struct cmt_counter *counter,
98                     uint64_t timestamp,
99                     int labels_count, char **label_vals)
100 {
101     struct cmt_metric *metric;
102 
103     metric = cmt_map_metric_get(&counter->opts,
104                                 counter->map, labels_count, label_vals,
105                                 CMT_TRUE);
106     if (!metric) {
107         cmt_log_error(counter->cmt, "unable to retrieve metric: %s for counter %s_%s_%s",
108                       counter->map, counter->opts.ns, counter->opts.subsystem,
109                       counter->opts.name);
110         return -1;
111     }
112     cmt_metric_inc(metric, timestamp);
113     return 0;
114 }
115 
cmt_counter_add(struct cmt_counter * counter,uint64_t timestamp,double val,int labels_count,char ** label_vals)116 int cmt_counter_add(struct cmt_counter *counter, uint64_t timestamp, double val,
117                     int labels_count, char **label_vals)
118 {
119     struct cmt_metric *metric;
120 
121     metric = cmt_map_metric_get(&counter->opts,
122                                 counter->map, labels_count, label_vals,
123                                 CMT_TRUE);
124     if (!metric) {
125         cmt_log_error(counter->cmt, "unable to retrieve metric: %s for counter %s_%s_%s",
126                       counter->map, counter->opts.ns, counter->opts.subsystem,
127                       counter->opts.name);
128         return -1;
129     }
130     cmt_metric_add(metric, timestamp, val);
131     return 0;
132 }
133 
134 /* Set counter value, new value cannot be smaller than current value */
cmt_counter_set(struct cmt_counter * counter,uint64_t timestamp,double val,int labels_count,char ** label_vals)135 int cmt_counter_set(struct cmt_counter *counter, uint64_t timestamp, double val,
136                     int labels_count, char **label_vals)
137 {
138     struct cmt_metric *metric;
139 
140     metric = cmt_map_metric_get(&counter->opts, counter->map,
141                                 labels_count, label_vals,
142                                 CMT_TRUE);
143     if (!metric) {
144         cmt_log_error(counter->cmt, "unable to retrieve metric: %s for counter %s_%s_%s",
145                       counter->map, counter->opts.ns, counter->opts.subsystem,
146                       counter->opts.name);
147         return -1;
148     }
149 
150     if (cmt_metric_get_value(metric) > val && counter->allow_reset == 0) {
151         cmt_log_error(counter->cmt, "attempting to reset unresetable counter: %s_%s_%s",
152                       counter->opts.ns, counter->opts.subsystem,
153                       counter->opts.name);
154         return -1;
155     }
156     cmt_metric_set(metric, timestamp, val);
157     return 0;
158 }
159 
cmt_counter_get_val(struct cmt_counter * counter,int labels_count,char ** label_vals,double * out_val)160 int cmt_counter_get_val(struct cmt_counter *counter,
161                         int labels_count, char **label_vals, double *out_val)
162 {
163     int ret;
164     double val = 0;
165 
166     ret = cmt_map_metric_get_val(&counter->opts,
167                                  counter->map, labels_count, label_vals,
168                                  &val);
169     if (ret == -1) {
170         cmt_log_error(counter->cmt, "unable to retrieve metric: %s for counter %s_%s_%s",
171                       counter->map, counter->opts.ns, counter->opts.subsystem,
172                       counter->opts.name);
173         return -1;
174     }
175     *out_val = val;
176     return 0;
177 }
178