Skip to main content
Version: 028-rc15

Pantavisor Log Sockets

The Pantavisor logging system uses two Unix sockets for inter-process log management: pv-ctrl-log for receiving direct log messages and pv-fd-log for subscribing file descriptors to be polled by Pantavisor.

pv-ctrl-log

This socket is used by applications and containers to send log messages directly to the Pantavisor Log Server. All messages must follow the logserver_msg structure:

struct logserver_msg {
int code; // Protocol code: 0 for LEGACY, 256 for CMD
int len; // Length of the following buffer
char buf[0]; // Log data buffer
};

Legacy Protocol (code = 0)

The buf contains the log metadata and message, separated by null terminators (\0):

level\0platform\0source\0data
  • level: Log level as a string (e.g., "3" for INFO).
  • platform: Name of the container or "pantavisor".
  • source: The specific source of the log (e.g., a process name or module).
  • data: The actual log message content.

The supported log levels are:

  • 0: FATAL
  • 1: ERROR
  • 2: WARN
  • 3: INFO
  • 4: DEBUG
  • 5: ALL

pv-fd-log

This socket allows containers to delegate the polling of their file descriptors (e.g., pipes, sockets, or open files) to Pantavisor.

Subscription Protocol

To subscribe or unsubscribe a file descriptor, you must use the sendmsg system call with SCM_RIGHTS to pass the file descriptor.

The msghdr must contain an iovec array with 4 elements:

iov IndexTypeMax LengthDescription
iov[0]string50 bytesPlatform name (container name)
iov[1]string50 bytesSource name (e.g., "stdout", "syslog")
iov[2]int4 bytesLog level for the messages from this FD
iov[3]int4 bytesAction: 1 to subscribe, 0 to unsubscribe

Subscribe

  • Send the file descriptor using SCM_RIGHTS.
  • Set iov[3] to 1.
  • Pantavisor will poll this FD and create a corresponding log file at /storage/logs/current/<platform>/<source>.

Unsubscribe

  • Set iov[3] to 0.
  • The file descriptor passed in SCM_RIGHTS can be -1.
  • Pantavisor will stop polling and close its internal reference to the FD for that platform/source pair.

!!! Note Only one file descriptor can be subscribed per platform-source pair. Subscribing a new FD for an existing pair will replace the previous one.

/dev/log

Pantavisor's Log Server creates a symbolic link to the pv-ctrl-log socket at /dev/log — the standard syslog socket path used by most operating systems and logging libraries. Applications that write standard syslog messages will have their logs captured automatically with no additional configuration.

RFC 3164 and RFC 5424 protocol support is always active. The /dev/log bind-mount into containers is controlled globally by PV_LOG_AUTO_DEVLOG (default: enabled).

Per-container control

Each container inherits the global PV_LOG_AUTO_DEVLOG setting by default. You can override this per-container with the dev-log key in <container>/run.json:

{
"#spec": "service-manifest-run@1",
"dev-log": false
}
ValueEffect
true (default)/dev/log is bind-mounted into the container
false/dev/log is never mounted in this container, regardless of the global setting

The parser is selected at runtime based on the first bytes of each datagram:

First bytesProtocol detected
<NNN>1 … (digit 1 immediately after the closing >)RFC 5424
<NNN>… (any other character after the closing >)RFC 3164
Binary struct logserver_msg with code headerLegacy binary

RFC 3164

RFC 3164 is the original BSD syslog wire format. It is the default output of openlog/syslog on most Linux systems.

Message format:

<PRI>Mmm dd HH:MM:SS HOSTNAME APP[PID]: message

Annotated example:

<34>May 15 16:48:18 mydevice myapp[1234]: Connection established
^^ ^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^ ^^^^ ^^^^^^^^^^^^^^^^^^^^^^
| timestamp hostname app message text
priority (facility=4, severity=2 → ERROR)

Field mapping:

RFC 3164 fieldPantavisor attributeNotes
HOSTNAMEplatformContainer name or source identifier
APPsrc (source)Process name; [PID] suffix is stripped
PRI severity bitslvl (level)See priority table
TimestamptimeParsed with strptime("%b %d %H:%M:%S")
Message textlog dataEverything after APP[PID]:

Missing or unparseable fields fall back to "unknown-host" and "unknown-app".

RFC 5424

RFC 5424 is the structured syslog format. It adds a version field, ISO 8601 timestamps, and optional structured data elements.

Message format:

<PRI>1 TIMESTAMP HOSTNAME APP PROCID MSGID STRUCTURED-DATA MSG

Annotated example:

<34>1 2026-05-15T16:48:18Z mydevice myapp 1234 - - Connection established
^^ ^ ^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^ ^^^^^ ^^^^ ^ ^ ^^^^^^^^^^^^^^^^^^^^^^
| | timestamp hostname app pid | | message text
| version = 1 (RFC 5424 marker) | structured-data (nil)
priority msgid (nil)

Nil fields are represented by a single - character. Pantavisor accepts PROCID, MSGID, and STRUCTURED-DATA but does not store or forward them.

Field mapping:

RFC 5424 fieldPantavisor attributeNotes
HOSTNAMEplatformContainer name or source identifier
APPsrc (source)Application name
PRI severity bitslvl (level)See priority table
TIMESTAMPtimeParsed with strptime("%Y-%m-%dT%H:%M:%S"); nil (-) → current time
MSGlog dataEverything after the structured-data field
PROCID, MSGID, STRUCTURED-DATAAccepted but ignored

!!! Note Fractional seconds in RFC 5424 timestamps are silently dropped. Use UTC (Z suffix) for best fidelity.

Priority and Facility

Both RFC 3164 and RFC 5424 encode priority as a single integer:

PRI = facility × 8 + severity

Severity → Pantavisor level mapping:

Severitysyslog namePantavisor level
0EMERGFATAL
1ALERTFATAL
2CRITERROR
3ERRERROR
4WARNINGWARN
5NOTICEINFO
6INFOINFO
7DEBUGDEBUG

Common facility codes:

CodeNameDescription
0kernKernel messages
1userUser-level messages
3daemonSystem daemons
16LOCAL0Recommended for Pantavisor containers

LOCAL0 (facility 16) is the recommended facility for container applications.

Library support

Any standard syslog library that writes to /dev/log works without modification. The examples below show the minimal setup for common languages.

C / C++ (syslog.h)

#include <syslog.h>

int main(void) {
openlog("myapp", LOG_PID, LOG_LOCAL0);
syslog(LOG_INFO, "Container started");
closelog();
return 0;
}

openlog targets /dev/log by default on Linux. LOG_LOCAL0 maps to facility 16.


**Python (`logging.handlers.SysLogHandler`)**

```python
import logging
import logging.handlers

handler = logging.handlers.SysLogHandler(address="/dev/log")
logger = logging.getLogger("myapp")
logger.addHandler(handler)
logger.setLevel(logging.DEBUG)
logger.info("Container started")

Go (log/syslog)

package main

import "log/syslog"

func main() {
w, err := syslog.New(syslog.LOG_INFO|syslog.LOG_LOCAL0, "myapp")
if err != nil {
panic(err)
}
defer w.Close()
w.Info("Container started")
}