| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 | 
							-  /*
 
-  * libwebsockets - small server side websockets and web server implementation
 
-  *
 
-  * Copyright (C) 2010 - 2021 Andy Green <andy@warmcat.com>
 
-  *
 
-  * Permission is hereby granted, free of charge, to any person obtaining a copy
 
-  * of this software and associated documentation files (the "Software"), to
 
-  * deal in the Software without restriction, including without limitation the
 
-  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 
-  * sell copies of the Software, and to permit persons to whom the Software is
 
-  * furnished to do so, subject to the following conditions:
 
-  *
 
-  * The above copyright notice and this permission notice shall be included in
 
-  * all copies or substantial portions of the Software.
 
-  *
 
-  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
-  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
-  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 
-  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
-  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 
-  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 
-  * IN THE SOFTWARE.
 
-  *
 
-  * Public apis related to metric collection and reporting
 
-  */
 
- /* lws_metrics public part */
 
- typedef uint64_t u_mt_t;
 
- enum {
 
- 	LWSMTFL_REPORT_OUTLIERS				= (1 << 0),
 
- 	/**< track outliers and report them internally */
 
- 	LWSMTFL_REPORT_OOB				= (1 << 1),
 
- 	/**< report events as they happen */
 
- 	LWSMTFL_REPORT_INACTIVITY_AT_PERIODIC		= (1 << 2),
 
- 	/**< explicitly externally report no activity at periodic cb, by
 
- 	 * default no events in the period is just not reported */
 
- 	LWSMTFL_REPORT_MEAN				= (1 << 3),
 
- 	/**< average/min/max is meaningful, else only sum is meaningful */
 
- 	LWSMTFL_REPORT_ONLY_GO				= (1 << 4),
 
- 	/**< no-go pieces invalid */
 
- 	LWSMTFL_REPORT_DUTY_WALLCLOCK_US		= (1 << 5),
 
- 	/**< aggregate compares to wallclock us for duty cycle */
 
- 	LWSMTFL_REPORT_HIST				= (1 << 6),
 
- 	/**< our type is histogram (otherwise, sum / mean aggregation) */
 
- };
 
- /*
 
-  * lws_metrics_tag allows your object to accumulate OpenMetrics-style
 
-  * descriptive tags before accounting for it with a metrics object at the end.
 
-  *
 
-  * Tags should represent low entropy information that is likely to repeat
 
-  * identically, so, eg, http method name, not eg, latency in us which is
 
-  * unlikely to be seen the same twice.
 
-  *
 
-  * Tags are just a list of name=value pairs, used for qualifying the final
 
-  * metrics entry with decorations in additional dimensions.  For example,
 
-  * rather than keep individual metrics on methods, scheme, mountpoint, result
 
-  * code, you can keep metrics on http transactions only, and qualify the
 
-  * transaction metrics entries with tags that can be queried on the metrics
 
-  * backend to get the finer-grained information.
 
-  *
 
-  * http_srv{code="404",mount="/",method="GET",scheme="http"} 3
 
-  *
 
-  * For OpenMetrics the tags are converted to a { list } and appended to the base
 
-  * metrics name before using with actual metrics objects, the same set of tags
 
-  * on different transactions resolve to the same qualification string.
 
-  */
 
- typedef struct lws_metrics_tag {
 
- 	lws_dll2_t	list;
 
- 	const char	*name; /* tag, intended to be in .rodata, not copied */
 
- 	/* overallocated value */
 
- } lws_metrics_tag_t;
 
- LWS_EXTERN LWS_VISIBLE int
 
- lws_metrics_tag_add(lws_dll2_owner_t *owner, const char *name, const char *val);
 
- #if defined(LWS_WITH_SYS_METRICS)
 
- /*
 
-  * wsi-specific version that also appends the tag value to the lifecycle tag
 
-  * used for logging the wsi identity
 
-  */
 
- LWS_EXTERN LWS_VISIBLE int
 
- lws_metrics_tag_wsi_add(struct lws *wsi, const char *name, const char *val);
 
- #else
 
- #define lws_metrics_tag_wsi_add(_a, _b, _c)
 
- #endif
 
- #if defined(LWS_WITH_SECURE_STREAMS)
 
- /*
 
-  * ss-specific version that also appends the tag value to the lifecycle tag
 
-  * used for logging the ss identity
 
-  */
 
- #if defined(LWS_WITH_SYS_METRICS)
 
- LWS_EXTERN LWS_VISIBLE int
 
- lws_metrics_tag_ss_add(struct lws_ss_handle *ss, const char *name, const char *val);
 
- #else
 
- #define lws_metrics_tag_ss_add(_a, _b, _c)
 
- #endif
 
- #endif
 
- LWS_EXTERN LWS_VISIBLE void
 
- lws_metrics_tags_destroy(lws_dll2_owner_t *owner);
 
- LWS_EXTERN LWS_VISIBLE size_t
 
