libwebsockets
Lightweight C library for HTML5 websockets
lws-metrics.h
Go to the documentation of this file.
1  /*
2  * libwebsockets - small server side websockets and web server implementation
3  *
4  * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in
14  * all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  *
24  * Public apis related to metric collection and reporting
25  */
26 
27 /* lws_metrics public part */
28 
29 typedef uint64_t u_mt_t;
30 
31 enum {
32  LWSMTFL_REPORT_OUTLIERS = (1 << 0),
34  LWSMTFL_REPORT_OOB = (1 << 1),
39  LWSMTFL_REPORT_MEAN = (1 << 3),
41  LWSMTFL_REPORT_ONLY_GO = (1 << 4),
45  LWSMTFL_REPORT_HIST = (1 << 6),
47 };
48 
49 /*
50  * lws_metrics_tag allows your object to accumulate OpenMetrics-style
51  * descriptive tags before accounting for it with a metrics object at the end.
52  *
53  * Tags should represent low entropy information that is likely to repeat
54  * identically, so, eg, http method name, not eg, latency in us which is
55  * unlikely to be seen the same twice.
56  *
57  * Tags are just a list of name=value pairs, used for qualifying the final
58  * metrics entry with decorations in additional dimensions. For example,
59  * rather than keep individual metrics on methods, scheme, mountpoint, result
60  * code, you can keep metrics on http transactions only, and qualify the
61  * transaction metrics entries with tags that can be queried on the metrics
62  * backend to get the finer-grained information.
63  *
64  * http_srv{code="404",mount="/",method="GET",scheme="http"} 3
65  *
66  * For OpenMetrics the tags are converted to a { list } and appended to the base
67  * metrics name before using with actual metrics objects, the same set of tags
68  * on different transactions resolve to the same qualification string.
69  */
70 
71 typedef struct lws_metrics_tag {
73 
74  const char *name; /* tag, intended to be in .rodata, not copied */
75  /* overallocated value */
77 
79 lws_metrics_tag_add(lws_dll2_owner_t *owner, const char *name, const char *val);
80 
81 #if defined(LWS_WITH_SYS_METRICS)
82 /*
83  * wsi-specific version that also appends the tag value to the lifecycle tag
84  * used for logging the wsi identity
85  */
87 lws_metrics_tag_wsi_add(struct lws *wsi, const char *name, const char *val);
88 #else
89 #define lws_metrics_tag_wsi_add(_a, _b, _c)
90 #endif
91 
92 #if defined(LWS_WITH_SECURE_STREAMS)
93 /*
94  * ss-specific version that also appends the tag value to the lifecycle tag
95  * used for logging the ss identity
96  */
97 #if defined(LWS_WITH_SYS_METRICS)
99 lws_metrics_tag_ss_add(struct lws_ss_handle *ss, const char *name, const char *val);
100 #else
101 #define lws_metrics_tag_ss_add(_a, _b, _c)
102 #endif
103 #endif
104 
107 
108 LWS_EXTERN LWS_VISIBLE size_t
109 lws_metrics_tags_serialize(lws_dll2_owner_t *owner, char *buf, size_t len);
110 
111 LWS_EXTERN LWS_VISIBLE const char *
112 lws_metrics_tag_get(lws_dll2_owner_t *owner, const char *name);
113 
114 /* histogram bucket */
115 
116 typedef struct lws_metric_bucket {
118  uint64_t count;
119 
120  /* name + NUL is overallocated */
122 
123 /* get overallocated name of bucket from bucket pointer */
124 #define lws_metric_bucket_name_len(_b) (*((uint8_t *)&(_b)[1]))
125 #define lws_metric_bucket_name(_b) (((const char *)&(_b)[1]) + 1)
126 
127 /*
128  * These represent persistent local event measurements. They may aggregate
129  * a large number of events inbetween external dumping of summaries of the
130  * period covered, in two different ways
131  *
132  * 1) aggregation by sum or mean, to absorb multiple scalar readings
133  *
134  * - go / no-go ratio counting
135  * - mean averaging for, eg, latencies
136  * - min / max for averaged values
137  * - period the stats covers
138  *
139  * 2) aggregation by histogram, to absorb a range of outcomes that may occur
140  * multiple times
141  *
142  * - add named buckets to histogram
143  * - bucket has a 64-bit count
144  * - bumping a bucket just increments the count if already exists, else adds
145  * a new one with count set to 1
146  *
147  * The same type with a union covers both cases.
148  *
149  * The lws_system ops api that hooks lws_metrics up to a metrics backend is
150  * given a pointer to these according to the related policy, eg, hourly, or
151  * every event passed straight through.
152  */
153 
154 typedef struct lws_metric_pub {
155  const char *name;
167  /* scope of data in .u is "since last dump" --> */
168 
169  union {
170  /* aggregation, by sum or mean */
171 
172  struct {
173  u_mt_t sum[2];
175  u_mt_t min;
177  u_mt_t max;
180  uint32_t count[2];
182  } agg;
183 
184  /* histogram with dynamic named buckets */
185 
186  struct {
187  lws_metric_bucket_t *head;
190  uint64_t total_count;
192  uint32_t list_size;
194  } hist;
195  } u;
196 
198 
200 
203  lws_dll2_owner_t *tow2);
204 
205 
206 /*
207  * Calipers are a helper struct for implementing "hanging latency" detection,
208  * where setting the start time and finding the end time may happen in more than
209  * one place.
210  *
211  * There are convenience wrappers to eliminate caliper definitions and code
212  * cleanly if WITH_SYS_METRICS is disabled for the build.
213  */
214 
215 struct lws_metric;
216 
217 typedef struct lws_metric_caliper {
218  struct lws_dll2_owner mtags_owner;
220  struct lws_metric *mt;
223 
224 #if defined(LWS_WITH_SYS_METRICS)
225 #define lws_metrics_caliper_compose(_name) \
226  lws_metric_caliper_t _name;
227 #define lws_metrics_caliper_bind(_name, _mt) \
228  { if (_name.mt) { \
229  lwsl_err("caliper: overwrite %s\n", \
230  lws_metrics_priv_to_pub(_name.mt)->name); \
231  assert(0); } \
232  _name.mt = _mt; _name.us_start = lws_now_usecs(); }
233 #define lws_metrics_caliper_declare(_name, _mt) \
234  lws_metric_caliper_t _name = { .mt = _mt, .us_start = lws_now_usecs() }
235 #define lws_metrics_caliper_report(_name, _go_nogo) \
236  { if (_name.us_start) { lws_metric_event(_name.mt, _go_nogo, \
237  (u_mt_t)(lws_now_usecs() - \
238  _name.us_start)); \
239  } lws_metrics_caliper_done(_name); }
240 #define lws_metrics_caliper_report_hist(_name, pwsi) if (_name.mt) { \
241  lws_metrics_hist_bump_priv_tagged(lws_metrics_priv_to_pub(_name.mt), \
242  &_name.mtags_owner, \
243  pwsi ? &((pwsi)->cal_conn.mtags_owner) : NULL); \
244  lws_metrics_caliper_done(_name); }
245 
246 #define lws_metrics_caliper_cancel(_name) { lws_metrics_caliper_done(_name); }
247 #define lws_metrics_hist_bump(_mt, _name) \
248  lws_metrics_hist_bump_(_mt, _name)
249 #define lws_metrics_hist_bump_priv(_mt, _name) \
250  lws_metrics_hist_bump_(lws_metrics_priv_to_pub(_mt), _name)
251 #define lws_metrics_caliper_done(_name) { \
252  _name.us_start = 0; _name.mt = NULL; \
253  lws_metrics_tags_destroy(&_name.mtags_owner); }
254 #else
255 #define lws_metrics_caliper_compose(_name)
256 #define lws_metrics_caliper_bind(_name, _mt)
257 #define lws_metrics_caliper_declare(_name, _mp)
258 #define lws_metrics_caliper_report(_name, _go_nogo)
259 #define lws_metrics_caliper_report_hist(_name, pwsiconn)
260 #define lws_metrics_caliper_cancel(_name)
261 #define lws_metrics_hist_bump(_mt, _name)
262 #define lws_metrics_hist_bump_priv(_mt, _name)
263 #define lws_metrics_caliper_done(_name)
264 #endif
265 
283  char *buf, size_t len);
284 
302 lws_metrics_hist_bump_(lws_metric_pub_t *pub, const char *name);
303 
305 lws_metrics_foreach(struct lws_context *ctx, void *user,
306  int (*cb)(lws_metric_pub_t *pub, void *user));
307 
310  const char *name);
311 
312 enum {
313  LMT_NORMAL = 0, /* related to successful events */
314  LMT_OUTLIER, /* related to successful events outside of bounds */
315 
316  LMT_FAIL, /* related to failed events */
317 
319 };
320 
321 typedef enum lws_metric_rpt {
322  LMR_PERIODIC = 0, /* we are reporting on a schedule */
323  LMR_OUTLIER, /* we are reporting the last outlier */
325 
326 #define METRES_GO 0
327 #define METRES_NOGO 1
328 
329 
unsigned int uint32_t
#define LWS_EXTERN
int64_t lws_usec_t
unsigned char uint8_t
#define LWS_VISIBLE
LWS_EXTERN LWS_VISIBLE const char * lws_metrics_tag_get(lws_dll2_owner_t *owner, const char *name)
lws_usec_t us_first
Definition: lws-metrics.h:160
void * backend_opaque
Definition: lws-metrics.h:157
const char * name
Definition: lws-metrics.h:155
struct lws_metric_bucket lws_metric_bucket_t
LWS_EXTERN LWS_VISIBLE int lws_metrics_hist_bump_(lws_metric_pub_t *pub, const char *name)
lws_dll2_t list
Definition: lws-metrics.h:72
@ LWSMTFL_REPORT_OUTLIERS
Definition: lws-metrics.h:32
@ LWSMTFL_REPORT_ONLY_GO
Definition: lws-metrics.h:41
@ LWSMTFL_REPORT_INACTIVITY_AT_PERIODIC
Definition: lws-metrics.h:36
@ LWSMTFL_REPORT_OOB
Definition: lws-metrics.h:34
@ LWSMTFL_REPORT_HIST
Definition: lws-metrics.h:45
@ LWSMTFL_REPORT_DUTY_WALLCLOCK_US
Definition: lws-metrics.h:43
@ LWSMTFL_REPORT_MEAN
Definition: lws-metrics.h:39
lws_usec_t us_dumped
Definition: lws-metrics.h:164
lws_metric_rpt
Definition: lws-metrics.h:321
@ LMR_PERIODIC
Definition: lws-metrics.h:322
@ LMR_OUTLIER
Definition: lws-metrics.h:323
LWS_EXTERN LWS_VISIBLE int lws_metrics_format(lws_metric_pub_t *pub, lws_metric_bucket_t **sub, char *buf, size_t len)
struct lws_metric_bucket * next
Definition: lws-metrics.h:117
union lws_metric_pub::@24 u
LWS_EXTERN LWS_VISIBLE size_t lws_metrics_tags_serialize(lws_dll2_owner_t *owner, char *buf, size_t len)
struct lws_metrics_tag lws_metrics_tag_t
lws_usec_t us_start
Definition: lws-metrics.h:221
uint64_t u_mt_t
Definition: lws-metrics.h:29
@ LMT_OUTLIER
Definition: lws-metrics.h:314
@ LMT_COUNT
Definition: lws-metrics.h:318
@ LMT_NORMAL
Definition: lws-metrics.h:313
@ LMT_FAIL
Definition: lws-metrics.h:316
LWS_EXTERN LWS_VISIBLE void lws_metrics_tags_destroy(lws_dll2_owner_t *owner)
LWS_VISIBLE LWS_EXTERN int lws_metrics_foreach(struct lws_context *ctx, void *user, int(*cb)(lws_metric_pub_t *pub, void *user))
lws_usec_t us_last
Definition: lws-metrics.h:162
struct lws_metric_caliper lws_metric_caliper_t
struct lws_metric * mt
Definition: lws-metrics.h:220
LWS_EXTERN LWS_VISIBLE int lws_metrics_tag_add(lws_dll2_owner_t *owner, const char *name, const char *val)
struct lws_dll2_owner mtags_owner
Definition: lws-metrics.h:218
struct lws_metric_pub lws_metric_pub_t
enum lws_metric_rpt lws_metric_rpt_kind_t
#define lws_metrics_tag_wsi_add(_a, _b, _c)
Definition: lws-metrics.h:89
LWS_EXTERN LWS_VISIBLE void lws_metrics_hist_bump_priv_tagged(lws_metric_pub_t *mt, lws_dll2_owner_t *tow, lws_dll2_owner_t *tow2)
LWS_VISIBLE LWS_EXTERN int lws_metrics_hist_bump_describe_wsi(struct lws *wsi, lws_metric_pub_t *pub, const char *name)
const char * name
Definition: lws-metrics.h:74