9

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.

Trey Stout
  • 6,231
  • 3
  • 24
  • 27

4 Answers4

9

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')
bufh
  • 3,153
  • 31
  • 36
FirefighterBlu3
  • 399
  • 5
  • 11
  • 4
    This is Python 3.3+ though. – malthe Jan 27 '14 at 13:10
  • 5
    Just an FYI for others who might run into the same issue. If you're doing `dictConfig` from a yaml file, the way you set `ident` is by putting the `ident` key under a `.` key. So it'll be something like `handlers:\n\t syslog:\n\t\t .:\n\t\t\t ident: appname`. – Calvin Huang Oct 09 '18 at 22:58
  • Don't you need a ":" for ident to be parsed as ident? journald seems to work when I put "conmon: " as ident – Osman-pasha Jun 10 '22 at 11:49
  • @Osman-pasha Yes. I had expected the class to check and add that but it doesn't – FirefighterBlu3 Jun 11 '22 at 17:20
9

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.

Community
  • 1
  • 1
4

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).

Vinay Sajip
  • 95,872
  • 14
  • 179
  • 191
  • Vinay thank you for the thorough answer. Turns out you were right, and this was mainly a miscommunication with my operations team. We're using a new formatter to put a fake "ident" flag as the first argument and rsyslog couldn't be happier. – Trey Stout Nov 23 '10 at 23:25
  • This is obsolete information, I would mark answer of FirefighterBlu3 as the correct one. – Arie Skliarouk Nov 27 '13 at 22:19
  • 1
    There is no reason to downvote because information gets out of date. It was the correct answer at the time, and thanks to `FirefighterBlu3` for providing the update. – Vinay Sajip Nov 27 '13 at 22:48
2

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

Mike Clark
  • 10,027
  • 3
  • 40
  • 54