diff --git a/.formatter.exs b/.formatter.exs index 00950e6..0a70dc0 100644 --- a/.formatter.exs +++ b/.formatter.exs @@ -1,4 +1,5 @@ +# Used by "mix format" [ - inputs: ["mix.exs", "{config,lib,test}/**/*.{ex,exs}"], + inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"], line_length: 120 ] diff --git a/.gitignore b/.gitignore index 411e19e..0bf7070 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,29 @@ -/_build -/cover -/deps +# The directory Mix will write compiled artifacts to. +/_build/ + +# If you run "mix test --cover", coverage assets end up here. +/cover/ + +# The directory Mix downloads your dependencies sources to. +/deps/ + +# Where third-party dependencies like ExDoc output generated docs. +/doc/ + +# Ignore .fetch files in case you like to edit your project deps locally. +/.fetch + +# If the VM crashes, it generates a dump, let's ignore it too. erl_crash.dump + +# Also ignore archive artifacts (built via "mix archive.build"). *.ez + +# Ignore package tarball (built via "mix hex.build"). +plug_logger_json-*.tar + +# Temporary files for e.g. tests. +/tmp + +# Misc. .local.plt -doc/ -.elixir_ls \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 66b10ad..a98bda1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,44 +1,49 @@ # Changelog -## Master +All notable changes to this project will be documented in this file. -## 0.7.0 +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## v0.7.0 - 2019-04-22 * Updated Readme -* Updated Dependencies -* Ran Formatter +* Updated Dependencies +* Ran Formatter * Fixed warnings up to 1.8 * Support nested param filtering -## 0.6.0 -* Extra configration that allows control of logging debug fields. +## v0.6.0 - 2017-12-26 +* Extra configuration that allows control of logging debug fields. * Allow built-in logging keys to be suppressed * Add Elixir 1.5.3 official support * Add Erlang/OTP 20.1 official support * Update dev & test dependencies -## 0.5.0 -* Extra attributes configration that allows for logging custom metrics +## v0.5.0 - 2017-08-21 +* Extra attributes configuration that allows for logging custom metrics * Add Elixir 1.5.1 * Add Erlang/OTP 20 * Add Erlang/OTP 19.3 to test suite -## v0.4.0 +## v0.4.0 - 2017-03-18 * Breaking Changes! * Log errors with logger level `error` instead of `info` * Change `status` field to an integer type instead of string * Drop official support of Elixir 1.2 and OTP 18 * Add support for Elixir 1.4 and OTP 19.1 & 19.2 -* Update depedencies +* Update dependencies * Fix dialyzer warnings -## v0.3.1 -* Update depedencies +## v0.3.1 - 2017-01-05 +* Update dependencies * Fix Elixir 1.4 warnings -## v0.3.0 +## v0.3.0 - 2016-11-22 * Breaking Changes! * Drop the `fastly_duration` log value * Add the ability to change verbosity. Log levels warn/debug will return everything from 0.2 minus fastly_duration. Log levels info/error will return a subset of warn/debug that is missing params, client_ip, & client_version. -## v0.2 +## v0.2.0 - 2016-10-26 * Add support for error logging tagged with the request id. Errors now are bunched up as a single JSON message in addition to the standard output for easier parsing of errors and matching requests to the resulting error. diff --git a/LICENSE b/LICENSE index ca26154..e2dd540 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2016 Bleacher Report + Copyright (c) 2016 Bleacher Report Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index 3a76705..4647520 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,19 @@ -# PlugLoggerJson -[![Hex pm](http://img.shields.io/hexpm/v/plug_logger_json.svg?style=flat)](https://hex.pm/packages/plug_logger_json) +# Plug Logger JSON + [![Build Status](https://travis-ci.org/bleacherreport/plug_logger_json.svg?branch=master)](https://travis-ci.org/bleacherreport/plug_logger_json) -[![License](https://img.shields.io/badge/license-Apache%202-blue.svg)](https://github.com/bleacherreport/plug_logger_json/blob/master/LICENSE) +[![Module Version](https://img.shields.io/hexpm/v/plug_logger_json.svg)](https://hex.pm/packages/plug_logger_json) +[![Hex Docs](https://img.shields.io/badge/hex-docs-lightgreen.svg)](https://hexdocs.pm/plug_logger_json/) +[![Total Download](https://img.shields.io/hexpm/dt/plug_logger_json.svg)](https://hex.pm/packages/plug_logger_json) +[![License](https://img.shields.io/hexpm/l/plug_logger_json.svg)](https://github.com/bleacherreport/plug_logger_json/blob/master/LICENSE) +[![Last Updated](https://img.shields.io/github/last-commit/bleacherreport/plug_logger_json.svg)](https://github.com/bleacherreport/plug_logger_json/commits/master) + A comprehensive JSON logger Plug. ## Dependencies -* Plug -* Poison +* `Plug` +* `Poison` ## Elixir & Erlang Support @@ -16,15 +21,17 @@ The support policy is to support the last 2 major versions of Erlang and the thr ## Installation -1. add plug_logger_json to your list of dependencies in `mix.exs`: +1. Add `:plug_logger_json` to your list of dependencies in `mix.exs`: ```elixir def deps do - [{:plug_logger_json, "~> 0.7.0"}] + [ + {:plug_logger_json, "~> 0.7.0"} + ] end ``` -2. ensure plug_logger_json is started before your application (Skip if using Elixir 1.4 or greater): +2. Ensure `:plug_logger_json` is started before your application (Skip if using Elixir 1.4 or greater): ```elixir def application do @@ -64,53 +71,55 @@ config :logger, :console, Do the following: -* update deps in `mix.exs` with the following: +* Update deps in `mix.exs` with the following: - ```elixir - def deps do - [{:logger_file_backend, "~> 0.0.10"}] - end - ``` + ```elixir + def deps do + [ + {:logger_file_backend, "~> 0.0.10"} + ] + end + ``` -* add to your `config/config.exs` or `config/env_name.exs`: +* Add to your `config/config.exs` or `config/env_name.exs`: - ```elixir - config :logger, - format: "$message\n", - backends: [{LoggerFileBackend, :log_file}, :console] + ```elixir + config :logger, + format: "$message\n", + backends: [{LoggerFileBackend, :log_file}, :console] - config :logger, :log_file, - format: "$message\n", - level: :info, - metadata: [:request_id], - path: "log/my_pipeline.log" - ``` + config :logger, :log_file, + format: "$message\n", + level: :info, + metadata: [:request_id], + path: "log/my_pipeline.log" + ``` -* ensure you are using `Plug.Parsers` (Phoenix adds this to `endpoint.ex` by default) to parse params as well as request body: +* Ensure you are using `Plug.Parsers` (Phoenix adds this to `endpoint.ex` by default) to parse params as well as request body: - ```elixir - plug Plug.Parsers, - parsers: [:urlencoded, :multipart, :json], - pass: ["*/*"], - json_decoder: Poison - ``` + ```elixir + plug Plug.Parsers, + parsers: [:urlencoded, :multipart, :json], + pass: ["*/*"], + json_decoder: Poison + ``` ## Error Logging In `router.ex` of your Phoenix project or in your plug pipeline: -* add `require Logger`, -* add `use Plug.ErrorHandler`, -* add the following two private functions: +* Add `require Logger`, +* Add `use Plug.ErrorHandler`, +* Add the following two private functions: - ```elixir - defp handle_errors(%Plug.Conn{status: 500} = conn, %{kind: kind, reason: reason, stack: stacktrace}) do - Plug.LoggerJSON.log_error(kind, reason, stacktrace) - send_resp(conn, 500, Poison.encode!(%{errors: %{detail: "Internal server error"}})) - end + ```elixir + defp handle_errors(%Plug.Conn{status: 500} = conn, %{kind: kind, reason: reason, stack: stacktrace}) do + Plug.LoggerJSON.log_error(kind, reason, stacktrace) + send_resp(conn, 500, Poison.encode!(%{errors: %{detail: "Internal server error"}})) + end - defp handle_errors(_, _), do: nil - ``` + defp handle_errors(_, _), do: nil + ``` ## Extra Attributes @@ -178,6 +187,20 @@ Before submitting your pull request, please run: * `mix credo --strict`, * `mix coveralls`, * `mix dialyzer`, - * update changelog. + * Update changelog. Please squash your pull request's commits into a single commit with a message and detailed description explaining the commit. + +## Copyright and License + +Copyright (c) 2016 Bleacher Report + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at [http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0) + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/lib/plug/logger_json.ex b/lib/plug/logger_json.ex index 7ad66b7..096bca2 100644 --- a/lib/plug/logger_json.ex +++ b/lib/plug/logger_json.ex @@ -1,6 +1,7 @@ defmodule Plug.LoggerJSON do @moduledoc """ A plug for logging basic request information in the format: + ```json { "api_version": "N/A" @@ -22,33 +23,37 @@ defmodule Plug.LoggerJSON do ``` To use it, just plug it into the desired module. - plug Plug.LoggerJSON, log: :debug + + plug Plug.LoggerJSON, log: :debug + ## Options + * `:log` - The log level at which this plug should log its request info. - Default is `:info`. + Default is `:info`. + * `:extra_attributes_fn` - Function to call with `conn` to add additional - fields to the requests. Default is `nil`. Please see "Extra Fields" section - for more information. + fields to the requests. Default is `nil`. Please see "Extra Fields" section + for more information. ## Extra Fields Additional data can be logged alongside the request by specifying a function to call which returns a map: - def extra_attributes(conn) do - map = %{ - "user_id" => get_in(conn.assigns, [:user, :user_id]), - "other_id" => get_in(conn.private, [:private_resource, :id]), - "should_not_appear" => conn.private[:does_not_exist] - } + def extra_attributes(conn) do + map = %{ + "user_id" => get_in(conn.assigns, [:user, :user_id]), + "other_id" => get_in(conn.private, [:private_resource, :id]), + "should_not_appear" => conn.private[:does_not_exist] + } - map - |> Enum.filter(&(&1 !== nil)) - |> Enum.into(%{}) - end + map + |> Enum.filter(&(&1 !== nil)) + |> Enum.into(%{}) + end - plug Plug.LoggerJSON, log: Logger.level, - extra_attributes_fn: &MyPlug.extra_attributes/1 + plug Plug.LoggerJSON, log: Logger.level, + extra_attributes_fn: &MyPlug.extra_attributes/1 In this example, the `:user_id` is retrieved from `conn.assigns.user.user_id` and added to the log if it exists. In the example, any values that are `nil` @@ -237,7 +242,14 @@ defmodule Plug.LoggerJSON do "-" <> zero_pad(month, 2) <> "-" <> - zero_pad(day, 2) <> "T" <> zero_pad(hour, 2) <> ":" <> zero_pad(minute, 2) <> ":" <> zero_pad(second, 2) <> "Z" + zero_pad(day, 2) <> + "T" <> + zero_pad(hour, 2) <> + ":" <> + zero_pad(minute, 2) <> + ":" <> + zero_pad(second, 2) <> + "Z" end @spec phoenix_attributes(map()) :: map() diff --git a/mix.exs b/mix.exs index ce98341..08061bf 100644 --- a/mix.exs +++ b/mix.exs @@ -1,30 +1,35 @@ defmodule PlugLoggerJson.Mixfile do use Mix.Project + @source_url "https://github.com/bleacherreport/plug_logger_json" + @version "0.7.0" + def project do [ app: :plug_logger_json, + name: "Plug Logger JSON", build_embedded: Mix.env() == :prod, - deps: deps(), - dialyzer: [ - plt_add_deps: true - ], - description: "Elixir Plug that formats http request logs as json", - docs: [extras: ["README.md"]], + start_permanent: Mix.env() == :prod, elixir: "~> 1.3", - homepage_url: "https://github.com/bleacherreport/plug_logger_json", - name: "Plug Logger JSON", + version: @version, + deps: deps(), package: package(), - preferred_cli_env: [coveralls: :test, "coveralls.detail": :test, "coveralls.post": :test, "coveralls.html": :test], - source_url: "https://github.com/bleacherreport/plug_logger_json", - start_permanent: Mix.env() == :prod, + docs: docs(), test_coverage: [tool: ExCoveralls], - version: "0.7.0" + dialyzer: [plt_add_deps: true], + preferred_cli_env: [ + coveralls: :test, + "coveralls.detail": :test, + "coveralls.post": :test, + "coveralls.html": :test + ] ] end def application do - [applications: [:logger, :plug]] + [ + applications: [:logger, :plug] + ] end defp deps do @@ -32,7 +37,7 @@ defmodule PlugLoggerJson.Mixfile do {:credo, "~> 1.0.2", only: [:dev]}, {:dialyxir, "~> 0.5.1", only: [:dev]}, {:earmark, "~> 1.3.1", only: [:dev]}, - {:ex_doc, "~> 0.19.3", only: [:dev]}, + {:ex_doc, ">= 0.0.0", only: [:dev], runtime: false}, {:excoveralls, "~> 0.10.5", only: [:test]}, {:plug, "~> 1.0"}, {:poison, "~> 1.5 or ~> 2.0 or ~> 3.0 or ~> 4.0"} @@ -41,10 +46,29 @@ defmodule PlugLoggerJson.Mixfile do defp package do [ - files: ["lib", "mix.exs", "README*", "LICENSE*"], - licenses: ["Apache 2.0"], - links: %{"GitHub" => "https://github.com/bleacherreport/plug_logger_json"}, - maintainers: ["John Kelly, Ben Marx"] + description: "Elixir Plug that formats HTTP request logs as JSON.", + files: ["lib", "mix.exs", "README*", "LICENSE*", "CHANGELOG*"], + licenses: ["Apache-2.0"], + maintainers: ["John Kelly, Ben Marx"], + links: %{ + "Changelog" => "https://hexdocs.pm/plug_logger_json/changelog.html", + "GitHub" => @source_url + }, + ] + end + + defp docs do + [ + extras: [ + "CHANGELOG.md", + "LICENSE": [title: "License"], + "README.md": [title: "Overview"] + ], + main: "readme", + source_url: @source_url, + source_ref: @version, + api_reference: false, + formatters: ["html"] ] end end diff --git a/mix.lock b/mix.lock index eb3ebfa..13efe92 100644 --- a/mix.lock +++ b/mix.lock @@ -1,26 +1,28 @@ %{ - "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm"}, - "certifi": {:hex, :certifi, "2.4.2", "75424ff0f3baaccfd34b1214184b6ef616d89e420b258bb0a5ea7d7bc628f7f0", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm"}, - "credo": {:hex, :credo, "1.0.2", "88bc918f215168bf6ce7070610a6173c45c82f32baa08bdfc80bf58df2d103b6", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"}, - "dialyxir": {:hex, :dialyxir, "0.5.1", "b331b091720fd93e878137add264bac4f644e1ddae07a70bf7062c7862c4b952", [:mix], [], "hexpm"}, - "earmark": {:hex, :earmark, "1.3.1", "73812f447f7a42358d3ba79283cfa3075a7580a3a2ed457616d6517ac3738cb9", [:mix], [], "hexpm"}, - "ex_doc": {:hex, :ex_doc, "0.19.3", "3c7b0f02851f5fc13b040e8e925051452e41248f685e40250d7e40b07b9f8c10", [:mix], [{:earmark, "~> 1.2", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.10", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm"}, - "excoveralls": {:hex, :excoveralls, "0.10.5", "7c912c4ec0715a6013647d835c87cde8154855b9b84e256bc7a63858d5f284e3", [:mix], [{:hackney, "~> 1.13", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm"}, + "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"}, + "certifi": {:hex, :certifi, "2.4.2", "75424ff0f3baaccfd34b1214184b6ef616d89e420b258bb0a5ea7d7bc628f7f0", [:rebar3], [{:parse_trans, "~>3.3", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm", "01d479edba0569a7b7a2c8bf923feeb6dc6a358edc2965ef69aea9ba288bb243"}, + "credo": {:hex, :credo, "1.0.2", "88bc918f215168bf6ce7070610a6173c45c82f32baa08bdfc80bf58df2d103b6", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "df2e5ad6f6d40b140fa109b465325ee718d54f23f56a4aa9178796ede2a1ab83"}, + "dialyxir": {:hex, :dialyxir, "0.5.1", "b331b091720fd93e878137add264bac4f644e1ddae07a70bf7062c7862c4b952", [:mix], [], "hexpm", "6c32a70ed5d452c6650916555b1f96c79af5fc4bf286997f8b15f213de786f73"}, + "earmark": {:hex, :earmark, "1.3.6", "ce1d0675e10a5bb46b007549362bd3f5f08908843957687d8484fe7f37466b19", [:mix], [], "hexpm", "1476378df80982302d5a7857b6a11dd0230865057dec6d16544afecc6bc6b4c2"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.13", "0c98163e7d04a15feb62000e1a891489feb29f3d10cb57d4f845c405852bbef8", [:mix], [], "hexpm", "d602c26af3a0af43d2f2645613f65841657ad6efc9f0e361c3b6c06b578214ba"}, + "ex_doc": {:hex, :ex_doc, "0.24.2", "e4c26603830c1a2286dae45f4412a4d1980e1e89dc779fcd0181ed1d5a05c8d9", [:mix], [{:earmark_parser, "~> 1.4.0", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1", [hex: :makeup_erlang, repo: "hexpm", optional: false]}], "hexpm", "e134e1d9e821b8d9e4244687fb2ace58d479b67b282de5158333b0d57c6fb7da"}, + "excoveralls": {:hex, :excoveralls, "0.10.5", "7c912c4ec0715a6013647d835c87cde8154855b9b84e256bc7a63858d5f284e3", [:mix], [{:hackney, "~> 1.13", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "176052589b681f44de12fb85182ccf0296030f619b6939926bc647dabedf9320"}, "exjsx": {:hex, :exjsx, "4.0.0", "60548841e0212df401e38e63c0078ec57b33e7ea49b032c796ccad8cde794b5c", [:mix], [{:jsx, "~> 2.8.0", [hex: :jsx, repo: "hexpm", optional: false]}], "hexpm"}, - "hackney": {:hex, :hackney, "1.15.0", "287a5d2304d516f63e56c469511c42b016423bcb167e61b611f6bad47e3ca60e", [:rebar3], [{:certifi, "2.4.2", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.4", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"}, - "idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"}, - "jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm"}, + "hackney": {:hex, :hackney, "1.15.0", "287a5d2304d516f63e56c469511c42b016423bcb167e61b611f6bad47e3ca60e", [:rebar3], [{:certifi, "2.4.2", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "6.0.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.4", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "b69d97134f1876ba8e4e2f405e9da8cba7cf4f2da0b7cc24a5ccef8dcf1b46b2"}, + "idna": {:hex, :idna, "6.0.0", "689c46cbcdf3524c44d5f3dde8001f364cd7608a99556d8fbd8239a5798d4c10", [:rebar3], [{:unicode_util_compat, "0.4.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "4bdd305eb64e18b0273864920695cb18d7a2021f31a11b9c5fbcd9a253f936e2"}, + "jason": {:hex, :jason, "1.1.2", "b03dedea67a99223a2eaf9f1264ce37154564de899fd3d8b9a21b1a6fd64afe7", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fdf843bca858203ae1de16da2ee206f53416bbda5dc8c9e78f43243de4bc3afe"}, "jsx": {:hex, :jsx, "2.8.3", "a05252d381885240744d955fbe3cf810504eb2567164824e19303ea59eef62cf", [:mix, :rebar3], [], "hexpm"}, - "makeup": {:hex, :makeup, "0.8.0", "9cf32aea71c7fe0a4b2e9246c2c4978f9070257e5c9ce6d4a28ec450a839b55f", [:mix], [{:nimble_parsec, "~> 0.5.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm"}, - "makeup_elixir": {:hex, :makeup_elixir, "0.13.0", "be7a477997dcac2e48a9d695ec730b2d22418292675c75aa2d34ba0909dcdeda", [:mix], [{:makeup, "~> 0.8", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm"}, - "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm"}, - "mime": {:hex, :mime, "1.3.1", "30ce04ab3175b6ad0bdce0035cba77bba68b813d523d1aac73d9781b4d193cf8", [:mix], [], "hexpm"}, - "mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [:rebar3], [], "hexpm"}, - "nimble_parsec": {:hex, :nimble_parsec, "0.5.0", "90e2eca3d0266e5c53f8fbe0079694740b9c91b6747f2b7e3c5d21966bba8300", [:mix], [], "hexpm"}, - "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm"}, - "plug": {:hex, :plug, "1.7.2", "d7b7db7fbd755e8283b6c0a50be71ec0a3d67d9213d74422d9372effc8e87fd1", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}], "hexpm"}, - "plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm"}, - "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm"}, - "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.4", "f0eafff810d2041e93f915ef59899c923f4568f4585904d010387ed74988e77b", [:make, :mix, :rebar3], [], "hexpm"}, - "unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm"}, + "makeup": {:hex, :makeup, "1.0.5", "d5a830bc42c9800ce07dd97fa94669dfb93d3bf5fcf6ea7a0c67b2e0e4a7f26c", [:mix], [{:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cfa158c02d3f5c0c665d0af11512fed3fba0144cf1aadee0f2ce17747fba2ca9"}, + "makeup_elixir": {:hex, :makeup_elixir, "0.15.1", "b5888c880d17d1cc3e598f05cdb5b5a91b7b17ac4eaf5f297cb697663a1094dd", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.1", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "db68c173234b07ab2a07f645a5acdc117b9f99d69ebf521821d89690ae6c6ec8"}, + "makeup_erlang": {:hex, :makeup_erlang, "0.1.1", "3fcb7f09eb9d98dc4d208f49cc955a34218fc41ff6b84df7c75b3e6e533cc65f", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "174d0809e98a4ef0b3309256cbf97101c6ec01c4ab0b23e926a9e17df2077cbb"}, + "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, + "mime": {:hex, :mime, "1.3.1", "30ce04ab3175b6ad0bdce0035cba77bba68b813d523d1aac73d9781b4d193cf8", [:mix], [], "hexpm", "6cbe761d6a0ca5a31a0931bf4c63204bceb64538e664a8ecf784a9a6f3b875f1"}, + "mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [:rebar3], [], "hexpm", "7a4c8e1115a2732a67d7624e28cf6c9f30c66711a9e92928e745c255887ba465"}, + "nimble_parsec": {:hex, :nimble_parsec, "1.1.0", "3a6fca1550363552e54c216debb6a9e95bd8d32348938e13de5eda962c0d7f89", [:mix], [], "hexpm", "08eb32d66b706e913ff748f11694b17981c0b04a33ef470e33e11b3d3ac8f54b"}, + "parse_trans": {:hex, :parse_trans, "3.3.0", "09765507a3c7590a784615cfd421d101aec25098d50b89d7aa1d66646bc571c1", [:rebar3], [], "hexpm", "17ef63abde837ad30680ea7f857dd9e7ced9476cdd7b0394432af4bfc241b960"}, + "plug": {:hex, :plug, "1.7.2", "d7b7db7fbd755e8283b6c0a50be71ec0a3d67d9213d74422d9372effc8e87fd1", [:mix], [{:mime, "~> 1.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}], "hexpm", "de9825f21c6fd6adfdeae8f9c80dcd88c1e58301f06bf13d659b7e606b88abe0"}, + "plug_crypto": {:hex, :plug_crypto, "1.0.0", "18e49317d3fa343f24620ed22795ec29d4a5e602d52d1513ccea0b07d8ea7d4d", [:mix], [], "hexpm", "73c1682f0e414cfb5d9b95c8e8cd6ffcfdae699e3b05e1db744e58b7be857759"}, + "poison": {:hex, :poison, "3.1.0", "d9eb636610e096f86f25d9a46f35a9facac35609a7591b3be3326e99a0484665", [:mix], [], "hexpm", "fec8660eb7733ee4117b85f55799fd3833eb769a6df71ccf8903e8dc5447cfce"}, + "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.4", "f0eafff810d2041e93f915ef59899c923f4568f4585904d010387ed74988e77b", [:make, :mix, :rebar3], [], "hexpm", "603561dc0fd62f4f2ea9b890f4e20e1a0d388746d6e20557cafb1b16950de88c"}, + "unicode_util_compat": {:hex, :unicode_util_compat, "0.4.1", "d869e4c68901dd9531385bb0c8c40444ebf624e60b6962d95952775cac5e90cd", [:rebar3], [], "hexpm", "1d1848c40487cdb0b30e8ed975e34e025860c02e419cb615d255849f3427439d"}, }