Packages

Elixir loggly is a backend that forwards all log messages to the Loggly service.

Current section

Files

Jump to
ioffice_logglix lib logglix.ex
Raw

lib/logglix.ex

defmodule Logglix do
@moduledoc """
This module contains the GenEvent that you can use to transmit the logs of
your applications.
### Configuring
By default the LOGGLY_KEY environment variable is used to find
your API key for Loggly. You can also manually set your API key by
configuring the :logglix application.
config :logger, :logglix,
loggly_key: System.get_env("LOGGLY_KEY"),
tags: ["elixir"],
level: :info,
environment: :prod
The configuration defaults to:
config :logger, :logglix,
host: "http://logs-01.loggly.com",
loggly_key: System.get_env("LOGGLY_KEY"),
tags: [],
level: :info,
metadata: [],
formatter: Logger.Formatter,
timeout: 5000,
type: :inputs
"""
use GenEvent
@api_host "http://logs-01.loggly.com"
defmodule MissingLogglyKeyError do
defexception message: """
The loggly_key setting is required so that we can report the
correct environment name to Loggly. Please configure
loggly_key in your config.exs and environment specific config files
to have accurate reporting of errors.
config :logger, :logglix, loggly_key: YOUR_LOGGLY_KEY
"""
end
@doc false
def init({__MODULE__, name}) do
{:ok, setup(name, []) }
end
@doc false
def handle_call({:setup, opts}, %{name: name}) do
{:ok, :ok, setup(name, opts)}
end
@doc false
def handle_event({_level, gl, _event}, config) when node(gl) != node() do
{:ok, config}
end
@doc false
def handle_event({level, _gl, {Logger, msg, timestamp, metadata}}, config) do
if meet_level?(level, config.level) do
log_event(level, msg, timestamp, metadata, config)
end
{:ok, config}
end
defp meet_level?(_lvl, nil), do: true
defp meet_level?(lvl, min) do
Logger.compare_levels(lvl, min) != :lt
end
defp take_metadata(metadata, keys) do
metadatas = Enum.reduce(keys, [], fn key, acc ->
case Keyword.fetch(metadata, key) do
{:ok, val} -> [{key, val} | acc]
:error -> acc
end
end)
Enum.reverse(metadatas)
end
defp get_config(environment, key, default) do
Keyword.get(environment, key, default)
end
defp format_event(level, msg, timestamp, metadata, %{format: format, formatter: Logger.Formatter, metadata: config_metadata}) do
Logger.Formatter.format(format, level, msg, timestamp, take_metadata(metadata, config_metadata))
end
defp format_event(level, msg, timestamp, metadata, %{format: format, formatter: formatter, metadata: config_metadata}) do
apply(formatter, :format,
[format, level, msg, timestamp, metadata, config_metadata])
end
defp log_event(level, msg, timestamp, metadata, config) do
output = format_event(level, msg, timestamp, metadata, config)
HTTPoison.post(config.url, output, %{"content-type": "text/plain"}, timeout: config.timeout)
end
defp require_loggly_key(environment) do
case get_config(environment, :loggly_key, :not_found) do
:not_found ->
raise MissingLogglyKeyError
value -> value
end
end
defp setup(name, opts) do
environment = Application.get_env(:logger, name, [])
opts = Keyword.merge(environment, opts)
Application.put_env(:logger, name, opts)
format = Keyword.get(opts, :format) |> Logger.Formatter.compile
loggly_key = require_loggly_key(opts)
level = get_config(opts, :level, :info)
tags = get_config(opts, :tags, [])
log_type = get_config(opts, :type, :inputs)
timeout = get_config(opts, :timeout, 5000)
host = get_config(opts, :host, @api_host)
metadata = get_config(opts, :metadata, [])
formatter = get_config(opts, :formatter, Logger.Formatter)
%{name: name,
url: "#{host}/#{log_type}/#{loggly_key}/tag/#{Enum.join(tags, ",")}",
format: format,
formatter: formatter,
level: level,
metadata: metadata,
tags: tags,
timeout: timeout}
end
end