- lws_metrics_tags_serialize(lws_dll2_owner_t *owner, char *buf, size_t len);
 
- LWS_EXTERN LWS_VISIBLE const char *
 
- lws_metrics_tag_get(lws_dll2_owner_t *owner, const char *name);
 
- /* histogram bucket */
 
- typedef struct lws_metric_bucket {
 
- 	struct lws_metric_bucket	*next;
 
- 	uint64_t			count;
 
- 	/* name + NUL is overallocated */
 
- } lws_metric_bucket_t;
 
- /* get overallocated name of bucket from bucket pointer */
 
- #define lws_metric_bucket_name_len(_b) (*((uint8_t *)&(_b)[1]))
 
- #define lws_metric_bucket_name(_b) (((const char *)&(_b)[1]) + 1)
 
- /*
 
-  * These represent persistent local event measurements.  They may aggregate
 
-  * a large number of events inbetween external dumping of summaries of the
 
-  * period covered, in two different ways
 
-  *
 
-  * 1) aggregation by sum or mean, to absorb multiple scalar readings
 
-  *
 
-  *  - go / no-go ratio counting
 
-  *  - mean averaging for, eg, latencies
 
-  *  - min / max for averaged values
 
-  *  - period the stats covers
 
-  *
 
-  * 2) aggregation by histogram, to absorb a range of outcomes that may occur
 
-  *    multiple times
 
-  *
 
-  *  - add named buckets to histogram
 
-  *  - bucket has a 64-bit count
 
-  *  - bumping a bucket just increments the count if already exists, else adds
 
-  *    a new one with count set to 1
 
-  *
 
-  * The same type with a union covers both cases.
 
-  *
 
-  * The lws_system ops api that hooks lws_metrics up to a metrics backend is
 
-  * given a pointer to these according to the related policy, eg, hourly, or
 
-  * every event passed straight through.
 
-  */
 
- typedef struct lws_metric_pub {
 
- 	const char		*name;
 
- 	/**< eg, "n.cn.dns", "vh.myendpoint" */
 
- 	void			*backend_opaque;
 
- 	/**< ignored by lws, backend handler completely owns it */
 
- 	lws_usec_t		us_first;
 
- 	/**< us time metric started collecting, reset to us_dumped at dump */
 
- 	lws_usec_t		us_last;
 
- 	/**< 0, or us time last event, reset to 0 at last dump */
 
- 	lws_usec_t		us_dumped;
 
- 	/**< 0 if never, else us time of last dump to external api */
 
- 	/* scope of data in .u is "since last dump" --> */
 
- 	union {
 
- 		/* aggregation, by sum or mean */
 
- 		struct {
 
- 			u_mt_t			sum[2];
 
- 			/**< go, no-go summed for mean or plan sum */
 
- 			u_mt_t			min;
 
- 			/**< smallest individual measurement */
 
- 			u_mt_t			max;
 
- 			/**< largest individual measurement */
 
- 			uint32_t		count[2];
 
- 			/**< go, no-go count of measurements in sum */
 
- 		} agg;
 
- 		/* histogram with dynamic named buckets */
 
- 		struct {
 
- 			lws_metric_bucket_t	*head;
 
- 			/**< first bucket in our bucket list */
 
- 			uint64_t		total_count;
 
- 			/**< total count in all of our buckets */
 
- 			uint32_t		list_size;
 
- 			/**< number of buckets in our bucket list */
 
- 		} hist;
 
- 	} u;
 
- 	uint8_t			flags;
 
- } lws_metric_pub_t;
 
- 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);
 
- /*
 
-  * Calipers are a helper struct for implementing "hanging latency" detection,
 
-  * where setting the start time and finding the end time may happen in more than
 
-  * one place.
 
-  *
 
-  * There are convenience wrappers to eliminate caliper definitions and code
 
-  * cleanly if WITH_SYS_METRICS is disabled for the build.
 
-  */
 
- struct lws_metric;
 
- typedef struct lws_metric_caliper {
 
- 	struct lws_dll2_owner	mtags_owner; /**< collect tags here during
 
- 					      * caliper lifetime */
 
- 	struct lws_metric	*mt; /**< NULL == inactive */
 
- 	lws_usec_t		us_start;
 
- } lws_metric_caliper_t;
 
- #if defined(LWS_WITH_SYS_METRICS)
 
- #define lws_metrics_caliper_compose(_name) \
 
- 		lws_metric_caliper_t _name;
 
- #define lws_metrics_caliper_bind(_name, _mt) \
 
- 	{ if (_name.mt) { \
 
- 		lwsl_err("caliper: overwrite %s\n", \
 
- 				lws_metrics_priv_to_pub(_name.mt)->name); \
 
- 		assert(0); } \
 
- 	  _name.mt = _mt; _name.us_start = lws_now_usecs(); }
 
- #define lws_metrics_caliper_declare(_name, _mt) \
 
- 	lws_metric_caliper_t _name = { .mt = _mt, .us_start = lws_now_usecs() }
 
