{"id":16592422,"url":"https://github.com/hauleth/erlang-systemd","last_synced_at":"2025-04-14T08:56:15.301Z","repository":{"id":42573852,"uuid":"203662267","full_name":"hauleth/erlang-systemd","owner":"hauleth","description":"systemd utilities for Erlang applications","archived":false,"fork":false,"pushed_at":"2025-02-11T14:59:57.000Z","size":291,"stargazers_count":183,"open_issues_count":9,"forks_count":19,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-04-07T02:06:32.009Z","etag":null,"topics":["elixir","elixir-lang","erlang","hacktoberfest","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/hauleth.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","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},"funding":{"github":["hauleth"]}},"created_at":"2019-08-21T20:48:45.000Z","updated_at":"2025-03-27T05:12:19.000Z","dependencies_parsed_at":"2024-10-30T16:02:53.490Z","dependency_job_id":"562c0bda-e1ed-498a-b12e-4e136960e809","html_url":"https://github.com/hauleth/erlang-systemd","commit_stats":{"total_commits":121,"total_committers":8,"mean_commits":15.125,"dds":0.07438016528925617,"last_synced_commit":"81e98d35d1330d8903ef6823f53bf856a60ce9d2"},"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hauleth%2Ferlang-systemd","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hauleth%2Ferlang-systemd/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hauleth%2Ferlang-systemd/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/hauleth%2Ferlang-systemd/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/hauleth","download_url":"https://codeload.github.com/hauleth/erlang-systemd/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248852112,"owners_count":21171839,"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":["elixir","elixir-lang","erlang","hacktoberfest","systemd"],"created_at":"2024-10-11T23:20:52.025Z","updated_at":"2025-04-14T08:56:15.275Z","avatar_url":"https://github.com/hauleth.png","language":"Erlang","funding_links":["https://github.com/sponsors/hauleth"],"categories":["Erlang"],"sub_categories":[],"readme":"systemd\n=====\n\n[![Hex.pm](https://img.shields.io/hexpm/v/systemd?style=flat-square)](https://hex.pm/packages/systemd)\n[![HexDocs](https://img.shields.io/badge/HexDocs-docs-blue?style=flat-square)](https://hexdocs.pm/systemd/)\n[![Hex.pm License](https://img.shields.io/hexpm/l/systemd?style=flat-square)](https://tldrlegal.com/license/apache-license-2.0-(apache-2.0))\n[![GitHub Workflow Status](https://img.shields.io/github/actions/workflow/status/hauleth/erlang-systemd/erlang.yml?branch=master\u0026style=flat-square)](https://github.com/hauleth/erlang-systemd/actions)\n[![Codecov](https://img.shields.io/codecov/c/gh/hauleth/erlang-systemd?style=flat-square)](https://codecov.io/gh/hauleth/erlang-systemd)\n\nSimple library for notifying systemd about process state.\n\n## Features\n\n- `NOTIFY_SOCKET` communication with supervising process.\n- Watchdog process will be started automatically (if not disabled). It will also\n  handle sending keep-alive messages automatically.\n- Fetching file descriptors passed by the supervisor.\n- `journal` logger handler and formatters.\n\n## Installation\n\nJust add this to your `rebar.config`:\n\n```erlang\n{deps, [systemd]}.\n```\n\nOr in case of Mix project, to your `mix.exs`:\n\n```elixir\ndefp deps do\n  [\n    {:systemd, \"~\u003e 0.6\"}\n  ]\nend\n```\n\nThen call `systemd:notify(ready)` when your application is ready to work/accept\nconnections or add `systemd:ready()` as a child of your application's main supervisor.\n\n### Non-systemd systems\n\nThis application and all functions within are safe to call even in non-systemd\nand non-Linux OSes. In case if there is no systemd configuration options then\nall functions will simply work as (almost) no-ops.\n\n## Usage\n\nAssuming you have `my_app.service` unit like that\n\n```ini\n[Unit]\nDescription=My Awesome App\n\n[Service]\nUser=appuser\nGroup=appgroup\n# This will allow using `systemd:notify/1` for informing the system supervisor\n# about application status.\nType=notify\n# Application need to start in foreground instead of forking into background,\n# otherwise it may be not correctly detected and system will try to start it\n# again.\nExecStart=/path/to/my_app start\n# Enable watchdog process, which will expect messages in given timeframe,\n# otherwise it will restart the process as a defunct. It should be managed\n# automatically by `systemd` application in most cases and will send messages\n# twice as often as requested.\n#\n# You can force failure by using `systemd:watchdog(trigger)` or manually ping\n# systemd watchdog via `systemd:watchdog(ping)`.\nWatchdogSec=10s\nRestart=on-failure\n\n[Install]\nWantedBy=multi-user.target\n```\n\nYou can inform systemd about state of your application. To do so just call:\n\n```erlang\n% Erlang\nsystemd:notify(ready).\n```\n\n```elixir\n# Elixir\n:systemd.notify(:ready)\n```\n\nThis will make `systemctl start my_app.service` to wait until application is up\nand running.\n\nIf you want to restart your application you can notify systemd about it with:\n\n```erlang\n% Erlang\nsystemd:notify(reloading).\n```\n\n```elixir\n# Elixir\n:systemd.notify(:reloading)\n```\n\nMessage about application shutting down will be handled automatically for you.\n\nFor simplification of readiness notification there is `systemd:ready()` function\nthat returns child specs for temporary process that can be used as a part of\nyour supervision tree to mark the point when application is ready, ex.:\n\n```erlang\n% Erlang\n-module(my_app_sup).\n\n-behaviour(supervisor).\n\n-export([start_link/1,\n         init/1]).\n\nstart_link(Opts) -\u003e\n    supervisor:start_link({local, ?MODULE}, ?MODULE, Opts).\n\ninit(_Opts) -\u003e\n    SupFlags = #{\n      strategy =\u003e one_for_one\n    },\n    Children = [\n      my_app_db:child_spec(),\n      my_app_webserver:child_spec(),\n      systemd:ready(),\n      my_app_periodic_job:child_spec()\n    ],\n\n    {ok, {SupFlags, Children}}.\n```\n\n```elixir\n# Elixir\ndefmodule MyProject.Application do\n  use Application\n\n  def start(_type, _opts) do\n    children = [\n      MyProject.Repo,\n      MyProjectWeb.Endpoint,\n      :systemd.ready() # \u003c- IMPORTANT - this is a function call (it returns the proper child spec)\n    ]\n\n    Supervisor.start_link(children, strategy: :one_for_one)\n  end\nend\n```\n\n### Logs\n\nTo handle logs you have 2 possible options:\n\n- Output data to standard output or error with special prefixes. This approach\n  is much simpler and straightforward, however do not support structured logging\n  and multiline messages.\n- Use datagram socket with special communication protocol. This requires a\n  little bit more effort to set up, but seamlessly supports structured logging\n  and multiline messages.\n\nThis library supports both formats, and it is up to You which one (or\nboth?) your app will decide to use.\n\n#### Erlang\n\n##### Standard error\n\nThere is `systemd_kmsg_formatter` which formats data using `kmsg`-like level\nprefixes can be used with any logger that outputs to standard output or\nstandard error if this is attached to the journal. By default `systemd` library\nwill update all handlers that use `logger_std_h` with type `standard_io` or\n`standard_error` that are attached to the journal (it is automatically detected\nvia `JOURNAL_STREAM` environment variable). You can disable that behaviour by\nsetting:\n\n```erlang\n% Erlang\n[\n  {systemd, [{install_kmsg, false}]}\n].\n```\n\nFor custom loggers you can use this formatter by adding new option `parent` to\nthe formatter options that will be used as \"upstream\" formatter, ex.:\n\n```erlang\nlogger:add_handler(example_handler, logger_disk_log_h, #{\n  formatter =\u003e {systemd_kmsg_formatter, #{parent =\u003e logger_formatter,\n                                          template =\u003e [msg]},\n  config =\u003e #{\n    file =\u003e \"/var/log/my_app.log\"\n  }\n}).\n```\n\n##### Datagram socket\n\nThis one requires `systemd` application to be started to spawn some processes\nrequired for handling sockets, so the best way to handle it is to add predefined\n`systemd` handlers after your application starts:\n\n```erlang\nlogger:add_handlers(systemd),\nlogger:remove_handler(default).\n```\n\nBe aware that this one is **not** guaranteed to work on non-systemd systems, so\nif You aren't sure if that application will be ran on systemd-enabled OS then\nyou shouldn't use it as an only logger solution in your application or you can\nend with no logger attached at all.\n\nThis handler **should not** be used with `systemd_kmsg_formatter` as this will\nresult with pointless `kmsg`-like prefixes in the log messages.\n\nYou can also \"manually\" configgure handler if you want to configure formatter:\n\n```erlang\nlogger:add_handler(my_handler, systemd_journal_h, #{\n  formatter =\u003e {my_formatter, FormatterOpts}\n}),\nlogger:remove_handler(default).\n```\n\n#### Elixir\n\nThis assumes Elixir 1.10+, as earlier versions do not use Erlang's `logger`\nmodule for dispatching logs.\n\n##### Standard error\n\n`systemd` has Erlang's `logger` backend, which mean that you have 2 ways of\nachieving what is needed:\n\n1. Disable Elixir's backends and just rely on default Erlang's handler:\n  ```elixir\n  # config/config.exs\n  config :logger,\n    backends: [],\n    handle_otp_reports: false,\n    handle_sasl_reports: false\n  ```\n  And then allow `systemd` to make its magic that is used in \"regular\" Erlang\n  code.\n\n2. \"Manually\" add handler that will use `systemd_kmsg_formatter`:\n  ```elixir\n  # In application start/2 callback\n  :ok = :logger.add_handler(\n    :my_handler,\n    :logger_std_h,\n    %{formatter: {:systemd_kmsg_formatter, %{}}}\n  )\n  Logger.remove_backend(:console)\n  ```\n\nHowever remember, that currently (as Elixir 1.11) there is no \"Elixir formatter\"\nfor Erlang's `logger` implementation, so you can end with Erlang-style\nformatting of the metadata in the logs.\n\n##### Datagram socket\n\nYou can use Erlang-like approach, which is:\n\n```elixir\n# In application start/2 callback\n:logger.add_handlers(:systemd)\nLogger.remove_backend(:console)\n```\n\nOr you can manually configure the handler:\n\n```elixir\n# In application start/2 callback\n:logger.add_handler(\n  :my_handler,\n  :systemd_journal_h,\n  %{formatter: {MyFormatter, formatter_opts}}\n)\nLogger.remove_backend(:console)\n```\n\nBe aware that this one is **not** guaranteed to work on non-systemd systems, so\nif You aren't sure if that application will be ran on systemd-enabled OS then\nyou shouldn't use it as an only logger solution in your application or you can\nend with no logger attached at all.\n\nThis handler **should not** be used with `:systemd_kmsg_formatter` as this will\nresult with pointless `kmsg`-like prefixes in the log messages.\n\n## License\n\nSee [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhauleth%2Ferlang-systemd","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhauleth%2Ferlang-systemd","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhauleth%2Ferlang-systemd/lists"}