Code Monkey home page Code Monkey logo

ex_syslogger's Introduction

ExSyslogger

Build Status Hex.pm Docs Hex.pm Deps Status Hex.pm

ExSyslogger is custom backend for Elixir Logger that logs to syslog by wrapping erlang-syslog.

This project is a fork of exsyslog.

Requirements

  • Elixir ~> 1.3

Features

  • Logs to syslog
  • Allows adding multiple backends with different configurations (e.g. each backend logs to a different facility with different log level)
  • Custom log formatter
  • Built-in JSON formatter(jason dependency is set to optional and you should explicitly add it to your dependency list)

Installation

Add :ex_syslogger as a dependency in your mix.exs file

Elixir 1.5 and above

defp deps do
  [
    {:ex_syslogger, "~> 1.5"}
  ]
end

Elixir ~> 1.4

defp deps do
  [
    {:ex_syslogger, "~> 1.3"}
  ]
end

Add :ex_syslogger to your list of included_applications:

def application do
  [included_applications: [:ex_syslogger]]
end

If you going to use JsonFormatter please we sure that jason is added as dependency in your application. For older Elixir versions it might be needed to add it to the list of applications as above.

Configuration

ExSyslogger is a Logger custom backend, as such, it relies on Logger application.

On your config.exs file tell Logger that it should add ExSyslogger backend

config :logger,
  backends: [
            {ExSyslogger, :ex_syslogger_error},
            {ExSyslogger, :ex_syslogger_debug},
            {ExSyslogger, :ex_syslogger_json}
            ]

With the configuration above, Logger application will add three ExSyslogger backend with the name {ExSyslogger, :ex_syslogger_error}, {ExSyslogger, :ex_syslogger_debug} and {ExSyslogger, :ex_syslogger_json}.

You might notice that instead of just passing the Module name, we're passing a tuple with {Module name, backend configuration name}. This allow us to have multiple backends with different configuration. Let's configure the backends:

config :logger, :ex_syslogger_error,
  level: :error,
  format: "$date $time [$level] $levelpad$node $metadata $message",
  metadata: [:module, :line, :function],
  ident: "MyApplication",
  facility: :local0,
  option: [:pid, :cons]

config :logger, :ex_syslogger_debug,
  level: :debug,
  format: "$date $time [$level] $message",
  ident: "MyApplication",
  facility: :local1,
  option: [:pid, :perror]

config :logger, :ex_syslogger_json,
  level: :debug,
  format: "$message",
  formatter: ExSyslogger.JsonFormatter,
  metadata: [:module, :line, :function],
  ident: "MyApplication",
  facility: :local1,
  option: :pid

Backend configuration properties

  • level (optional): the logging level. It defaults to :info
  • format (optional): Same as :console backend (Logger.Formatter). It defaults to "\n$date $time [$level] $levelpad$node $metadata $message\n"
  • formatter (optional): Formatter that will be used to format the log. It default to Logger.Formatter
  • metadata (optional): Same as :console backend Logger.Formatter. It defaults to []
  • ident (optional): A string that's prepended to every message, and is typically set to the app name. It defaults to "Elixir"
  • facility (optional): syslog facility to be used. It defaults to :local0. More documentation on erlang-syslog
  • option (optional): syslog option to be used. It defaults to :ndelay. More documentation on erlang-syslog

Custom Formatters

ExSyslogger by default uses Logger.Formatter. However, it comes with a JSON formatter that formats a given log entry to a JSON string. NOTE: ExSyslogger.JsonFormatter can be use as an example if one wants to build his own formatter.

To build a custom formatter the formatter needs to implement the following functions:

compile(str) Compiles a format string

compile(binary | nil) :: [Logger.Formatter.pattern | binary]
compile({atom, atom}) :: {atom, atom}

format(format, level, msg, timestamp, metadata, config_metadata) Takes a compiled format and transforms it on a string that will be pass to syslog

format({atom, atom} | [Logger.Formatter.pattern | binary], Logger.level, Logger.message, Logger.Formatter.time, Keyword.t, [atom]) :: IO.chardata

