Question

I have logging configured using logging.fileConfig(). I have a the root logger going to a handler that uses SysLogHandler('/dev/log', handlers.SysLogHandler.LOG_USER)

This all works perfectly well, and I see my log entries in /var/log/user.log

The question is how can I set the syslog ident string to something other than python? It appears the syslog module in the standard lib allows setting this when opening a log, but the logging handler doesn't offer this feature.

Would the solution be to subclass SysLogHandler and use the syslog library inside it's emit method? This is a unix only program, so using syslog directly doesn't pose a portability problem.

Was it helpful?

Solution

AFAIK, the ident string is an artifact of the syslog API, see this page. It's just using the C argv[0] which would of course be "python".

I'm surprised that you're getting this using SysLogHandler with a domain socket, as the message sent to syslog daemons across domain or TCP sockets is just a string with the priority in <angle brackets> followed by the formatted message and a NUL byte. There's no ident string specified by SysLogHandler, as it doesn't use the syslog API (which has some thread-safety issues in some versions, IIRC).

OTHER TIPS

This is a bit old but new information should be recorded here so people don't feel the need to write their own syslog handler.

Since Python 3.3, the SysLogHandler has a class attribute of .ident precisely for this purpose; the default for it is ''.

Example:

import logging
from logging.handlers import SysLogHandler

h = SysLogHandler(address=('some.destination.com',514), facility=SysLogHandler.LOG_LOCAL6)
h.setFormatter(
    logging.Formatter('%(name)s %(levelname)s %(message)s')
)
h.ident = 'conmon'

syslog = logging.getLogger('syslog')
syslog.setLevel(logging.DEBUG)
syslog.addHandler(h)

syslog.debug('foo syslog message')

Syslog implementations accepting RFC3164 messages should recognize first part of the message ("foo:" in the example) as TAG.

The MSG part has two fields known as the TAG field and the CONTENT field. The value in the TAG field will be the name of the program or process that generated the message.

Python code..

import logging
from logging.handlers import SysLogHandler

h = SysLogHandler(address='/dev/log')
h.setFormatter(logging.Formatter('foo: %(message)s'))
logging.getLogger().addHandler(h)

logging.error('bar')

..will send this into syslog socket

connect(3, {sa_family=AF_UNIX, sun_path="/dev/log"}, 10) = 0
sendto(3, "<11>foo: bar\0", 13, 0, NULL, 0) = 13
close(3)

Which in turn, produces this in systemd's journal.

Dec 13 14:48:20 laptop foo[1928]: bar

Journal message details:

{
  ..
  "PRIORITY" : "3",
  "SYSLOG_FACILITY" : "1",
  "SYSLOG_IDENTIFIER" : "foo",
  "MESSAGE" : "bar",
  "_PID" : "1928",
}

It works with Py2.6, 2.7, 3.4, 3.5 and Systemd's syslog server. It may work with other syslog implementations as well (if they accept RFC3164) messages. This solution will probably break when python's SysLogHandler will default to newer RFC5424.

For Python 2.7, you could do something like this:

class MySysLogHandler(logging.handlers.SysLogHandler):
    def __init__(self):
        super(MySysLogHandler, self).__init__(address='/dev/log')
    def emit(self, record):
        priority = self.encodePriority(self.facility, self.mapPriority(record.levelname))
        record.ident = "My[" + str(priority) + "]:"
        super(MySysLogHandler, self).emit(record)

handler = MySysLogHandler()
handler.formatter = logging.Formatter(fmt="%(ident)s %(levelname)s: %(message)s")
logging.root.addHandler(handler)
logging.info("hello world")

This will produce in the syslog:

Sep 3 16:28:53 hostname My[14]: INFO: hello world

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top