Skip to content

0.6.4 — 2026-10-18

0.6.4 puts the network on the map from the agent’s host: full routing tables, SNMP discovery, Ethernet aggregates, ARP/NDP neighbours and the system services, with Kubernetes resource and pod log collection from a DaemonSet, severity derived from more log formats, Redis Sentinel and ACL support, clock synchronisation reporting, and an opt-in self-log rail. It also fixes identity handling, SNMP series labels, Redis empty databases, heartbeat jitter, export counters, and other issues, and makes the syslog receiver keep messages it cannot parse.

Before you upgrade

  • systemd and winservices watch fewer services and emit one series each. With no list configured they watch only what the supervisor starts by itself (enabled units, automatic services) instead of every unit or service, and emit one state series per service; detail: full restores the other families. A configuration that names its units or services keeps them.
  • The system services probe and, on Docker hosts, the Swarm probe are now default. The upgrade adds probes.d/05-services.yaml (systemd on Linux, winservices on Windows) and, where /var/run/docker.sock exists, probes.d/06-swarm.yaml, unless a probe of that type is already configured. The services probe is added only where systemd runs (never in a container). Renaming a file to *.disabled is the supported opt-out. SENHUB_DEFAULT_PROBES=off in the agent's environment keeps it from adding either, for images and fleets whose configuration is managed elsewhere; the package honours it too. The agent and the package add the fragments once per host, so neither a restart nor a later upgrade brings back one you removed. A legacy single-file configuration is left as it is.
  • PRTG sensors built on these probes change. A winservices or systemd sensor keeps one channel per watched service: the channels of services that are not started automatically and the per-service Status channels go, and a Check Result channel is added. A Windows cpu sensor loses its per-core detail channels (it keeps per-core usage and the total) and gains two Host Clock channels. To keep the previous channels, set detail: full on winservices / systemd (and list the services you watch), and per_core_details: true on cpu, before upgrading. Otherwise, after the upgrade, PRTG keeps the channels the agent no longer sends, without data: delete those channels from the sensor, or delete the sensor and add it again so it lists only the current channels. Memory, network and disk sensors are unchanged.
  • Leaner host defaults, each restorable. The network probe no longer collects container and virtualisation interfaces (veth, docker, br-, cni, flannel, cali, cilium, vxlan, …; Hyper-V vEthernet adapters are kept) nor the ip label on interface series; include_virtual_interfaces: true and address_label: true restore them. On Windows the cpu probe keeps per-core usage and the full total, and per_core_details: true restores the per-core user, privileged, interrupt and DPC series. The PRTG channels of the dropped series disappear unless the option is set.
  • Kubernetes containers have one producer. On a Kubernetes node the docker probe no longer publishes containers carrying io.kubernetes.pod.uid; the kubernetes cluster probe describes them.
  • SNMP topology is swept every minute by default. topology_interval of snmp_poll (and so the discovery crawl) goes from 10 minutes to 1 minute, so a link going down is on the map within a minute. Polled devices answer a few more SNMP walks per minute; set topology_interval back to 10m on a device that should be queried less often. Devices no longer carry mgmt.ip, which depended on the agent polling them; their addresses are network.address entities.
  • Metric series no longer carry the agent version. service.version is left off the metrics resource and the metric scope carries no version, so service_version and otel_scope_version labels disappear from every series in a Prometheus-like backend. Upgrading to 0.6.4 recreates the series once more; later upgrades no longer do. The version stays on logs, traces and senhub.agent.build.info.
  • SENHUB_HOST_ID is now read by the agent binary itself. Previously only the container entrypoint used it; the agent now honours a valid value directly (lowercase, dashed machine-id). Hosts run outside the official image that set SENHUB_HOST_ID will change identity; an invalid value is logged and ignored.
  • Hosts and SNMP devices now publish full routing tables. Each route appears as an entity with route.type, route.protocol, the egress interface and metric, capped at 500 per host or device; senhub.routes.omitted reports how many were left out. Topology consumers will receive these new entities and attributes.
  • SNMP device and interface metrics are born with their keys. network.device.id and network.interface.name are present from the first data point; previously a series could be emitted without them and later gain labels, creating a keyless orphan series.
  • An empty Redis database now reports db0 at zero. When Redis omits the keyspace line for an empty db, the probe publishes DB 0 Keys, DB 0 Expiring Keys and DB 0 Average TTL at 0 (except on Sentinel). Alerts that relied on the absence of these channels will see them appear.
  • The Redis replication role at -1 now reads “Sentinel or unknown”. It no longer says “Unknown” with a warning on every Sentinel.

