Skip to content

Commit

Permalink
Merge 6a12c97 into 7ecc5eb
Browse files Browse the repository at this point in the history
  • Loading branch information
mjaric committed Dec 19, 2018
2 parents 7ecc5eb + 6a12c97 commit 54ab8b6
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 37 deletions.
2 changes: 2 additions & 0 deletions config/config.exs
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ use Mix.Config
config :logger,
level: :info,
compile_time_purge_level: :debug

config :json, log_level: :info
17 changes: 9 additions & 8 deletions lib/json.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ defmodule JSON do
"""

require Logger
import Json.Logger

alias JSON.Encoder, as: Encoder
alias JSON.Decoder, as: Decoder
Expand Down Expand Up @@ -55,16 +56,16 @@ defmodule JSON do
Decoder.decode() |>
case do
res = {:ok, _} ->
Logger.debug("#{__MODULE__}.decode(#{inspect bitstring_or_char_list}} was sucesfull: #{inspect res}")
log(:debug, "#{__MODULE__}.decode(#{inspect bitstring_or_char_list}} was sucesfull: #{inspect res}")
res
e = {:error, {:unexpected_token, tok}} ->
Logger.debug("#{__MODULE__}.decode!(#{inspect bitstring_or_char_list}} unexpected token #{tok}")
log(:debug, "#{__MODULE__}.decode!(#{inspect bitstring_or_char_list}} unexpected token #{tok}")
e
e = {:error, :unexpected_end_of_buffer} ->
Logger.debug("#{__MODULE__}.decode!(#{inspect bitstring_or_char_list}} end of buffer")
log(:debug, "#{__MODULE__}.decode!(#{inspect bitstring_or_char_list}} end of buffer")
e
e ->
Logger.debug("#{__MODULE__}.decode!(#{inspect bitstring_or_char_list}} an unknown problem occurred #{inspect e}")
log(:debug, "#{__MODULE__}.decode!(#{inspect bitstring_or_char_list}} an unknown problem occurred #{inspect e}")
end
end

Expand All @@ -81,16 +82,16 @@ defmodule JSON do
def decode!(bitstring_or_char_list) do
case Decoder.decode(bitstring_or_char_list) do
{:ok, value} ->
Logger.debug("#{__MODULE__}.decode!(#{inspect bitstring_or_char_list}} was sucesfull: #{inspect value}")
log(:debug, "#{__MODULE__}.decode!(#{inspect bitstring_or_char_list}} was sucesfull: #{inspect value}")
value
{:error, {:unexpected_token, tok}} ->
Logger.debug("#{__MODULE__}.decode!(#{inspect bitstring_or_char_list}} unexpected token #{tok}")
log(:debug, "#{__MODULE__}.decode!(#{inspect bitstring_or_char_list}} unexpected token #{tok}")
raise JSON.Decoder.UnexpectedTokenError, token: tok
{:error, :unexpected_end_of_buffer} ->
Logger.debug("#{__MODULE__}.decode!(#{inspect bitstring_or_char_list}} end of buffer")
log(:debug, "#{__MODULE__}.decode!(#{inspect bitstring_or_char_list}} end of buffer")
raise JSON.Decoder.UnexpectedEndOfBufferError
e ->
Logger.debug("#{__MODULE__}.decode!(#{inspect bitstring_or_char_list}} an unknown problem occurred #{inspect e}")
log(:debug, "#{__MODULE__}.decode!(#{inspect bitstring_or_char_list}} an unknown problem occurred #{inspect e}")
end
end
end
19 changes: 10 additions & 9 deletions lib/json/decoder.ex
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ end

defmodule JSON.Decoder.DefaultImplementations do
require Logger
import Json.Logger

defimpl JSON.Decoder, for: BitString do
@moduledoc """
Expand All @@ -36,23 +37,23 @@ defmodule JSON.Decoder.DefaultImplementations do
"""
def decode(bitstring) do
Logger.debug("#{__MODULE__}.decode(#{inspect bitstring}) starting...")
log(:debug, "#{__MODULE__}.decode(#{inspect bitstring}) starting...")
bitstring
|> String.trim()
|> Parser.parse()
|> case do
{:error, error_info} ->
Logger.debug("#{__MODULE__}.decode(#{inspect bitstring}} failed with errror: #{inspect error_info}")
log(:debug, "#{__MODULE__}.decode(#{inspect bitstring}} failed with errror: #{inspect error_info}")
{:error, error_info}
{:ok, value, rest} ->
Logger.debug("#{__MODULE__}.decode(#{inspect bitstring}) trimming remainder of JSON payload #{inspect rest}...")
log(:debug, "#{__MODULE__}.decode(#{inspect bitstring}) trimming remainder of JSON payload #{inspect rest}...")
case rest |> String.trim() do
<<>> ->
Logger.debug("#{__MODULE__}.decode(#{inspect bitstring}) successfully trimmed remainder JSON payload!")
Logger.debug("#{__MODULE__}.decode(#{inspect bitstring}) returning {:ok. #{inspect value}}")
log(:debug, "#{__MODULE__}.decode(#{inspect bitstring}) successfully trimmed remainder JSON payload!")
log(:debug, "#{__MODULE__}.decode(#{inspect bitstring}) returning {:ok. #{inspect value}}")
{:ok, value}
rest ->
Logger.debug("#{__MODULE__}.decode(#{inspect bitstring}} failed consume entire buffer: #{rest}")
log(:debug, "#{__MODULE__}.decode(#{inspect bitstring}} failed consume entire buffer: #{rest}")
{:error, {:unexpected_token, rest}}
end
end
Expand Down Expand Up @@ -88,13 +89,13 @@ defmodule JSON.Decoder.DefaultImplementations do
case do
{:ok, value} -> {:ok, value}
{:error, error_info} when is_binary(error_info) ->
Logger.debug("#{__MODULE__}.decode(#{inspect charlist}} failed with errror: #{inspect error_info}")
log(:debug, "#{__MODULE__}.decode(#{inspect charlist}} failed with errror: #{inspect error_info}")
{:error, error_info |> to_charlist()}
{:error, {:unexpected_token, bin}} when is_binary(bin) ->
Logger.debug("#{__MODULE__}.decode(#{inspect charlist}} failed with errror: #{inspect bin}")
log(:debug, "#{__MODULE__}.decode(#{inspect charlist}} failed with errror: #{inspect bin}")
{:error, {:unexpected_token, bin |> to_charlist()}}
e = {:error, error_info} ->
Logger.debug("#{__MODULE__}.decode(#{inspect charlist}} failed with errror: #{inspect e}")
log(:debug, "#{__MODULE__}.decode(#{inspect charlist}} failed with errror: #{inspect e}")
{:error, error_info}
end
end
Expand Down
49 changes: 49 additions & 0 deletions lib/json/logger.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
defmodule Json.Logger do
@moduledoc """
Exposes separate log level configuration so developers can set logging
verbosity for json library
To configure log level only for json library, add folowing line in config file
use Mix.Config
# to make json be very verbose
config :json, log_level: :debug
# to make json be silent
config :json, log_level: :error
"""
require Logger
@levels [:debug, :info, :warn, :error]
@level Application.get_env(:json, :log_level, :info)

@allowed_levels @levels
|> Enum.reverse()
|> Enum.reduce_while([], fn l, acc ->
if l == @level do
{:halt, [@level | acc]}
else
{:cont, [l | acc]}
end
end)
|> Enum.reverse()

@doc false
@spec allowed_levels() :: [:debug | :error | :info | :warn, ...]
def allowed_levels(), do: @allowed_levels

@doc """
Logs given message to logger at given log level
Supported log levels are:
- `:debug` - All messages are logged
- `:info` - only :info, :warn and :error messages are logged
- `:warn` - only :warn and :error messages are logged
- `:error` - only :error messages are logged
"""
defmacro log(level, message) do
quote bind_quoted: [level: level, message: message] do
if level in Json.Logger.allowed_levels() do
Logger.log(level, message)
end
end
end
end
21 changes: 11 additions & 10 deletions lib/json/parser.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ defmodule JSON.Parser do
alias Parser.String, as: StringParser

require Logger
import Json.Logger

@doc """
parses a valid JSON value, returns its elixir representation
Expand Down Expand Up @@ -69,44 +70,44 @@ defmodule JSON.Parser do
"""

def parse(<<?[, _::binary>> = bin) do
Logger.debug("#{__MODULE__}.parse(bin) starting ArrayParser.parse(bin)...")
log(:debug, "#{__MODULE__}.parse(bin) starting ArrayParser.parse(bin)...")
ArrayParser.parse(bin)
end
def parse(<<?{, _::binary>> = bin) do
Logger.debug("#{__MODULE__}.parse(bin) starting ObjectParser.parse(bin)...")
log(:debug, "#{__MODULE__}.parse(bin) starting ObjectParser.parse(bin)...")
ObjectParser.parse(bin)
end
def parse(<<?", _::binary>> = bin) do
Logger.debug("#{__MODULE__}.parse(bin) starting ArrayParser.parse(bin)...")
log(:debug, "#{__MODULE__}.parse(bin) starting ArrayParser.parse(bin)...")
StringParser.parse(bin)
end

def parse(<<?-, number::utf8, _::binary>> = bin) when number in ?0..?9 do
Logger.debug("#{__MODULE__}.parse(bin) starting negative NumberParser.parse(bin)...")
log(:debug, "#{__MODULE__}.parse(bin) starting negative NumberParser.parse(bin)...")
NumberParser.parse(bin)
end
def parse(<<number::utf8, _::binary>> = bin) when number in ?0..?9 do
Logger.debug("#{__MODULE__}.parse(bin) starting NumberParser.parse(bin)...")
log(:debug, "#{__MODULE__}.parse(bin) starting NumberParser.parse(bin)...")
NumberParser.parse(bin)
end
def parse(<<?n, ?u, ?l, ?l, rest::binary>>) do
Logger.debug("#{__MODULE__}.parse(bin) parsed `null` token.")
log(:debug, "#{__MODULE__}.parse(bin) parsed `null` token.")
{:ok, nil, rest}
end
def parse(<<?t, ?r, ?u, ?e, rest::binary>>) do
Logger.debug("#{__MODULE__}.parse(bin) parsed `true` token.")
log(:debug, "#{__MODULE__}.parse(bin) parsed `true` token.")
{:ok, true, rest}
end
def parse(<<?f, ?a, ?l, ?s, ?e, rest::binary>>) do
Logger.debug("#{__MODULE__}.parse(bin) parsed `false` token.")
log(:debug, "#{__MODULE__}.parse(bin) parsed `false` token.")
{:ok, false, rest}
end
def parse(<<>>) do
Logger.debug("#{__MODULE__}.parse(<<>>) unexpected end of buffer.")
log(:debug, "#{__MODULE__}.parse(<<>>) unexpected end of buffer.")
{:error, :unexpected_end_of_buffer}
end
def parse(json) do
Logger.debug("#{__MODULE__}.parse(json) unexpected token: #{inspect json}")
log(:debug, "#{__MODULE__}.parse(json) unexpected token: #{inspect json}")
{:error, {:unexpected_token, json}}
end
end
21 changes: 11 additions & 10 deletions lib/json/parser/array.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ defmodule JSON.Parser.Array do
alias JSON.Parser, as: Parser

require Logger
import Json.Logger

@doc """
parses a valid JSON array value, returns its elixir list representation
Expand All @@ -31,53 +32,53 @@ defmodule JSON.Parser.Array do
{:ok, ["foo", 1, 2, 1.5], " lala"}
"""
def parse(<<?[, rest::binary>>) do
Logger.debug("#{__MODULE__}.parse(#{inspect rest}) trimming string and the calling parse_array_contents()")
log(:debug, "#{__MODULE__}.parse(#{inspect rest}) trimming string and the calling parse_array_contents()")
rest |> String.trim() |> parse_array_contents()
end

def parse(<<>>) do
Logger.debug("#{__MODULE__}.parse(<<>>) unexpected end of buffer.")
log(:debug, "#{__MODULE__}.parse(<<>>) unexpected end of buffer.")
{:error, :unexpected_end_of_buffer}
end
def parse(json) do
Logger.debug("#{__MODULE__}.parse(<<>>) unexpected token: #{inspect json}")
log(:debug, "#{__MODULE__}.parse(<<>>) unexpected token: #{inspect json}")
{:error, {:unexpected_token, json}}
end

# begin parse array
defp parse_array_contents(json) when is_binary(json) do
Logger.debug("#{__MODULE__}.parse_array_contents(#{inspect json}) beginning to parse array contents...")
log(:debug, "#{__MODULE__}.parse_array_contents(#{inspect json}) beginning to parse array contents...")
parse_array_contents([], json)
end

# stop condition
defp parse_array_contents(acc, <<?], rest::binary>>) do
Logger.debug("#{__MODULE__}.parse_array_contents(#{inspect acc}, #{inspect rest}) finished parsing array contents.")
log(:debug, "#{__MODULE__}.parse_array_contents(#{inspect acc}, #{inspect rest}) finished parsing array contents.")
{:ok, Enum.reverse(acc), rest}
end

# error condition
defp parse_array_contents(_, <<>>) do
Logger.debug("#{__MODULE__}.parse_array_contents(acc, <<>>) unexpected end of buffer.")
log(:debug, "#{__MODULE__}.parse_array_contents(acc, <<>>) unexpected end of buffer.")
{:error, :unexpected_end_of_buffer}
end

defp parse_array_contents(acc, json) do
json |> String.trim() |> Parser.parse() |> case do
{:error, error_info} ->
Logger.debug("#{__MODULE__}.parse_array_contents(#{inspect acc}, #{inspect json}) generated an error: #{inspect error_info}")
log(:debug, "#{__MODULE__}.parse_array_contents(#{inspect acc}, #{inspect json}) generated an error: #{inspect error_info}")
{:error, error_info}
{:ok, value, after_value} ->
Logger.debug("#{__MODULE__}.parse_array_contents(acc, json) sucessfully parsed value `#{inspect value}`, with
log(:debug, "#{__MODULE__}.parse_array_contents(acc, json) sucessfully parsed value `#{inspect value}`, with
after_value=#{inspect after_value}")
after_value |> String.trim() |>
case do
<<?,, after_comma::binary>> ->
trimmed = String.trim(after_comma)
Logger.debug("#{__MODULE__}.parse_array_contents(acc, json) found a comma, continuing parsing of #{inspect trimmed}")
log(:debug, "#{__MODULE__}.parse_array_contents(acc, json) found a comma, continuing parsing of #{inspect trimmed}")
parse_array_contents([value | acc], trimmed)
rest ->
Logger.debug("#{__MODULE__}.parse_array_contents(acc, json) continuing parsing of #{inspect rest}")
log(:debug, "#{__MODULE__}.parse_array_contents(acc, json) continuing parsing of #{inspect rest}")
parse_array_contents([value | acc], rest)
end
end
Expand Down

0 comments on commit 54ab8b6

Please sign in to comment.