0.6.3 — 2026-10-13¶
0.6.3 completes the Azure Container Apps collector: every application of a
subscription found and followed with its coverage measured, jobs
discovered automatically, one shared identity for every Azure probe,
senhub-agent check azure to verify the permissions, log volume per
application and official Grafana dashboards. It also keeps configuration,
secrets and identity on an Azure Files (SMB) share, and fixes the
corrective items found on 0.6.2.
Before you upgrade¶
- Container Apps discovery now pages through the whole subscription. If you capped
discovery.max_appsor added named probes to work around missing applications, raise or remove the cap and remove those probes, or the applications are followed twice. - Container App Jobs keep a bookmark by default. At the first start of 0.6.3, a job declared without
bookmark_pathpublishes once the executions Azure still holds; the bookmark then lives in the state directory, which should be on a volume.
Features¶
- Official Grafana dashboards for Azure Container Apps and Container App Jobs.
azure-container-apps.json(coverage, per-application health, scan failures by reason, volume, logs) andazure-container-app-jobs.json(executions by status, duration, last run, logs) indocs/grafana/. They read the per-application metrics, not log counts. senhub-agent check azure. A read-only command that checks, with the credentials of the configured Azure probes, the token, the subscription, the applications and jobs found, and each permission the probes need, one verdict per line; it exits non-zero when a required item fails.- Container Apps discovery reports its coverage.
discovery.found,discovery.followedanddiscovery.left_out(byfilterormax_apps) read "26 of 26" from metrics;discovery.last_ageanddiscovery.failuresshow a listing that stopped working. Under discovery, the volume counters and scan failures are given per application, and an application never read no longer reports zero replicas. - Container App Jobs discovery. A
discovery:block onazure_container_app_jobsfollows every job of a subscription (resource groups, include and exclude patterns, cap), each with its own executions file; jobs that appear or disappear are picked up at the next enumeration. When executions come back without replicas, the log names the missingMicrosoft.App/jobs/*/readpermission once per job. - Shared Azure credentials.
SENHUB_AZURE_TENANT_ID,SENHUB_AZURE_CLIENT_ID,SENHUB_AZURE_CLIENT_SECRET(or_FILE) andSENHUB_AZURE_SUBSCRIPTION_IDgive the identity once for every Azure probe; a probe's own value still wins key by key. - Log volume per Container App.
senhub.azure_container_apps.records.volumecounts the bytes of published log bodies per application, so the volume compares with what Log Analytics bills; the official dashboard shows it per second and over the range.
Fixes¶
- doctor resolves
${env:}with the service's environment. It readsEnvironment=andEnvironmentFile=from the systemd unit and its drop-ins (as root), and on Windows the service'sEnvironmentvalue in the registry (HKLM\SYSTEM\CurrentControlSet\Services\senhub-agent). A reference it cannot resolve outside the service is a warning that names the variable, never a failure. - A monolithic
agent.yamlbeside the filesinstallcreated is split. The defaultprobes.d/00-host.yamlandstrategies.d/00-http.yamlare set aside as*.install-default; if the directories hold your own files, one message names them. The split failure and the legacy notice are logged once per start, and no seal failure is reported when the split was refused. - The OTLP logs queue announces itself at start. One Info line gives its path, size cap and retention, so a healthy queue is no longer indistinguishable from a disabled one.
- A cut update download is retried. When the stream breaks midway, the whole request is repeated up to three more times with a growing pause, with a
senhub-agent/<version>User-Agent and no transparent compression of the archive. - The OTLP receiver coverage counters start at zero.
senhub.agent.otlp_receiver.receivedand.received.without_host_idexist from the start for each enabled signal, so "nothing received yet" is no longer indistinguishable from a dead receiver. - No error when the journal reader is stopped with the agent.
linux_logsno longer logsjournalctl subprocess died unexpectedlywhen systemd terminates journalctl as part of stopping the service. logicaldiskstops warning about/run/user/*every cycle. A per-user runtime directory the service account cannot read is skipped quietly; any other mount it cannot read is named once.- A Redis TLS failure names the handshake. The
redisprobe runs the TLS handshake right after connecting and reportsTLS handshake with <host>:<port> failed: ...instead of anAUTH send failedthat hid the cause. - Container and Azure pages corrected. Image tags move to 0.6.3; the container page explains
SENHUB_HOST_IDand the upgrade trap of an existingagent.yaml; the Container Apps page states thatdiscoveryexcludesappandresource_group; both Azure pages use the probe namesCAandCAJ, the jobs page gains a "From environment variables" section, and the configuration page documents that${env:}inside aSENHUB_PROBE_*value is not expanded and that the variables win key by key. - Jobs probe docs.
bookmark_pathdefaults to<probe name>.executionsin the state directory, and an entry withoutappordiscovery:is refused. - One
host.nameon every signal. Metrics, the OTLP resource, the host entity, the systemd unit entities and the info endpoint all use the same canonical host name. - Every log record carries an OTel severity number. Whatever level word a source writes, the number is derived (the text stays as written), including a
level=noticepair or a lower-case word after the timestamp (2026-10-12T14:00:00Z warn ...) on a line read without a parser; a journald entry without a priority is informational instead of an emergency. - Relative paths follow the configuration directory.
bookmark_pathand the*_fileparameters (CA, certificate, key, password files), andconfig/nagios.yaml, are resolved against the directory of the configuration, not the working directory;config checkfrom another directory no longer reports a false permission error. - doctor flags a stale
senhub-agenton the PATH. When another binary on the PATH reports a version different from the running service, doctor warns, naming both paths and versions and pointing to the unit's binary. - Identity re-keys are announced once, not at every start. The retirement of the legacy database and service identities (0.5.4 re-key) was repeated during the first cycles of every agent start, which a topology backend read as the producer reporting the node gone. A marker file in the state directory now records that it was announced; if the directory is not writable the announcement repeats and one warning is logged.
- Identity re-keys are really announced once. The marker was consulted after the probes had already published their first announcements, so every restart still repeated them; the marker is now active before any probe starts.
- Relayed OTLP logs keep a severity number. A record received with a severity text (
WARNING,CRITICAL) and no number is exported with the matching number; a number set by the sender and the text are left as written. - A stalled update download is abandoned. An archive download that receives no byte for 60 seconds is cancelled and retried like a cut stream, instead of waiting indefinitely.
- No false alarms when the configuration is split. The first start of a monolithic
agent.yamlno longer logs the "Legacy monolithic config" warning just before splitting it, and the*.install-defaultfiles set aside by the split are no longer reported as "Files not loaded". - host.id is always lowercase. The
/etc/machine-idfallback was not lowercased; the same id in two cases would be two hosts downstream (no host in production was affected). - The agent's own CPU time is what it used.
senhub.agent.process.cpu.timeread the CPU available to the process (GOMAXPROCS over its lifetime), so an idle agent in a 2-CPU container showed 2 CPUs busy; it now reads user plus system time from the OS.