Features

  • Kubernetes nodes as their own entity. The kubernetes probe publishes each node as k8s.node (its role in the cluster: kubelet version, runtime, schedulable, Ready and pressure conditions), joined by same_as to the host it runs on, which keeps the machine facts.
  • Select all / Clear in the URL builder. Each tag filter of the console's sensor URL builder starts with "Select all" and "Clear".
  • Kubernetes Grafana dashboards. kubernetes-workloads.json (node, pod and container resources from kubelet_stats) and kubernetes-logs.json (pod logs and their volume) in docs/grafana/.
  • Ethernet aggregates on the map (opt-in). LAG / LACP port-channels on switches and bonds or teams on Linux hosts and hypervisors: each member port is linked to its aggregate, with the aggregate's mode and, where it exists, each member's LACP or active-backup state, so a path no longer stops at an aggregate. entities.aggregation.enabled, off until the receiving Toise registers the relation.
  • Hosts say whether they route. senhub.host.ip_forwarding.ipv4 and .ipv6 on the host entity, so a multi-homed server is not drawn as a gateway.
  • Full routing tables on the map. Hosts and SNMP devices publish every route with its type (connected, remote, reject, blackhole), its origin (static, OSPF, BGP… in the IANA vocabulary), its egress interface and metric; each next hop of a multipath route is its own route, IPv6 included. Connected routes give the last hop of a path. A bound of 500 routes per host or device, with senhub.routes.omitted saying how many were left out. See SNMP Poll → Routes.
  • SNMP discovery maps the network from the agent's host. The discovery block of snmp_poll now runs: from its seeds it follows LLDP neighbours, within bounds, and puts every device found on the map with its interfaces, addresses, routes and links. Without seeds it starts from the host's default gateways, and without allowed_cidrs it stays inside the host's private networks, so a profile with the community is enough. senhub.snmp.discovery.* metrics report devices, runs, duration, failures and seeds.
  • ARP and NDP neighbours on the map (opt-in). Each neighbour in the host table becomes a network.neighbor entity identified by {host.id, mac}, carries its addresses and the interface it was seen on, with a neighbor_of relation to that interface. entities.neighbors.enabled turns it on; entities.neighbors.resolves_to adds a resolves_to edge to the interface that owns the MAC when this agent observed both ends (basis arp, ndp or fdb). Both are off by default: the receiving Toise must know the network.neighbor type, and register resolves_to before that edge is turned on.
  • Kubernetes resource metrics from the kubelet. The Helm DaemonSet enables kubelet_stats by default; the probe reads the kubelet Summary API for CPU, memory, filesystem and network of the node, pods and containers, named after the OTel k8s conventions, with namespace globs to narrow pods. The chart binds the required ClusterRole, mounts the token and passes the node IP; insecureSkipVerify defaults to true because kubelet certificates are often self-signed.
  • Kubernetes pod logs from the DaemonSet. Helm enables podLogs by default, writing a kubernetes_logs probe that follows /var/log/pods on each Linux node. Every pod is discovered (the agent's own excluded), CRI partial chunks are reassembled, offsets survive rotation by inode, and records carry the OTel k8s attributes; include/exclude globs and optional multiline stack-trace folding are available.
  • Host clock synchronisation. The cpu probe reports senhub.system.clock.synchronized, senhub.system.clock.offset and senhub.system.clock.max_error, and the detected time source on Linux via adjtimex; on Windows it reads the Windows Time Service counters. system_clock_max_error is omitted when the platform cannot provide it instead of reading 0.
  • Redis Sentinel and ACL support. redis adds Sentinel quorum, failover state and peer Sentinels per master, with the master address as a tag, and accepts an optional ACL username (AUTH <user> <password>). The page gains a TLS and Sentinel example and the channels a failover moves.
  • Severity from more log formats. The parser derives severity from HTTP status codes in nginx and Apache access logs (5xx ERROR, 4xx WARN, else INFO), and from klog, abbreviated, java.util.logging, PostgreSQL, MySQL, Apache and JSON level keys; prose without a level stays unclassified.
  • Self-log rail (opt-in). SENHUB_SELF_LOGS=warn or error publishes the agent's own warnings and errors as log records from the senhub-agent producer, with senhub.agent.module and other attributes. Unset, off or any other value sends nothing; a token bucket bounds the volume and published/dropped are self-metrics.
  • Every probe says what it checks and why a check failed. Each series of a database, application or platform probe carries the identity of the entity it describes (db.instance.id, service.instance.id, container.id, k8s.node.uid…), exactly as the entity carries it, so a dashboard can show the health of each service. A new series, senhub.probe.check.result, tells apart a target that is down (1) from a check that could not run: refused credentials (2), timeout (3), TLS error (4), configuration error (5), unreadable reply (6) or missing permission (7). Active checks (http_check, tcp_dial, icmp_check, ntp, dns_latency) now put their targets on the map, with a result per target. Existing PRTG channels are unchanged; a "Check Result" channel is added.
  • Series metering (Enterprise). senhub.agent.series.active, .created and .untracked count, per output and probe, the series the agent exports over OTLP, the figure a time-series backend bills on. See Series metering.
  • A local check says when nothing listens. tcp_dial and http_check aimed at a local port add senhub.probe.check.target.unresolved (value 1, reason=no_listener) when the port refuses the connection, next to the check result and with the same service.endpoint key as the listener the check monitors.
  • Top processes by memory. process accepts filter.top_by: memory next to top_n, to keep the N processes using the most resident memory (the working set on Windows) and name the one behind a low-memory condition.

  • System services on the map. systemd and winservices publish each service they watch as a host.service entity (identity host.id + host.service.name), with its start mode, linked to its host. Whether a service runs is the series host.service.running, 1 when it runs and 0 otherwise, the same series for both systems, keyed by the same host.id and host.service.name; it replaces systemd.unit.active_state and windows.service.state as the default series, which detail: full keeps. Units that earlier agents published as service.instance are retired with the reason rekeyed.

Fixes

  • The syslog receiver keeps messages it cannot parse. Such a message is kept as raw text with no facility, priority or severity, and empty frames between TCP messages are no longer published as records.
  • Log dashboards count errors and warnings again. The Linux and Windows logs and overview dashboards filtered on a severity field that VictoriaLogs leaves empty for OTLP logs (the level is stored as severity_text), so they showed no errors and no warnings. They now read severity_text, and severity for older ingestion.
  • Grafana dashboards: no more empty panels on metrics the agent does not emit. "CPU time by mode" now reads system_cpu_utilization_ratio by mode (the agent reports utilization, not a CPU-time counter), and the collect-error panels show 0 until a probe fails instead of nothing, split by probe and reason.
  • Entities announce the cadence they are actually read at. An entity whose source re-reads its facts less often than the entity heartbeat (an SNMP topology sweep or discovery crawl set to 10 minutes, a probe polling every 30 minutes) now announces that cadence as its interval, so a consumer no longer orders two changes the agent could not tell apart. The announced interval is never shorter than before. A source slower than 7 days, which the graph consumer refuses, is still announced as it is and logged as a warning by the agent.
  • winservices reports protected services. It asked the Service Control Manager for full access, which Windows refuses on protected services (WinDefend, BFE, RpcSs, DcomLaunch, mpssvc…) even to LocalSystem, so they were left out silently. It now opens services read-only.
  • The Zabbix rule for an automatic Windows service that is not running fires again. It also required windows.service.start_type, which the default detail: state no longer emits; the probe already watches only automatic services by default, so the rule now reads the state alone.
  • senhub-agent update follows include_beta. Without --config-path the command read ./agent-config.yaml and so never saw the beta channel the daemon announced; it now reads the same agent.yaml as the agent.
  • senhub-agent update leaves package installs to the package manager. On a host installed from the .deb or .rpm, the command now refuses and says to use apt or dnf, instead of replacing the binary behind the package manager, which then recorded a version that no longer ran.
  • The agent no longer dies under its systemd unit when it reads the clock. The clock synchronisation metrics read the kernel state with adjtimex(), which the unit's system call filter refused by killing the process. The unit now allows that call and makes any other refused call fail with an error instead of stopping the agent. It no longer sets ProtectClock, which blocks every clock call including that read; the clock stays unwritable because the unit grants no capability. An agent updated in place with senhub-agent update keeps the unit it was installed with: under a unit from 0.6.3 or earlier it now leaves the clock synchronisation metrics out, logs why, and senhub-agent doctor points at sudo senhub-agent refresh-unit, which restores them.
  • A replayed fact keeps the time it was read. When a source fails for a moment and the agent re-sends what it last read (a silent SNMP device during its grace, a discovered device that missed a run, any source within its last-good window), the entity event now carries the time of that read as its event_time, not the current time, so a consumer sees how old the fact is.
  • Windows events carry their message. windows_eventlog sends the message Windows renders for each event (as Get-WinEvent shows it), not only the provider, the event id and the insertion strings, and it reads the UserData payload some providers use instead of EventData. A low-virtual-memory warning now names the processes that consumed the memory.
  • A discovered device that answers in part keeps what it could not read. When one SNMP table walk fails on a device found by discovery (its interface table, say), the interfaces it could not read leave the map as unmonitored instead of as removed, as the polled target already did.
  • A cut link leaves the map, and a silent device leaves as unmonitored. snmp_poll no longer reports a link while either of its ports reads down, even when the far switch still lists the neighbour. A device that stops answering is no longer replayed after three topology intervals and leaves with the reason "unmonitored", not as gone; a device answering nothing at all no longer appears under an address-only identity. The local interface of a link whose far end was not read recently carries senhub.link.peer_state (unread, stale, unreachable).
  • A neighbour the ARP cache forgot is not reported as ended. When an ARP or NDP entry ages out, on the host or in a device's tables read over SNMP, its network.neighbor now leaves with the reason "aged_out" instead of "terminated".
  • Router-to-router routes reach the next router. A route whose private next hop is an address the agent sees on a device it polls now carries its next_hop_via, so a path no longer stops at every router.
  • Redis 8 key-size lines are no longer read as databases. Channels such as DB 0_distrib_strings_sizes Keys disappear; only dbN lines of the keyspace make a database.
  • The agent image upgrades its base packages at build time. The 0.6.4 image no longer ships a zlib version with a known CVE that container scanners flag.
  • Entity heartbeats publish on a fixed grid. Unchanged entities are re-published on a shared cadence with tolerance, so a ticker firing a few milliseconds early no longer produces alternating 120 s and 180 s gaps.
  • Export failure counters are declared at zero from the start. senhub.agent.export.send.failed is emitted per strategy and reason at start, so alerts reading it do not go silent after a restart.
  • The 0.5.x install split now completes. The 0.5.x 00-http.yaml template is recognised, so the monolithic agent.yaml split is no longer refused and the legacy notice does not repeat at every start.
  • A log file truncated in place is no longer duplicated. When a file is emptied and refilled past the old offset, the tail restarts once and does not deliver the first lines a second time.