{-| This module provides a convenient way to decode a 'Manager' from json string

There is a 'Config' type in "Logging.Config.Type" module, it is an instance
of 'FromJSON', 1) decode 'Config' from json string, 2) construct an 'Manager'
from 'Config'.


All 'Maybe' fileds can be omitted, the default value will be used, e.g.

1) 'List' type field will use '[]' as default

2) 'Purelude.Bool' type filed will use False as default

3) if the field is an instance of 'Data.Default.Default', use 'def'

4) an appropriate value as default for other fields


In fact, you can decode 'Config' from an empty json (object) string,

@
  manager <- getManager "{}" -- enable the 'OverloadedStrings' extension
@

it will create a manager with a root sink (i.e. 'Logging.defaultRoot'),
the 'Logging.defaultRoot' will be used when the root sink is omitted.

Here is a json string template:

@
  {
    \"sinks\":
    {
      \"root\":
      {
        \"handlers\": [\"console\", \"file\"]
      },
      \"App.Json\":
      {
        \"handlers\": [\"file\"],
        \"propagate\": false
      },
      \"App.Yaml\":
      {
        \"handlers\": [\"rotate\"],
        \"propagate\": false
      }
    },
    \"handlers\":
    {
      \"console\":
      {
        \"type\": \"StreamHandler\",
        \"level\": \"DEBUG\",
        \"formatter\": \"simple\",
        \"stream\": \"stderr\"
      },
      \"file\":
      {
        \"type\": \"FileHandler\",
        \"level\": \"Level 100\",
        \"filterer\": [\"App.Json\"],
        \"formatter\": \"standard\",
        \"file\": \"/etc\/my\/json.log\",
        \"encoding\": \"utf8\"
      },
      \"rotate\":
      {
        \"type\": \"RotatingFileHandler\",
        \"level\": \"INFO\",
        \"filterer\": [\"App.Yaml\"],
        \"formatter\": \"standard\",
        \"file\": \"/etc\/my\/yaml.log\",
        \"encoding\": \"utf8\",
        \"maxBytes\": 1048576,
        \"backupCount\": 10
      }
    },
    \"formatters\":
    {
      \"simple\": \"{message}\",
      \"standard\": \"{asctime:%Y-%m-%dT%H:%M:%S%6Q%z} - {level} - {logger}] {message}\"
    },
    \"disabled\": false,
    \"catchUncaughtException\": true
  }
@

-}

module Logging.Config.Json (getManager, getManagerFile) where


import           Control.Exception
import           Data.Aeson
import           Data.ByteString
import           Prelude             hiding (readFile)

import           Logging.Config.Type
import           Logging.Types       (Manager)


-- | decode a 'Manager' from strict 'ByteString'
--
-- @since 0.4.0
getManager :: ByteString -> IO Manager
getManager bs =
  case eitherDecodeStrict bs of
    Left msg     -> throw $ ConfigException msg
    Right config -> createManager config


-- | decode a 'Manager' from a file
--
-- @since 0.4.0
getManagerFile :: FilePath -> IO Manager
getManagerFile path = getManager =<< catch (readFile path) reThrow
  where
    reThrow :: SomeException -> IO a
    reThrow e = throw $ ConfigException $ displayException e