{"id":20100603,"url":"https://github.com/seriyps/logger_journald","last_synced_at":"2025-10-26T20:46:04.059Z","repository":{"id":57517892,"uuid":"299072161","full_name":"seriyps/logger_journald","owner":"seriyps","description":"OTP logger backend that sends log events to Systemd's journald service","archived":false,"fork":false,"pushed_at":"2023-11-21T22:11:00.000Z","size":89,"stargazers_count":7,"open_issues_count":0,"forks_count":1,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-05-01T20:24:18.720Z","etag":null,"topics":["erlang","journald","logger","logger-backend","systemd"],"latest_commit_sha":null,"homepage":"","language":"Erlang","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/seriyps.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-09-27T16:26:55.000Z","updated_at":"2021-11-10T09:15:52.000Z","dependencies_parsed_at":"2024-11-15T08:45:40.261Z","dependency_job_id":null,"html_url":"https://github.com/seriyps/logger_journald","commit_stats":{"total_commits":25,"total_committers":1,"mean_commits":25.0,"dds":0.0,"last_synced_commit":"34b5d9cc0c35b06abe05fe2b5b7d826bf69fd8bc"},"previous_names":[],"tags_count":7,"template":false,"template_full_name":null,"purl":"pkg:github/seriyps/logger_journald","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seriyps%2Flogger_journald","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seriyps%2Flogger_journald/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seriyps%2Flogger_journald/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seriyps%2Flogger_journald/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/seriyps","download_url":"https://codeload.github.com/seriyps/logger_journald/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/seriyps%2Flogger_journald/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263828367,"owners_count":23516789,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["erlang","journald","logger","logger-backend","systemd"],"created_at":"2024-11-13T17:16:27.297Z","updated_at":"2025-10-26T20:45:59.026Z","avatar_url":"https://github.com/seriyps.png","language":"Erlang","funding_links":[],"categories":[],"sub_categories":[],"readme":"logger_journald\n===============\n\nOTP [logger](http://erlang.org/doc/apps/kernel/logger_chapter.html) backend that sends log\nevents to Systemd's journald service.\nPure Erlang implementation (no C dependencies).\n\nUsage\n-----\n\nAdd to your `rebar.config`\n\n```erlang\n{deps, [logger_journald]}.\n```\n\nto your `sys.config`\n\n```erlang\n{kernel, [\n    {logger, [\n        {handler, my_handler, logger_journald_h, #{\n            level =\u003e info,\n            formatter =\u003e {logger_formtter, #{max_size =\u003e 4096}},\n            config =\u003e #{\n              socket_path =\u003e \"/run/systemd/journal/socket\",  % optional\n              defaults =\u003e #{\"MY_KEY\" =\u003e \"My value\",          % optional\n                            \"SYSLOG_IDENTIFIER\" =\u003e my_release},\n              sync_mode_qlen =\u003e 10,\n              drop_mode_qlen =\u003e 200\n            }\n        }}\n    ]}\n]}\n```\n\nor do this somewhere in your code\n\n```erlang\nlogger:add_handler(my_handler, logger_journald_h,\n                   #{config =\u003e #{defaults =\u003e #{\"SYSLOG_IDENTIFIER\" =\u003e my_release}}}).\n```\n\nI'd recommend to add at least one key to `defaults` to uniquely identify your application. The\nrecommended key name for that is `SYSLOG_IDENTIFIER`.\n\nOther `logger:handler_config()` options (`level`, `filters`) should also work.\n`formatter` is limited: only `logger_formatter` callback module is supported and\n`legacy_header`, `template`, `time_*` options are ignored (this may change in the future).\n\nThen start your app and send some logs. They can be seen, eg, like this (see `man journalctl`):\n\n```bash\n$ journalctl -f -o verbose _COMM=beam.smp -t my_release\n```\n\nMultiple instances of `logger_journald_h` handler can be started.\n\nIt's not currently possible to set `logger_journald_h` as `default` handler via `sys.config`,\nbecause `sys.config` is applied at `kernel` application start time and `logger_journald`\napplication depends on `kernel` application (sort of cyclic dependency). However, disabling\n`default` handler and installing just `logger_journald_d` works fine (but you might miss some\nof early start-up related logs)\n`[{handler, default, undefined}, {handler, my_handler, logger_journald_d, #{}}]`.\n\nThere is also [journald_sock](src/journald_sock.erl) module available, which provides a thin wrapper\nwith limited API for journald's control socket.\n\nHow it works?\n-------------\n\nWhen `logger_journald` application is started, it creates an empty supervisor.\nWhen `logger:add_handler/3` is called, `logger_journald` starts a new `gen_server` under\nthis supervisor, which holds open `gen_udp` UNIX-socket open to journald and some internal state.\n\nWhen you call `logger:log` (or use `?LOG*` macro), your log message is converted to be a flat\nkey-value structure in the same process where `log` is called and then sent to this `gen_server`,\nwhich writes it to journld's socket via `gen_udp`.\n\nLogger supports some basic overload protection, only `sync_mode_qlen` and `drop_mode_qlen`\nare supported, they behave the same way as in standard logging handlers. See\n[User guide](http://erlang.org/doc/apps/kernel/logger_chapter.html#protecting-the-handler-from-overload).\nHandler keeps counting dropped messages and will periodically log how many messages were dropped\nsince last report (if any).\n\nThe way [logger:log_event()](http://erlang.org/doc/man/logger.html#type-log_event) is converted\nto a journald flat key-value structure is following:\n\n* `msg` is formatted with formatter and sent as `MESSAGE` field\n* `level` is converted to syslog's numerical value between 0 (\"emergency\") and 7 (\"debug\") and is\n  sent as `PRIORITY` field\n* `meta` fields are encoded in a following way\n  * `file`, `line` and `mfa` are encoded as `CODE_FILE`, `CODE_LINE` and `CODE_FUNC` (in\n    `Module:Function/Arity` form)\n  * `time` is encoded in RFC-3339 format and sent as `SYSLOG_TIMESTAMP` field\n  * `pid` is encoded as a string and sent as `ERL_PID` field\n  * `gl` is encoded the same as `pid` and sent as `ERL_GROUP_LEADER`\n  * `domain` is encoded as dot-separated string (eg `[otp, sasl]` -\u003e `otp.sasl`) and sent as\n    `ERL_DOMAIN`\n  * all the custom metadata field names are converted to uppercase string and values are formatted\n    with `io_lib:format(\"~p\", [Value])`\n\nEncoder works quite well with iolists / iodata values (they are sent as is), but it's slightly\nmore optimized for a binary values.\n\nDevelopment\n-----------\n\nPlease, run the following before committing\n\n```\nmake pre-commit\nmake test\nmake dialyzer\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fseriyps%2Flogger_journald","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fseriyps%2Flogger_journald","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fseriyps%2Flogger_journald/lists"}