To add the custom formatter you will need to set the formatter property on the configuration as exemplified above with ExSyslogger.JsonFormatter

Try it

In another shell:

$ tail -f /var/log/syslog

(Mac users)

$ tail -f /var/log/system.log

NOTE Mac has a funny syslog. Your info logs might not show up. You'll need to configure your Mac syslog.

Clone the project, go to examples/examples1 and run the project ($ iex -S mix).

Erlang/OTP 18 [erts-7.0.2] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]

Interactive Elixir (1.0.5) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> Example1.run
2015-09-11 15:26:18.850 [error] nonode@nohost module=Elixir.Example1 function=run/0 line=5  Hello ExSyslogger
:ok

You should see on the tail -f something similar to:

exsyslog_error backend

Sep 11 16:26:18 bt.local MyApplication[12833]: 2015-09-11 15:26:18.850 [error] nonode@nohost module=Elixir.Example1 function=run/0 line=5  Hello ExSyslogger

exsyslog_debug backend

Sep 11 16:26:18 bt.local MyApplication[12833]: 2015-09-11 15:26:18.850 [error] Hello ExSyslogger

exsyslog_json backend

Sep 11 16:26:18 bt.local MyApplication[12833]: {"node":"nonode@nohost","module":"Elixir.Example1","message":"Hello ExSyslogger","line":5,"level":"error","function":"run/0"}

The source code is released under the MIT License. Check LICENSE for more information.

ex_syslogger's People

Contributors

aaronjensen avatar bt-dazn avatar mootpointer avatar mr-bt avatar petrohi avatar slashmili avatar smpallen99 avatar surik avatar tylerwitt avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

ex_syslogger's Issues

Warnings when compiling with Elixir 1.5

I get the following warnings because of the deprecations in Elixir 1.5

==> ex_syslogger
Compiling 2 files (.ex)
warning: use GenEvent is deprecated, use one of the alternatives described in the documentation for the GenEvent module
  lib/ex_syslogger.ex:150

warning: the GenEvent module is deprecated, see its documentation for alternatives
  lib/ex_syslogger.ex:150

warning: String.to_char_list/1 is deprecated, use String.to_charlist/1
  lib/ex_syslogger.ex:226
...

Generated ex_syslogger app

unable to run the example

I'm on the latest Mac OS X. Here is what've tried so far:

  • $ git clone https://github.com/slashmili/ex_syslogger.git
  • $ cd ex_syslogger
  • $ mix deps.get
  • $ cd examples/example1
  • $ mix deps.get
  • $ iex -S mix
  • iex(1)> Example1.run

I'll paste the error as is:

