System Metrics
The logfire.instrument_system_metrics() method can be used to collect system metrics with Logfire, such as CPU and memory usage.
Install logfire with the system-metrics extra:
pip install 'logfire[system-metrics]'
uv add 'logfire[system-metrics]'
import logfire
logfire.configure()
logfire.instrument_system_metrics()
Your metrics then show up in several places in the Logfire UI:
- Hosts — the machine running your code appears automatically, with CPU, memory, load, disk, network and process-count charts per host.
- Metrics explorer — browse the
system.*metrics by namespace and break them down by dimension, no SQL required. - Dashboards — enable the built-in Basic System Metrics (Logfire) standard dashboard. Standard dashboards are read-only; to adjust it, use it as a template for a custom dashboard.
You can also query the metrics directly in the Explore view via the metrics
table (see the SQL reference).
The Hosts view identifies a machine by its host.name, which Logfire takes from socket.gethostname(). If that
isn’t meaningful — for example a random container ID — set a clearer value (or add other resource attributes such
as process.* or cloud metadata). See the SQL reference for how to set
and query resource attributes.
By default, instrument_system_metrics collects only the metrics it needs to display the ‘Basic System Metrics (Logfire)’ dashboard. You can choose exactly which metrics to collect and how much data to collect about each metric. The default is equivalent to this:
logfire.instrument_system_metrics({
'process.cpu.utilization': None, # (1)
'system.cpu.simple_utilization': None, # (2)
'system.memory.utilization': ['available'], # (3)
'system.swap.utilization': ['used'], # (4)
}) The None value means that there are no fields to configure for this metric. The value of this metric is psutil.Process().cpu_percent()/100, i.e. the fraction of CPU time used by this process, where 1 means using 100% of a single CPU core. The value can be greater than 1 if the process uses multiple cores.
The None value means that there are no fields to configure for this metric. The value of this metric is psutil.cpu_percent()/100, i.e. the fraction of CPU time used by the whole system, where 1 means using 100% of all CPU cores.
The value here is a list of 'modes' of memory. The full list can be seen in the psutil documentation. available is "the memory that can be given instantly to processes without the system going into swap. This is calculated by summing different memory metrics that vary depending on the platform. It is supposed to be used to monitor actual memory usage in a cross platform fashion." The value of the metric is a number between 0 and 1, and subtracting the value from 1 gives the fraction of memory used.
This is the fraction of available swap used. The value is a number between 0 and 1.
To collect lots of detailed data about all available metrics, use logfire.instrument_system_metrics(base='full').
logfire.instrument_system_metrics(base='full') is equivalent to:
logfire.instrument_system_metrics({
'system.cpu.simple_utilization': None,
'system.cpu.time': ['idle', 'user', 'system', 'irq', 'softirq', 'nice', 'iowait', 'steal', 'interrupt', 'dpc'],
'system.cpu.utilization': ['idle', 'user', 'system', 'irq', 'softirq', 'nice', 'iowait', 'steal', 'interrupt', 'dpc'],
'system.memory.usage': ['available', 'used', 'free', 'active', 'inactive', 'buffers', 'cached', 'shared', 'wired', 'slab', 'total'],
'system.memory.utilization': ['available', 'used', 'free', 'active', 'inactive', 'buffers', 'cached', 'shared', 'wired', 'slab'],
'system.swap.usage': ['used', 'free'],
'system.swap.utilization': ['used'],
'system.disk.io': ['read', 'write'],
'system.disk.operations': ['read', 'write'],
'system.disk.time': ['read', 'write'],
'system.network.dropped.packets': ['transmit', 'receive'],
'system.network.packets': ['transmit', 'receive'],
'system.network.errors': ['transmit', 'receive'],
'system.network.io': ['transmit', 'receive'],
'system.thread_count': None,
'process.context_switches': ['involuntary', 'voluntary'],
'process.runtime.gc_count': None,
'process.open_file_descriptor.count': None,
'process.cpu.time': ['user', 'system'],
'process.cpu.utilization': None,
'process.cpu.core_utilization': None,
'process.disk.io': ['read', 'write'],
'process.memory.usage': None,
'process.memory.virtual': None,
'process.thread.count': None,
'cpython.gc.collected_objects': None,
'cpython.gc.collections': None,
'cpython.gc.uncollectable_objects': None,
})
Each key here is a metric name. The values have different meanings for different metrics. For example, for system.cpu.utilization, the value is a list of CPU modes. So there will be a separate row for each CPU core saying what percentage of time it spent idle, another row for the time spent waiting for IO, etc. There are no fields to configure for system.thread_count, so the value is None.
For convenient customizability, the first dict argument is merged with the base. For example, if you want to collect disk read operations (but not writes) you can write:
logfire.instrument_system_metrics({'system.disk.operations': ['read']})to collect that data in addition to the basic defaults.logfire.instrument_system_metrics({'system.disk.operations': ['read']}, base='full')to collect detailed data about all metrics, excluding disk write operations.logfire.instrument_system_metrics({'system.disk.operations': ['read']}, base=None)to collect only disk read operations and nothing else.