Available from 1.9.19.
The uWSGI metrics subsystem allows you to manage “numbers” from your app.
While the caching subsystem got some math capabilities during the 1.9 development cycle, the metrics subsystem is optimized by design for storing numbers and applying functions over them. So, compared to the caching subsystem it’s way faster and requires a fraction of the memory.
When enabled, the metric subsystem configures a vast amount of metrics (like requests per-core, memory usage, etc) but, in addition to this, you can configure your own metrics, such as the number of active users or, say, hits of a particular URL, as well as the memory consumption of your app or the whole server.
To enable the metrics subsystem just add --enable-metrics to your options, or configure a stats pusher (see below).
The metrics subsystem is completely thread-safe.
By default uWSGI creates a lot of metrics (and more are planned), so before adding your own be sure uWSGI does not already expose the one(s) you need.
Each metric must have a name (containing only numbers, letters, underscores, dashes and dots) and an optional oid (required for mapping a metric to The embedded SNMP server).
Before dealing with metrics you need to understand the various types represented by each metric:
This is a generally-growing up number (like the number of requests).
This is a number that can increase or decrease dynamically (like the memory used by a worker, or CPU load).
This is an absolute number, like the memory of the whole server, or the size of the hard disk.
This is a virtual metric pointing to another one . You can use it to give different names to already existing metrics.
Once you define a metric type, you need to tell uWSGI how to ‘collect’ the specific metric.
There are various collectors available (and more can be added via plugins).
ptr – The value is collected from a memory pointer
file – the value is collected from a file
sum – the value is the sum of other metrics
avg – compute the algebraic average of the children (added in 1.9.20)
accumulator – always add the sum of children to the final value. See below for an example.
Round 1: child1 = 22, child2 = 17 -> metric_value = 39 Round 2: child1 = 26, child2 = 30 -> metric_value += 56
multiplier - Multiply the sum of children by the specified argument (arg1n).
child1 = 22, child2 = 17, arg1n = 3 -> metric_value = (22+17)*3
func - the value is computed calling a specific function every time
manual - the NULL collector. The value must be updated manually from applications using the metrics API.
You can define additional metrics to manage from your app.
The --metric option allows you to add more metrics.
It has two syntaxes: “simplified” and “keyval”.
uwsgi --http-socket :9090 --metric foobar
will create a metric ‘foobar’ with type ‘counter’, manual collector and no oid.
For creating advanced metrics you need the keyval way:
uwsgi --http-socket :9090 --metric name=foobar,type=gauge,oid=100.100.100
The following keys are available:
The ptr is currently unimplemented, while the other collector requires a bit of additional configuration:
collector=file requires arg1 for the filename and an optional arg1n for the so-called split value.
uwsgi --metric name=loadavg,type=gauge,collector=file,arg1=/proc/loadavg,arg1n=1,freq=3
This will add a ‘loadavg` metric, of type gauge, updated every 3 seconds with the content of /proc/loadavg. The content is split (using \n, \t, spaces, \r and zero as separator) and the item 1 (the returned array is zero-based) used as the return value.
The splitter is very powerful, making it possible to gather information from more complex files, such as /proc/meminfo.
uwsgi --metric name=memory,type=gauge,collector=file,arg1=/proc/meminfo,arg1n=4,freq=3
Once split, /proc/meminfo has the MemFree value in the 4th slot.
collector=sum requires the list of metrics that must be summed up. Each metric has the concept of ‘children’. The sum collector will sum the values of all of its children:
uwsgi --metric name=reqs,collector=sum,children=worker.1.requests;worker.2.requests
This will sum the value of worker.1.requests and worker.2.requests every second.
collector=func is a convenience collector avoiding you to write a whole plugin for adding a new collector.
Let’s define a C function (call the file mycollector.c or whatever you want):
int64_t my_collector(void *metric) {
return 173;
}
and build it as a shared library...
gcc -shared -o mycollector.so mycollector.c
now run uWSGI loading the library...
uwsgi --dlopen ./mycollector.so --metric name=mine,collector=func,arg1=my_collector,freq=10
this will call the C function my_collector every 10 seconds and will set the value of the metric ‘mine’ to its return value.
The function must returns an int64_t value. The argument it takes is a uwsgi_metric pointer. You generally do not need to parse the metric, so just casting to void will avoid headaches.
UNIX sysadmins love text files. They are generally the things they have to work on most of the time. If you want to make a UNIX sysadmin happy, just give him or her some text file to play with. (Or some coffee, or whiskey maybe, depending on their tastes. But generally, text files should do just fine.)
The metrics subsystem can expose all of its metrics in the form of text files in a directory:
uwsgi --metrics-dir mymetrics ...
The directory must exist in advance.
This will create a text file for each metric in the ‘mymetrics’ directory. The content of each file is the value of the metric (updated in real time).
Each file is mapped into the process address space, so do not worry if your virtual memory increases slightly.
When you restart a uWSGI instance, all of its metrics are reset.
This is generally the best thing to do, but if you want, you can restore the previous situation using the values stored in the metrics directory defined before.
Just add the --metrics-dir-restore option to force the metric subsystem to read-back the values from the metric directory before starting to collect values.
Your language plugins should expose at least the following api functions. Currently they are implemented in Perl, CPython, PyPy and Ruby
metric_get(name)
metric_set(name, value)
metric_set_max(name, value) – only set the metric name if the give value is greater than the one currently stored
metric_set_min(name, value) – only set the metric name if the give value is lower than the one currently stored
metric_set_max and metric_set_min can be used to avoid having to call metric_get when you need a metric to be set at a maximal or minimal value. Another simple use case is to use the avg collector to calculate an average between some max and min set metrics.
metric_inc(name[, delta])
metric_dec(name[, delta])
metric_mul(name[, delta])
metric_div(name[, delta])
metrics (tuple/array of metric keys, should be immutable and not-callable, currently unimplemented)
Collected metrics can be sent to external systems for analysis or chart generation.
Stats pushers are plugins aimed at sending metrics to those systems.
There are two kinds of stats pushers at the moment: JSON and raw.
The JSON stats pusher send the whole JSON stats blob (the same you get from the stats server), while ‘raw’ ones send the metrics list.
Currently available stats pushers:
This will store an rrd file for each metric in the specified directory. Each rrd file has a single data source named ‘metric’.
Usage:
uwsgi --rrdtool my_rrds ...
# or
uwsgi --stats-push rrdtool:my_rrds ...
By default the RRD files are updated every 300 seconds. You can tune this value with --rrdtool-freq
The librrd.so library is detected at runtime. If you need you can specify its absolute path with --rrdtool-lib.
Push metrics to a statsd server.
Usage:
uwsgi --stats-push statsd:127.0.0.1:8125,myinstance ...
Push metrics to a zabbix server.
The plugin exposes a --zabbix-template option that will generate a zabbix template (on stdout or in the specified file) containing all of the exposed metrics as trapper items.
Note
On some Zabbix versions you will need to authorize the IP addresses allowed to push items.
Usage:
uwsgi --stats-push zabbix:127.0.0.1:10051,myinstance ...
Push statistics (as JSON) the the specified MongoDB database.
Push metrics to a UDP server with the following format: <metric> <type> <value> (<type> is in the numeric form previously reported).
Example:
uwsgi --stats-push socket:127.0.0.1:8125,myinstance ...
You can configure one or more “thresholds” for each metric.
Once this limit is reached the specified alarm (see The uWSGI alarm subsystem (from 1.3)) is triggered.
Once the alarm is delivered you may choose to reset the counter to a specific value (generally 0), or continue triggering alarms with a specified rate.
[uwsgi]
...
metric-alarm = key=worker.0.avg_response_time,value=2000,alarm=overload,rate=30
metric-alarm = key=loadavg,value=3,alarm=overload,rate=120
metric-threshold = key=mycounter,value=1000,reset=0
...
Specifying an alarm is not required. Using the threshold value to automatically reset a metric is perfectly valid.
Note: --metric-threshold and --metric-alarm are aliases for the same option.
The The embedded SNMP server server exposes metrics starting from the 1.3.6.1.4.1.35156.17.3 OID.
For example to get the value of worker.0.requests:
snmpget -v2c -c <snmp_community> <snmp_addr>:<snmp_port> 1.3.6.1.4.1.35156.17.3.0.1
Remember: only metrics with an associated OID can be used via SNMP.
The ‘’router_metrics’’ plugin (builtin by default) adds a series of actions to the internal routing subsystem.
In addition to action, a route var named “metric” is added.
Example:
[uwsgi]
metric = mymetric
route = ^/foo metricinc:mymetric
route-run = log:the value of the metric 'mymetric' is ${metric[mymetric]}
log-format = %(time) - %(metric.mymetric)
You can access metrics values from your request logging format using the %(metric.xxx) placeholder:
[uwsgi]
log-format = [hello] %(time) %(metric.worker.0.requests)
This is a work in progress.
The best way to know which default metrics are exposed is enabling the stats server and querying it (or adding the --metrics-dir option).
If you want to write a plugin that will expose metrics, please add the OID namespace that you are going to use to the list below and make a pull request first.
This will ensure that all plugins are using unique OID namespaces.
Prefix all plugin metric names with plugin name to ensure no conflicts if same keys are used in multiple plugins (example plugin.myplugin.foo.bar, worker.1.plugin.myplugin.foo.bar)
- (3|4).100.1 - cheaper_busyness