2017-07-16 00:37:17.081 [error] nonode@nohost module=Logger.Watcher line=99 function=handle_info/2  :gen_event handler {ExSyslogger, :ex_syslogger_json} installed at Logger
** (exit) an exception was raised:
    ** (UndefinedFunctionError) function Poison.encode/1 is undefined (module Poison is not available)
        Poison.encode(%{level: :error, message: "GenServer #PID<0.170.0> terminating\n** (stop) {:EXIT, {:undef, [{Poison, :encode, [%{level: :error, message: \"GenEvent handler {ExSyslogger, :ex_syslogger_json} installed in Logger terminating\\n** (UndefinedFunctionError) function Poison.encode/1 is undefined (module Poison is not available)\\n    Poison.encode(%{level: :error, message: \\\"GenServer #PID<0.168.0> terminating\\\\n** (stop) {:EXIT, {:undef, [{Poison, :encode, [%{level: :error, message: \\\\\\\"GenEvent handler {ExSyslogger, :ex_syslogger_json} installed in Logger terminating\\\\\\\\n** (UndefinedFunctionError) function Poison.encode/1 is undefined (module Poison is not available)\\\\\\\\n

Does not work with escript "sh: line 1: exec: syslog_drv: not found"

The package works fine for me as long as I use it under mix run. But when I build an executable with escript, it emits an error message and no longer sends things to syslog:

% ./test_syslogger 
sh: line 1: exec: syslog_drv: not found

09:43:11.563 [info]  Just a test 2

(The last line was seen on the console but not in the syslog file.)

Details:

The mix.exs:

defmodule TestSyslogger.MixProject do
  use Mix.Project

  def project do
    [
      app: :test_syslogger,
      version: "0.1.0",
      elixir: "~> 1.9",
      start_permanent: Mix.env() == :prod,
      deps: deps(),
      escript: [main_module: Simple] # Syslogging no longer works if built as a escript "sh: 1: exec: syslog_drv: not found"
    ]
  end

  def application do
    [
      extra_applications: [:logger]
    ]
  end

  defp deps do
    [
      {:ex_syslogger, "~> 2.0.0"} # https://hexdocs.pm/ex_syslogger/ https://github.com/slashmili/ex_syslogger
    ]
  end
end

The module Simple:

  def main(_argv) do
    require Logger

    Logger.configure([level: :debug])
    Logger.add_backend({ExSyslogger, :default_logger})
    #Logger.configure_backend({ExSyslogger, :default_logger}, [])
    Logger.info("Just a test 2")
  end
end

A simple driver for mix run (here, everything works, unlike the escript case):

Simple.main([])

The result of the compilation. syslog_drv.so is built so this bug is different from #8:

% mix run simple.exs 
===> Fetching pc v1.14.0
===> Analyzing applications...
===> Compiling pc
===> Analyzing applications...
===> Compiling syslog
===> Compiling c_src/syslog_drv.c
===> Linking /home/stephane/Programmation/Elixir/essais/test_syslogger/_build/dev/lib/syslog/priv/syslog_drv.so
==> ex_syslogger
Compiling 2 files (.ex)
Generated ex_syslogger app
==> test_syslogger
Compiling 1 file (.ex)
Generated test_syslogger app
% elixir --version
Erlang/OTP 24 [erts-12.3] [source] [64-bit] [smp:1:1] [ds:1:1:10] [async-threads:1] [jit]

Elixir 1.13.2 (compiled with Erlang/OTP 24)

syslog_drv fails to build

If I include {:ex_syslogger, "~> 1.3"} in my deps and build, syslog_drv fails to build.

===> Compiling syslog
==> ex_syslogger
Compiling 2 files (.ex)

Forcing erlang-syslog to the latest release that is not on hex.pm

{:ex_syslogger, "~> 1.3"},
{:syslog, git: "https://github.com/Vagabond/erlang-syslog.git", tag: "1.0.5", override: true}

Fixed this for me

===> Fetching pc ({git,"git://github.com/blt/port_compiler.git",{tag,"1.6.0"}})
===> Compiling pc
===> Compiling syslog
===> Compiling c_src/syslog_drv.c
===> Linking priv/syslog_drv.so
==> ex_syslogger
Compiling 2 files (.ex)

There is an issue on erlang-syslog to push the latest release to hex.pm
Vagabond/erlang-syslog#30

In the meantime, it may be wroth depending on the git version.

Won't compile on OTP 24

#8 seems to be happening again. I created a downstream issue: Vagabond/erlang-syslog#40

โžœ  mix compile
===> Fetching pc v1.12.0
=WARNING REPORT==== 14-May-2021::15:55:53.612552 ===
Description: "Authenticity is not established by certificate path validation"
     Reason: "Option {verify, verify_peer} and cacertfile/cacerts is missing"

===> Analyzing applications...
===> Compiling pc
===> Analyzing applications...
===> Compiling syslog
===> Compiling c_src/syslog_drv.c
===> Linking priv/syslog_drv.so
===> Missing artifact priv/syslog_drv.so
** (Mix) Could not compile dependency :syslog, "/home/alex/.mix/rebar3 bare compile --paths /home/alex/Projects/soapbox/_build/dev/lib/*/ebin" command failed. You can recompile this dependency with "mix deps.compile syslog", update it with "mix deps.update syslog" or clean it with "mix deps.clean syslog"

Crashes when using with config metadata: :all

Elixir Logger console backend accept value :all for metadata backend configuration.
When using this configuration with this lib it crashes with the following:

20:17:25.790 [error] CRASH REPORT Process <0.10004.0> with 0 neighbours exited with reason: {'EXIT',{#{'__exception__' => true,'__struct__' => 'Elixir.Protocol.UndefinedError',description => <<>>,protocol => 'Elixir.Enumerable',value => all},[{'Elixir.Enumerable','impl_for!',1,[{file,"/Users/jose/OSS/elixir/lib/elixir/lib/enum.ex"},{line,1}]},{'Elixir.Enumerable','member?',2,[{file,"/Users/jose/OSS/elixir/lib/elixir/lib/enum.ex"},{line,166}]},{'Elixir.Enum','member?',2,[{file,"lib/enum.ex"},{line,1553}]},{'Elixir.Keyword','-take/2-lists^filter/1-0-',2,[{file,"lib/keyword.ex"},{line,...}]},...]}} in gen_server:handle_common_reply/8 line 751
20:17:25.790 [error] Supervisor 'Elixir.Logger.BackendSupervisor' had child {'Elixir.ExSyslogger',ex_syslogger} started with 'Elixir.Logger.Watcher':start_link({'Elixir.Logger',{'Elixir.ExSyslogger',ex_syslogger},{'Elixir.ExSyslogger',ex_syslogger}}) at <0.10004.0> exit with reason {'EXIT',{#{'__exception__' => true,'__struct__' => 'Elixir.Protocol.UndefinedError',description => <<>>,protocol => 'Elixir.Enumerable',value => all},[{'Elixir.Enumerable','impl_for!',1,[{file,"/Users/jose/OSS/elixir/lib/elixir/lib/enum.ex"},{line,1}]},{'Elixir.Enumerable','member?',2,[{file,"/Users/jose/OSS/elixir/lib/elixir/lib/enum.ex"},{line,166}]},{'Elixir.Enum','member?',2,[{file,"lib/enum.ex"},{line,1553}]},{'Elixir.Keyword','-take/2-lists^filter/1-0-',2,[{file,"lib/keyword.ex"},{line,...}]},...]}} in context child_terminated
:gen_event handler {ExSyslogger, :ex_syslogger} installed in Logger terminating
** (exit) an exception was raised:
    ** (Protocol.UndefinedError) protocol Enumerable not implemented for :all. This protocol is implemented for: Ecto.Adapters.SQL.Stream, Postgrex.Stream, DBConnection.PrepareStream, DBConnection.Stream, Timex.Interval, Date.Range, File.Stream, Function, GenEvent.Stream, HashDict, HashSet, IO.Stream, List, Map, MapSet, Range, Stream
        (elixir) /Users/jose/OSS/elixir/lib/elixir/lib/enum.ex:1: Enumerable.impl_for!/1
        (elixir) /Users/jose/OSS/elixir/lib/elixir/lib/enum.ex:166: Enumerable.member?/2
        (elixir) lib/enum.ex:1553: Enum.member?/2
        (elixir) lib/keyword.ex:927: Keyword."-take/2-lists^filter/1-0-"/2
        (ex_syslogger) lib/ex_syslogger.ex:268: ExSyslogger.format_event/5
        (ex_syslogger) lib/ex_syslogger.ex:215: ExSyslogger.handle_event/2
        (stdlib) gen_event.erl:577: :gen_event.server_update/4
        (stdlib) gen_event.erl:559: :gen_event.server_notify/4
        (stdlib) gen_event.erl:300: :gen_event.handle_msg/6
        (stdlib) proc_lib.erl:249: :proc_lib.init_p_do_apply/3

Do you know why ex_syslogger doesn't support that value for metadata backend configuration?

Exception when manually configuring backend level

I get an exception with the following command:

iex> Logger.configure_backend {ExSyslogger, :my_syslog}, level: :info

The problem is in ExSyslogger.handle_call({.configure, options?,...:

    {:ok, log} = if config.facility !== new_config.facility or
       config.ident !== new_config.ident or
       config.option !== new_config.option do

        close_log(log)
        open_log(new_config)
    end

If the condition fails, the match {:ok, log} = nil raises an exception.

Additionally, I think the if statement should includes a check for level also.

I'll submit a PR shortly.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.