- #define lws_metrics_caliper_report(_name, _go_nogo) \
 
- 	{ if (_name.us_start) { lws_metric_event(_name.mt, _go_nogo, \
 
- 			   (u_mt_t)(lws_now_usecs() - \
 
- 					   _name.us_start)); \
 
- 					  }  lws_metrics_caliper_done(_name);  }
 
- #define lws_metrics_caliper_report_hist(_name, pwsi) if (_name.mt) { \
 
- 		lws_metrics_hist_bump_priv_tagged(lws_metrics_priv_to_pub(_name.mt), \
 
- 						  &_name.mtags_owner, \
 
- 						  pwsi ? &((pwsi)->cal_conn.mtags_owner) : NULL); \
 
- 		lws_metrics_caliper_done(_name);  }
 
- #define lws_metrics_caliper_cancel(_name) { lws_metrics_caliper_done(_name); }
 
- #define lws_metrics_hist_bump(_mt, _name) \
 
- 		lws_metrics_hist_bump_(_mt, _name)
 
- #define lws_metrics_hist_bump_priv(_mt, _name) \
 
- 		lws_metrics_hist_bump_(lws_metrics_priv_to_pub(_mt), _name)
 
- #define lws_metrics_caliper_done(_name) { \
 
- 		_name.us_start = 0; _name.mt = NULL; \
 
- 		lws_metrics_tags_destroy(&_name.mtags_owner); }
 
- #else
 
- #define lws_metrics_caliper_compose(_name)
 
- #define lws_metrics_caliper_bind(_name, _mt)
 
- #define lws_metrics_caliper_declare(_name, _mp)
 
- #define lws_metrics_caliper_report(_name, _go_nogo)
 
- #define lws_metrics_caliper_report_hist(_name, pwsiconn)
 
- #define lws_metrics_caliper_cancel(_name)
 
- #define lws_metrics_hist_bump(_mt, _name)
 
- #define lws_metrics_hist_bump_priv(_mt, _name)
 
- #define lws_metrics_caliper_done(_name)
 
- #endif
 
- /**
 
-  * lws_metrics_format() - helper to format a metrics object for logging
 
-  *
 
-  * \param pub: public part of metrics object
 
-  * \param buf: output buffer to place string in
 
-  * \param len: available length of \p buf
 
-  *
 
-  * Helper for describing the state of a metrics object as a human-readable
 
-  * string, accounting for how its flags indicate what it contains.  This is not
 
-  * how you would report metrics, but during development it can be useful to
 
-  * log them inbetween possibily long report intervals.
 
-  *
 
-  * It uses the metric's flags to adapt the format shown appropriately, eg,
 
-  * as a histogram if LWSMTFL_REPORT_HIST etc
 
-  */
 
- LWS_EXTERN LWS_VISIBLE int
 
- lws_metrics_format(lws_metric_pub_t *pub, lws_metric_bucket_t **sub,
 
- 		   char *buf, size_t len);
 
- /**
 
-  * lws_metrics_hist_bump() - add or increment histogram bucket
 
-  *
 
-  * \param pub: public part of metrics object
 
-  * \param name: bucket name to increment
 
-  *
 
-  * Either increment the count of an existing bucket of the right name in the
 
-  * metrics object, or add a new bucket of the given name and set its count to 1.
 
-  *
 
-  * The metrics object must have been created with flag LWSMTFL_REPORT_HIST
 
-  *
 
-  * Normally, you will actually use the preprocessor wrapper
 
-  * lws_metrics_hist_bump() defined above, since this automatically takes care of
 
-  * removing itself from the build if WITH_SYS_METRICS is not defined, without
 
-  * needing any preprocessor conditionals.
 
-  */
 
- LWS_EXTERN LWS_VISIBLE int
 
- lws_metrics_hist_bump_(lws_metric_pub_t *pub, const char *name);
 
- LWS_VISIBLE LWS_EXTERN int
 
- lws_metrics_foreach(struct lws_context *ctx, void *user,
 
- 		    int (*cb)(lws_metric_pub_t *pub, void *user));
 
- LWS_VISIBLE LWS_EXTERN int
 
- lws_metrics_hist_bump_describe_wsi(struct lws *wsi, lws_metric_pub_t *pub,
 
- 				   const char *name);
 
- enum {
 
- 	LMT_NORMAL = 0,	/* related to successful events */
 
- 	LMT_OUTLIER,	/* related to successful events outside of bounds */
 
- 	LMT_FAIL,	/* related to failed events */
 
- 	LMT_COUNT,
 
- };
 
- typedef enum lws_metric_rpt {
 
- 	LMR_PERIODIC = 0,	/* we are reporting on a schedule */
 
- 	LMR_OUTLIER,		/* we are reporting the last outlier */
 
- } lws_metric_rpt_kind_t;
 
- #define METRES_GO	0
 
- #define METRES_NOGO	1
 
 
  |