syslog
A Syslog-based logging framework and/or OTP logger handler for Erlang. This
project is inspired by the great work put in the two projects
sasl_syslog and
lager. In fact syslog tries to combine both
approaches. In a nutshell syslog can be seen as a lightweight version of the
lager logging framework supporting only a fully compliant, Erlang-only Syslog
backend allowing remote logging.
The main difference between sasl_syslog and syslog is that sasl_syslog
does only provide logging of error_logger reports. However, the error_logger
is known for its bad memory consumption behaviour under heavy load (due to its
asynchronous logging mechanism). Additionally, syslog provides an optional
RFC 3164 (BSD Syslog) compliant protocol backend which is the only standard
supported by old versions of syslog-ng and rsyslog.
Compared to lager, syslog has a very limited set of backends. As its name
implies syslog is specialized in delivering its messages using Syslog only,
there is no file or console backend, no custom-written and configurable log
rotation, no line formatting and no tracing support. However, syslog does not
rely on port drivers or NIFs to implement the Syslog protocol and it includes
measures to enhance the overall robustness of a node, e.g. load distribution,
back-pressure mechanisms, throughput optimization, etc.
Features
-
Log messages and standard
error_loggerreports formatted according to RFC 3164 (BSD Syslog) or RFC 5424 (Syslog Protocol) without the need for drivers, ports or NIFs. - Support for sending log message metadata as RFC 5424 STRUCTURED-DATA.
-
System independent logging to local or remote facilities using one of the
following transports:
- UDP (RFC 3164 and RFC 5426)
- TCP (Octet Counting according to RFC 6587)
- TCP/TLS (RFC 5425)
- Robust event handlers - using supervised event handler subscription.
- Optionally independent error messages using a separate facility.
-
Get the well-known SASL event format for
supervisorandcrashreports. - Configurable verbosity of SASL printing format (printing depth is also configurable).
- Load distribution between all concurrently logging processes by moving the message formatting into the calling process(es). Additionally uses binaries to minimize message copying and thus enhance performance.
-
Proper OTP-21 support using the new
logger' framework. * Built-inlagerbackend to bridge between both frameworks. ## Configuration Thesyslogapplication already comes with sensible defaults (except for the facilities used and the destination host). However, many things can be customized if desired. These are the advanced configuration options that are available and can be configured in the application environment: *{protocol, rfc3164 | rfc5424 |
Specifies which protocol/transport standard should be used to format and send outgoing Syslog packets. Please note that empty/default TLS/SSL options are currently not supported. Default formatting is{rfc3164 | rfc5424, tcp | udp} | {rfc3164 | rfc5424, udp, [gen_udp:option()]} | {rfc3164 | rfc5424, tcp, [gen_tcp:option()]} | {rfc5424, tls, [ssl:connect_option()]}}`rfc3164and the default transport isudp.{use_rfc5424_bom, boolean()}
false.{dest_host, inet:ip_address() | inet:hostname()}
{127, 0, 0, 1}.{dest_port, inet:port_number()}
514.{facility, syslog:facility()}
daemon.{crash_facility, syslog:facility()}
crash, will be sent with. It replaces the previouserror_facilityproperty. This accompanies a change in behaviour. Starting with release2.0.0error messages will also be sent withfacility. Only crash and supervisor reports will be sent to this (maybe) separate facility. If the values of the propertiesfacilityandcrash_facilitydiffer a short one-line summary will additionally be sent tofacility. Default isdaemon.{no_progress, boolean()}
true. Default isfalse.{app_name | appname, atom() | string() | binary()}
APP-NAMEfield of Syslog messages. If not set (the default), the name part of the node name will be used. If the node is not alive (not running in distributed mode) the stringbeamwill be used.{appname_from_metadata, atom()}
APP-NAMEfrom log event metadata (applies to thesyslog'slagerbackend as well as to the OTP-21loggerhandler). E.g. if this configuration is set toapplicationand a log message has the mappingapplication => saslin its metadata, the SyslogAPP-NAMEfield will have the valuesasl. If there is no mapping or this option is not set (which is the default) the rules described in theappnameconfiguration apply.{log_level, syslog:severity()}
debug(discard nothing).{async, boolean()}
syslog_loggerserver is done synchronously or asynchronously. It is highly recommended to leave this at its default valuefalsebecause asynchronous delivery is really dangerous. A simple log burst of a few thousand processes may be enough to take your node down (due to out-of-memory).{timeout, pos_integer()}
{async, false}). This is useful if your application has performance restrictions (under high load) and you are willing to sacrifice safety for this reason. It's still safer to set this to a lower value than completely switching to{async, true}. Default is1000ms.{multiline_mode, boolean()}
syslogwill send messages potentially containing multiline strings. Please be aware, that many Syslog servers will not be able to handle multiline messages well, e.g. will insert garbage characters for a newline character. Default isfalse.{hostname_transform, none | short | long}
node()will be transformed for use as the hostname in messages. If the setting isnonethe value will be used as-is, if the setting isshortany domain part of the name will be removed, and if the setting islongthensyslogwill attempt to fully qualify the name if no domain part is present. If the hostname obtained fromnode()is an IP address then no transformation is applied. If the node is not alive then the result ofinet:gethostnamewill be used in place ofnode(). Note that RFC 3164 requires that the domain is not included in the hostname, and will remove the domain part from the resulting hostname. Default islong.Structured Data
syslogis capable of sending STRUCTURED-DATA. Please note that this will require therfc5424formatting. STRUCTURED-DATA can be sent using thesyslog:msg/5function. This function allows passing a list of structured data elements that will be formatted and sent to the remote receiver. However, no content checking will be done. If there's unescaped or unallowed content in the provided structured data elements invalid Syslog messages will be sent.Another useful feature ofsyslogis the optional ability to store the metadata from aloggerorlagerlog event/message into the STRUCTURED-DATA part of an RFC 5424 message. A structured data mapping has the form of a 2-tuple, e.g.
where{"sdata_id", [application, pid]}sdata_idis being used as the STRUCTURED-DATA id and the second element being a list of atoms corresponding to the metadata keys whose values you want to pack. Only metadata matching the configured keys will be included into the STRUCTURED-DATA. If metadata does not contain a configured key, the key will be skipped. Please turn to the respective integration section to learn how to define structured data mappings.OTP-21 Logger Integration
Thesyslogapplication uses the recommended way to integrate with the OTP-21 logger by utilizing thelogger:add_handlers/1function on application startup. This enables user to configure the integration through thesys.configof their release. By default,syslogwill add a singleloggerhandler with the idsyslog.To usesyslogas the one (and only) default handler in your release you'll need something like the following in yoursys.config:
However, keep in mind that it is not necessary to make[ {kernel, [{logger, [{handler, default, undefined}]}]}, {syslog, [{logger, [{handler, default, syslog_logger_h, #{}}]}]} ]syslogyour default/primary log handler. It can also only be an additional handler.Similar to thelagerbackend, theloggerhandler is capable of conversion of metadata to structured data, e.g. if you want to include the metadata mappings for the keysapplicationandpid(if available) as structured data in log messages you could configure the handlers like so:
Of course it is allowed to configure multiple structured data mappings, by default no metadata is packed as structured data.Additional handler configuration may be passed using the handler argument map like it would be done with other{syslog, [ {logger, [ {handler, syslog, syslog_logger_h, #{config => #{structured_data => [{"sdata_id", [application, pid]}]}}} ]} ]}loggerhandlers. However, progress report filtering is strictly controlled by thesyslogapplication environment and filtering (discarding) of remote log events is always enabled.Finally, to completely disable theloggerintegration (similar to settingsyslog_error_loggertofalsein pre-OTP-21 releases) you'll have to configure an empty handler list:{syslog, [{logger, []}]}Error Logger Integration
The following configuration options are related to theerror_loggerhandler/integration. If there is noerror_loggeravailable (e.g. OTP-21 orsyslog_error_logger =:= false), these configurations have no effect.{syslog_error_logger, boolean()}
syslogwill handle messages from theerror_logger. Default istrue. Note: This will not start theerror_loggerin OTP-21.{msg_queue_limit, Limit :: pos_integer() | infinity}
error_loggermessage queue. If the message queue exceeds this limitsyslogwill drop the events exceeding the limit. Default isinfinity.{drop_percentage, Percentage :: 1..100}
error_loggermessage queue exceeds the configuredmsg_queue_limit. Thedrop_percentageis given as percentage (of themsg_queue_limit). E.g. ifdrop_percentageis10(the default),msg_queue_limitis100and the current length of theerror_loggermessage queue is 120, then20 + 10messages will be dropped to give thesyslog_error_hhandler some air to catch up.{verbose, true | {false, Depth :: pos_integer()}}
error_loggerreports (that is progress reports, not format messages). If verbose istruethe~pformat character will be used when formatting terms. This will likely result in a lot of multiline strings. If set to{false, Depth}the~Pformat character is used along with the specified printing depth. Default istrue.Thesyslogapplication will disable the standarderror_loggerTTY output on application startup. This has nothing to do with the standard SASL logging. It only disables non-SASL logging via, for exampleerror_logger:info_msg/1,2. This kind of standard logging can be re-enabled at any time using the following:
This behaviour can also be configured in the application environment. If you don't wanterror_logger:tty(true).syslogto mess with your TTY settings use{disable_tty, false}.Thesyslogapplication will not touch the standard SASL report handlers attached to theerror_loggerwhen SASL starts. However, having SASL progress reports on TTY can be quite annoying when trying to use the shell. The correct way to disable this output is to configure the SASL application in thesys.configof a release, for example the following line will instruct SASL not to attach any TTY handlers to theerror_logger:{sasl, [{sasl_error_logger, false}]}Lager Integration
Thesyslogapplication comes with a built-in, optional backend forlager. This is especially useful if your release has dependencies that requirelageralthough you wish to forward logging usingsyslogonly. To forwardlagerlogging intosyslogyou can use something like the following in yoursys.config:
It is also possible to explicitly specify the logging level{lager, [{handlers, [{syslog_lager_backend, []}]}]}
It will also handle custom formatters like other existing{lager, [{handlers, [{syslog_lager_backend, [info]}]}]}lagerbackends. And there are even more advanced features that may be configured, e.g.:
If you don't want to forward any metadata as structured data or are using RFC 3164 then you can supply an empty tuple{lager, [ {handlers, [ {syslog_lager_backend, [ debug, %% Log Level {"sdata_id", [application, pid]}, %% STRUCTURED-DATA mappings {lager_default_formatter, [message]}, %% Lager formatting true %% Use application field from %% lager metadata for appname ]} ]} ]}{}.Danger Zone
If your application really needs fast asynchronous logging and you like to live dangerously, thesyslogapplication should be configured with{async, true}and{msg_queue_limit, infinity}. This setssysloginto asynchronous delivery mode and all message queues are allowed to grow indefinitely.Usage
Although, thesyslogapplication will log everything that is logged using the standarderror_logger(pre-OTP-21) API, this should not be used for ordinary application logging. For pre-OTP-21 release it is recommended to use the logging API provided by thesyslogmodule. These functions are similar to the ones provided by theerror_loggermodule and should feel familiar (see the*msg/1,2functions) while providing overload protection for your application.For post-OTP-21 releases the recommended way of logging is (of course) to use the officialloggerAPI. Due to theloggerhandler abstraction design,syslogis able to provide overload protection for this function without the need for an additional, custom API.Performance
Performance profiling has been made with a the benchmark script located in thebenchmarksubdirectory. The figures below show the results of best-of-five runs on an Intel(R) Core(TM) i7-4790 CPU running OTP 17.4.The benchmark simulates a hard burst by spawningNprocesses that each send log messages, using a specific logging framework, in a tight loop for 10000ms. All log messages will be delivered over UDP (faked remote Syslog) to a socket opened by the benchmark itself. The total duration is the time it took to spawn the processes, send the messages and the time it took to receive all sent messages at the socket that the benchmark process listens on. The benchmark has two profiles. Thelargeprofiles uses log messages with a size of ~840bytes and thesmallprofile uses log messages with a size of ~40bytes.All frameworks are used in their default configuration with their native logging function (noterror_logger).To be able to comparelagerwith the other frameworks, the benchmark contains a very simple backend, that forwards log messages formatted with thelager_default_formatterusinggen_udp, e.g. likesyslogdoes it. Thesasl_syslogapplication is left out of scope, simply because it crashes the Erlang VM on every run (due to its purely asynchronous logging).Now let's see the numbers.Small Profile
For a relatively small number of senders, all frameworks have a pretty good throughput and the completion time is almost equal. While memory consumption is generally low, thelagerapplication uses significant more memory. This is due to the dynamic switching between synchronous and asynchronous message delivery: When delivery starts in asynchronous mode many log messages pile up in the internalgen_event's message queue. When the framework finally switches to synchronous mode the event manager is busy sending out these messages while senders get blocked.<img src="https://cloud.githubusercontent.com/assets/404313/16836745/5af8562e-49bf-11e6-8ba0-89a99d1a73f5.png" alt="small benchmark" />Adding more processes to the party makes the above mentioned effect more dramatic. Whilelog4erlandsyslogperform quite well by evening the load on the internal event manager or server using synchronous logging,lagerpiles up a hugh amount of messages in its internalgen_eventmessage queue. It takes the framework almost two minutes to process these messages.When looking at the memory usage it can be observed thatlager's backend throttling (which was also used insyslogup to this version) is effectively useless to protect from bursts with small log messages. Switching is simply too slow and once messages begin to pile up, the node keeps being busy sending these messages. Additionally, senders may get blocked an indefinite amount of time (remember thatgen_event:sync_notify/2usesinfinityfor timeouts). During the test it could be observed that some senders were blocked over 50 seconds!Large Profile
Numbers get interesting when large strings need to be formatted and copied around.log4erlas well aslagerdo the actual message formatting inside the internal event managers. Additionally, these frameworks pass around the unprocessed format string and its argument list.syslogon the other hand, is now able to score by offloading the formatting work into the logging processes and by exchanging binaries with the internal logging server.<img src="https://cloud.githubusercontent.com/assets/404313/16836747/5f04b848-49bf-11e6-9c28-603eb66036f4.png" alt="large benchmark" />Interestingly, the total duration is excellent for all frameworks. Most probably, copying the large terms makes the logging processes slow enough thatlager's backend throttling can kick in and prevent the internal message queue from growing too much. However, it could be observed again that some senders were blocked over 10 seconds.History
4.0.0
-
Add proper support for the new
OTP 21 Logger API:
syslogdoes now integrate as a properloggerhandler and inherited some of the nice features known from thelagerbackend, e.g. structured data from metadata (#15) -
Change the default value for the
hostname_transformoption tolong. This is done to be compliant to RFC 5424 by default, even when short hostnames are used for Erlang distribution. -
Allow using custom logger formatters when using the OTP 21
loggerhandler (thanks to @robinchew) -
Fix progress report filtering when using the OTP 21
loggerhandler (thanks to @juise) -
Fix millisecond time resolution when using the OTP 21
loggerhandler (#21, thanks to @juise) -
Fix application of the default
syslogformatter configuration (#22, thanks to @dmitrivereshchagin) - Fix a badmatch when formatting crash reports originated by `proc_lib' (#23, thanks to @dmitrivereshchagin)
-
Honor the
report_cbfeature when using the OTP 21loggerhandler
3.4.5
-
Do not open sockets in active mode. This prevents a socket
bindwhich in turn lets the socket listen for incoming traffic (thanks to @lukebakken)
3.4.4
-
Allow message header customizations, e.g.
APP-NAMEand/orHOSTNAME(thanks to @GlenWalker)
3.4.3
-
Add support for process ids formatted as strings in
lagermetadata (thanks to @hairyhum) -
Add basic support for OTP 21. This will make
syslogwork with the newloggerAPI. But be aware that this is only a hack involving the start of the legacyerror_logger. If you want to use this, do not forget to set thekernelenvironment variablelogger_sasl_compatibletotruein your release. Unfortunately, the unit tests don't work with OTP 21. Proper support for OTP 21 will be a topic for version 4. -
Add support for hostnames as values for the
dest_hostconfiguration (thanks to @lukebakken)
3.4.2
-
Fix unicode logging (using
~tsor~tc)
3.4.1
- Fix compatibility to OTP 20.1
3.4.0
- Due to a bug, this release is not compatible with OTP 20.1, use release 3.4.1 instead.
-
Allow certain configuration values to be set as string/binary. This especially
applies to the
dest_hostanddest_portoptions, e.g. it is now possible to set addresses like "127.0.0.1" or "::1" asdest_host. (thanks to @ogolosovskiy) -
Support for optional
multilinemode, which preventssyslogfrom splitting message strings at newline separators (thanks to @ogolosovskiy)
3.3.0
- Try to reopen the transport periodically on transport failures/errors (#11).
-
Support for configurable conversion of
lagermetadata to STRUCTURED-DATA (thanks to @walrusVision) -
Support for custom formatters in the
lagerbackend (thanks to @walrusVision)
3.2.0
-
Add support for STRUCTURED-DATA (RFC 5424) using
syslog:msg/5. This lead to a change of the internal formatter behaviour. Custom implementations of thesyslog_loggerbehaviour must be adapted to these changes. -
Error logger robustness has been improved, by giving the
error_loggermessages precedence over messages sent via the API. -
The internal
syslog_loggerhandles transport errors (gracefully). This way crashes are avoided which in turn relieve theerror_loggerwhen the system is under high load already.
3.1.0
- Allow configuration of custom protocol backend modules (thanks to @rich)
-
Export/move date formatting code into
syslog_lib(thanks to @rich) - Make TTY settings configurable in the application environment
-
Make
error_loggerintegration configurable
3.0.0
syslogis now available on hex.pm under the package namesyslog_app(the namesyslogis already assigned to another project)- Make project compatible to rebar3
-
Remove dynamic switching of log message delivery mode. Make mode explicitly
configurable with the new
asyncdirective (which replaces theasync_limitdirective) and thesyslog:set_log_mode/1API. -
Add
app_nameconfiguration directive to allow configuration of theAPP-NAMEfield value (thanks to @comtihon). -
Change severity of messages sent by
error_logger:info_[msg|report]/1,2andsyslog:info_msg/1,2fromnoticetoinformational(thanks to @comtihon). -
Add
log_levelconfiguration directive. With this configuration it is possible to discard messages with undesired severity values (thanks to @comtihon). -
Add optional
lagerbackend to forward messages fromlagertosyslog. - Further improvement of robustness, especially when many processes try to log concurrently by moving the message formatting away from the main event manager into the logging processes.
Version 2.0.1
-
Fix event handler supervision. Due to a defective match pattern in
syslog_monitorcrashed handlers did not get re-added as expected/supposed.
Version 2.0.0
-
Replace the property
error_facilitywithcrash_facility. Refer to the explanation ofcrash_facilityabove to learn more about this behaviour change. - Performance improvements (e.g. binary as internal message format)
Version 1.0.0
-
Provide discrete API for robust
error_loggerindependent logging - Automatic toggling of sync/async logging for better load protection (default)
- Various performance improvements (e.g. timestamps, process name resolution)
- Configurable verbosity of progress report logging
- Support for release upgrades
Version 0.0.9
-
Supervised
error_loggerintegration - Message queue length based load protection
- RFC 3164 compliant backend (default)
- RFC 5424 compliant backend
- Support for local and remote facilities using UDP
- Separate facility for error messages (default off)
-
Standard SASL event format for
supervisorandcrashreports
Supervision
For the curious; the above illustration shows the very simple supervision
hierarchy used by the syslog application. Please note that when OTP-21 is used
the syslog_logger_h handler is monitored/supervised by the logger
framework itself.