Current section
Files
Jump to
Current section
Files
lib/driftwood.ex
defmodule Driftwood do
@moduledoc false
end
#@default_format "$dateT$time [$level] $metadata $message\n"
#defstruct level: :info, format: @default_format, metadata: [:request_id]
#defmodule Driftwood do
#@moduledoc false
#use GenEvent
#@default_format "$dateT$time [$level] $metadata $message\n"
#defstruct level: nil, format: @default_format, metadata: nil
##defstruct [format: nil, metadata: nil, level: nil, colors: nil, device: nil,
##max_buffer: nil, buffer_size: 0, buffer: [], ref: nil, output: nil]
#def init({__MODULE__, opts}) when is_list(opts) do
#config = Keyword.merge(Application.get_env(:logger, :driftwood), opts)
#{:ok, init(config, %__MODULE__{})}
#end
#def handle_call({:configure, options}, state) do
#{:ok, :ok, configure(options, state)}
#end
#def handle_event({_level, gl, _event}, state) when node(gl) != node() do
#{:ok, state}
#end
#def handle_event({level, _gl, {Logger, msg, ts, md}}, state) do
#%{level: log_level} = state
#cond do
#meet_level?(level, log_level) ->
## do the logging
#output = format_event(level, msg, ts, md, state)
#end
#{:ok, state}
#end
#def handle_event(:flush, state) do
## we don't buffer
#{:ok, state}
#end
#def handle_event(_, state) do
#{:ok, state}
#end
#def code_change(_old_vsn, state, _extra) do
#{:ok, state}
#end
#def terminate(_reason, _state) do
#:ok
#end
#def handle_info(_, state) do
#{:ok, state}
#end
#defp configure(options, state) do
#config = Keyword.merge(Application.get_env(:logger, :console), options)
#Application.put_env(:logger, :driftwood, config)
#init(config, state)
#end
#defp init(config, state) do
#level = Keyword.get(config, :level)
#format = Logger.Formatter.compile Keyword.get(config, :format)
#metadata = Keyword.get(config, :metadata, [])
#%{state | format: format, metadata: Enum.reverse(metadata),
#level: level}
#end
#defp meet_level?(_lvl, nil), do: true
#defp meet_level?(lvl, min) do
#Logger.compare_levels(lvl, min) != :lt
#end
#defp format_event(level, msg, ts, md, %{format: format, metadata: keys}) do
#Logger.Formatter.format(format, level, msg, ts, take_metadata(md, keys))
#end
#defp take_metadata(metadata, keys) do
#Enum.reduce keys, [], fn key, acc ->
#case Keyword.fetch(metadata, key) do
#{:ok, val} -> [{key, val} | acc]
#:error -> acc
#end
#end
#end
#end
#defmodule Driftwood.Cache do
#@moduledoc """
#Cache for the logs
### Usage
#children = [
## ...
#worker(Driftwood.Cache, [])
#]
#"""
#use GenServer
#def start_link(name, _opts) do
#GenServer.start_link(__MODULE__, , opts)
#end
#def init({name, clean_period}) do
#^name = :ets.new(name, [:named_table, :public,
#write_concurrency: true, read_concurrency: true])
#schedule(clean_period)
#{:ok, %{clean_period: clean_period, name: name}}
#end
#@doc """
#Implementation for the PlugAttack.Storage.increment/4 callback.
#"""
#def increment(name, key, inc, expires_at) do
#:ets.update_counter(name, key, inc, {key, 0, expires_at})
#end
#@doc """
#Implementation for the PlugAttack.Storage.write_sliding_counter/3 callback.
#"""
#def write_sliding_counter(name, key, now, expires_at) do
#true = :ets.insert(name, {{key, now}, 0, expires_at})
#:ok
#end
#@doc """
#Implementation for the PlugAttack.Storage.read_sliding_counter/3 callback.
#"""
#def read_sliding_counter(name, key, now) do
#ms = :ets.fun2ms(fn {{^key, _}, _, expires_at} ->
#expires_at > now
#end)
#:ets.select_count(name, ms)
#end
#@doc """
#Implementation for the PlugAttack.Storage.write/4 callback.
#"""
#def write(name, key, value, expires_at) do
#true = :ets.insert(name, {key, value, expires_at})
#:ok
#end
#@doc """
#Implementation for the PlugAttack.Storage.read/3 callback.
#"""
#def read(name, key, now) do
#case :ets.lookup(name, key) do
#[{^key, value, expires_at}] when expires_at > now ->
#{:ok, value}
#_ ->
#:error
#end
#end
#@doc """
#Forcefully clean the storage.
#"""
#def clean(name) do
#:ets.delete_all_objects(name)
#end
#@doc """
#Starts the storage table and cleaner process.
#The process is registered under `name` and a public, named ets table
#with that name is created as well.
### Options
#* `:clean_period` - how often the ets table should be cleaned of stale
#data. The key scheme guarantees stale data won't be used for making
#decisions. This is only about limiting memory consumption
#(default: 5000 ms).
#"""
#def start_link(name, opts \\ []) do
#clean_period = Keyword.get(opts, :clean_period, 5_000)
#GenServer.start_link(__MODULE__, {name, clean_period}, opts)
#end
#@doc false
#def init() do
#db = :ets.new(__MODULE__, [:named_table, :public,
#write_concurrency: true, read_concurrency: true])
#{:ok, %{db: db}}
#end
#end