# TimeLogPlug

**Plug to log Phoenix requests and responses with a more accurate time than the custom Phoenix logger**

## Installation

If [available in Hex](, the package can be installed
by adding `time_log` to your list of dependencies in `mix.exs`:

def deps do
    {:time_log, "~> 0.1.1"}

## Usage

To use the TimeLogPlug correctly you have to adjust your `endpoint.ex`. In Phoenix projects >= 1.3 it should be located under `lib/<project_name>_web/endpoint.ex`:

defmodule MyProjectWeb.Endpoint do
  use Phoenix.Endpoint, otp_app: :my_project

  socket "/socket", MyProjectWeb.UserSocket
  plug TimeLog.TimePlug

  if code_reloading? do
    plug Phoenix.CodeReloader

  plug Plug.RequestId,
    http_header: "correlation_id"
  plug Plug.Logger

  plug Plug.Parsers,
    parsers: [:urlencoded, :multipart, :json],
    pass: ["*/*"],
    json_decoder: Poison

  plug Plug.MethodOverride
  plug Plug.Head

  plug Plug.Session,
    store: :cookie,
    key: "duefnkaslndfuefnmsdnfuwefn342n",
    signing_salt: "LIwo9Kg1"

  plug CORSPlug
  plug MyProject.PrometheusExporter     # makes the /metrics URL happen
  plug MyProject.PipelineInstrumenter   # measures pipeline exec times

  plug TimeLog.PreLogPlug
  plug MyProjectWeb.Router

  def init(_key, config) do
    IO.puts "Starting Endpoint...\nWith config #{inspect(config)}"
    if config[:load_from_system_env] do
      IO.puts "Loading from system Env ..."
      port = System.get_env("PORT") || raise "expected the PORT environment variable to be set"
      {:ok, Keyword.put(config, :http, [:inet6, port: port])}
      IO.puts "Not loading from ENV :ok"
      {:ok, config}


Notice that `TimeLog.TimePlug` gets called right after the socket receives the incoming request with the line `plug TimeLog.TimePlug`. In your project add it as early as possible too. This ensures that the response time measurement is as accurate as possible.

If you want detailed logging of the incoming request - including an ip check for internal ips (that are used for testing for example) - use the TimeLog.PrelogPlug and include the line `plug TimeLog.PreLogPlug` right before the Router of your app is called.

## Config

Within your config you can setup what an internal ip is in terms of your app, what name should be shown if an internal ip requested something or requests to which urls to ignore altogether.
You can append your config with:


  config :time_log,
    internal_ips: ["", "", ""],      # The IP's that identify a request as internal, used for testing purposes for example
    internal_name: "Internal IP",                                                     # The name that should be logged instead of Internal IP address
    ignore_urls: ["/health"],                                                               # Urls that should not be logged
    anonymize_ips?: true,                                                                   # Should ips be anonymized for privacy of customer data?
    sanitize_string: "*",                                           # String which replaces values of sanitized fields
    wildcard_string: "*",                                           # Wildcard string which can be used for sanitize fields e.g. "map.*" => sanitize all field values in "map"
    sanitize_fields: ["*.map.*", "anotherMap.field", "list.*.field"]            # "*.map.*" => searchs for field "map" in any level and sanitize all field values underneath. "anotherMap.field" searchs field "anotherMap" in first level and sanitize only value of "field". If "field" is a map or list, use "anotherMap.field.*" otherwise it won't sanitize any field in that map or list. "list.*.field" the wildcard "*" between "list" and "field" means that it will firstly search for list in first level, secondly it will search for "field" in any level under "list" and sanitize it. If the wildcard is infront of a field it will ignore the level of the structure, if it's behind a field e.g. "map.*" it will sanitize all fields under that structure.


The docs can be found at [](