diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 Kadzuya Okamoto https://arow.info
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,3 @@
+# tonatona-logger
+
+A plugin for `tonatona` that adds features to for logging.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/src/Tonatona/Logger.hs b/src/Tonatona/Logger.hs
new file mode 100644
--- /dev/null
+++ b/src/Tonatona/Logger.hs
@@ -0,0 +1,251 @@
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+{-# LANGUAGE UndecidableInstances #-}
+
+module Tonatona.Logger
+  ( Config(..)
+  , DeployMode(..)
+  , Verbose(..)
+  , defaultVerbosity
+    -- * Standard logging functions
+  , Tonatona.Logger.logDebug
+  , Tonatona.Logger.logInfo
+  , Tonatona.Logger.logWarn
+  , Tonatona.Logger.logError
+  , Tonatona.Logger.logOther
+    -- * Advanced logging functions
+    -- ** Sticky logging
+  , Tonatona.Logger.logSticky
+  , Tonatona.Logger.logStickyDone
+    -- ** With source
+  , Tonatona.Logger.logDebugS
+  , Tonatona.Logger.logInfoS
+  , Tonatona.Logger.logWarnS
+  , Tonatona.Logger.logErrorS
+  , Tonatona.Logger.logOtherS
+    -- ** Generic log function
+  , Tonatona.Logger.logGeneric
+    -- * Data types
+  , LogLevel (..)
+  , LogSource
+  ) where
+
+import RIO
+
+import GHC.Generics (Generic)
+import Tonatona (HasConfig(..), HasParser(..))
+import TonaParser
+  ( Var(..)
+  , (.||)
+  , argLong
+  , envVar
+  , liftWith
+  , optionalEnum
+  )
+
+
+-- Standard logging functions
+
+
+{- | Log a debug level message with no source.
+-}
+logDebug :: (HasConfig env Config) => Utf8Builder -> RIO env ()
+logDebug = unwrap . RIO.logDebug
+
+{- | Log an info level message with no source.
+-}
+logInfo :: (HasConfig env Config) => Utf8Builder -> RIO env ()
+logInfo = unwrap . RIO.logInfo
+
+{- | Log a warn level message with no source.
+-}
+logWarn :: (HasConfig env Config) => Utf8Builder -> RIO env ()
+logWarn = unwrap . RIO.logWarn
+
+{- | Log an error level message with no source.
+-}
+logError :: (HasConfig env Config) => Utf8Builder -> RIO env ()
+logError = unwrap . RIO.logError
+
+{- | Log a message with the specified textual level and no source.
+-}
+logOther :: (HasConfig env Config)
+  => Text -- ^ level
+  -> Utf8Builder -> RIO env ()
+logOther level = unwrap . RIO.logOther level
+
+
+
+-- With source
+
+
+{- | Log a debug level message with the given source.
+-}
+logDebugS
+  :: (HasConfig env Config)
+  => LogSource
+  -> Utf8Builder
+  -> RIO env ()
+logDebugS src = unwrap . RIO.logDebugS src
+
+{- | Log an info level message with the given source.
+-}
+logInfoS
+  :: (HasConfig env Config)
+  => LogSource
+  -> Utf8Builder
+  -> RIO env ()
+logInfoS src = unwrap . RIO.logInfoS src
+
+{- | Log a warn level message with the given source.
+-}
+logWarnS
+  :: (HasConfig env Config)
+  => LogSource
+  -> Utf8Builder
+  -> RIO env ()
+logWarnS src = unwrap . RIO.logWarnS src
+
+{- | Log an error level message with the given source.
+-}
+logErrorS
+  :: (HasConfig env Config)
+  => LogSource
+  -> Utf8Builder
+  -> RIO env ()
+logErrorS src = unwrap . RIO.logErrorS src
+
+{- | Log a message with the specified textual level and the given source.
+-}
+logOtherS
+  :: (HasConfig env Config)
+  => Text -- ^ level
+  -> LogSource
+  -> Utf8Builder
+  -> RIO env ()
+logOtherS level src = unwrap . RIO.logOtherS level src
+
+{- | Write a "sticky" line to the terminal. Any subsequent lines will
+  overwrite this one, and that same line will be repeated below
+  again. In other words, the line sticks at the bottom of the output
+  forever. Running this function again will replace the sticky line
+  with a new sticky line. When you want to get rid of the sticky
+  line, run 'logStickyDone'.
+
+  Note that not all 'LogFunc' implementations will support sticky
+  messages as described. However, the 'withLogFunc' implementation
+  provided by this module does.
+-}
+logSticky :: (HasConfig env Config) => Utf8Builder -> RIO env ()
+logSticky = unwrap . RIO.logSticky
+
+{- | This will print out the given message with a newline and disable
+  any further stickiness of the line until a new call to 'logSticky'
+  happens.
+-}
+logStickyDone :: (HasConfig env Config) => Utf8Builder -> RIO env ()
+logStickyDone = unwrap . RIO.logStickyDone
+
+
+
+-- Generic log function
+
+
+{- | Generic, basic function for creating other logging functions.
+-}
+logGeneric ::
+     (HasConfig env Config)
+  => LogSource
+  -> LogLevel
+  -> Utf8Builder
+  -> RIO env ()
+logGeneric src level str = unwrap $ RIO.logGeneric src level str
+
+
+unwrap :: RIO (InnerEnv env) () -> RIO env ()
+unwrap action = do
+  env <- ask
+  runRIO (InnerEnv env) action
+
+
+newtype InnerEnv env = InnerEnv { unInnerEnv :: env }
+
+
+instance (HasConfig env Config) => HasLogFunc (InnerEnv env) where
+  logFuncL = lens (logFunc . config . unInnerEnv) $
+    error "Setter for logFuncL is not defined"
+
+
+-- Config
+
+
+data Config = Config
+  { mode :: DeployMode
+  , verbose :: Verbose
+  , logOptions :: LogOptions
+  , logFunc :: LogFunc
+  }
+
+
+instance HasParser Config where
+  parser = do
+    mode <- parser
+    verbose <- parser
+    liftWith $ \action -> do
+      options <- defaultLogOptions mode verbose
+      withLogFunc options $ \lf ->
+        action $ Config mode verbose options lf
+
+
+-- Verbose
+
+
+newtype Verbose = Verbose { unVerbose :: Bool }
+  deriving (Show, Read, Eq)
+
+instance HasParser Verbose where
+  parser = Verbose <$>
+    optionalEnum
+      "Make the operation more talkative"
+      (argLong "verbose" .|| envVar "VERBOSE")
+      False
+
+
+-- DeployMode
+
+
+data DeployMode
+  = Development
+  | Production
+  | Staging
+  | Test
+  deriving (Eq, Generic, Show, Read, Bounded, Enum)
+
+instance Var DeployMode where
+  toVar = show
+  fromVar = readMaybe
+
+instance HasParser DeployMode where
+  parser =
+    optionalEnum
+      "Application deployment mode to run"
+      (argLong "env" .|| envVar "ENV")
+      Development
+
+
+-- Logger options
+
+
+{-| Default way to create 'LogOptions'.
+-}
+defaultLogOptions :: (MonadIO m) => DeployMode -> Verbose -> m LogOptions
+defaultLogOptions env verbose = do
+  logOptionsHandle stderr $ defaultVerbosity env verbose
+
+
+{-| Default setting for verbosity.
+-}
+defaultVerbosity :: DeployMode -> Verbose -> Bool
+defaultVerbosity env (Verbose v) =
+  case (v, env) of
+    (False, Development) -> True
+    _ -> v
diff --git a/test/DocTest.hs b/test/DocTest.hs
new file mode 100644
--- /dev/null
+++ b/test/DocTest.hs
@@ -0,0 +1,58 @@
+module Main (main) where
+
+import RIO
+
+import System.FilePath.Glob (glob)
+import Test.DocTest (doctest)
+
+main :: IO ()
+main = glob "src/**/*.hs" >>= doDocTest
+
+doDocTest :: [String] -> IO ()
+doDocTest options =
+  doctest $
+    options <>
+    ghcExtensions
+
+ghcExtensions :: [String]
+ghcExtensions =
+    [ "-XAutoDeriveTypeable"
+    , "-XBangPatterns"
+    , "-XBinaryLiterals"
+    , "-XConstraintKinds"
+    , "-XDataKinds"
+    , "-XDefaultSignatures"
+    , "-XDeriveDataTypeable"
+    , "-XDeriveFoldable"
+    , "-XDeriveFunctor"
+    , "-XDeriveGeneric"
+    , "-XDeriveTraversable"
+    , "-XDoAndIfThenElse"
+    , "-XEmptyDataDecls"
+    , "-XExistentialQuantification"
+    , "-XFlexibleContexts"
+    , "-XFlexibleInstances"
+    , "-XFunctionalDependencies"
+    , "-XGADTs"
+    , "-XGeneralizedNewtypeDeriving"
+    , "-XInstanceSigs"
+    , "-XKindSignatures"
+    , "-XLambdaCase"
+    , "-XMonadFailDesugaring"
+    , "-XMultiParamTypeClasses"
+    , "-XMultiWayIf"
+    , "-XNamedFieldPuns"
+    , "-XNoImplicitPrelude"
+    , "-XOverloadedStrings"
+    , "-XPartialTypeSignatures"
+    , "-XPatternGuards"
+    , "-XPolyKinds"
+    , "-XRankNTypes"
+    , "-XRecordWildCards"
+    , "-XScopedTypeVariables"
+    , "-XStandaloneDeriving"
+    , "-XTupleSections"
+    , "-XTypeFamilies"
+    , "-XTypeSynonymInstances"
+    , "-XViewPatterns"
+    ]
diff --git a/test/Spec.hs b/test/Spec.hs
new file mode 100644
--- /dev/null
+++ b/test/Spec.hs
@@ -0,0 +1,8 @@
+{-# LANGUAGE QuasiQuotes #-}
+
+module Main where
+
+import RIO
+
+main :: IO ()
+main = pure ()
diff --git a/tonatona-logger.cabal b/tonatona-logger.cabal
new file mode 100644
--- /dev/null
+++ b/tonatona-logger.cabal
@@ -0,0 +1,72 @@
+-- This file has been generated from package.yaml by hpack version 0.28.2.
+--
+-- see: https://github.com/sol/hpack
+--
+-- hash: b5ab94f733fcf6e5c39b81169aa57ae5aa85c4823292a8c1b603167dbd2f94ae
+
+name:           tonatona-logger
+version:        0.2.0.0
+synopsis:       tonatona plugin for logging.
+description:    Tonatona plugin for logging. This package provides a tonatona plugin for logging.
+category:       System, Library, Tonatona
+homepage:       https://github.com/tonatona-project/tonatona#readme
+bug-reports:    https://github.com/tonatona-project/tonatona/issues
+author:         Kadzuya Okamoto, Dennis Gosnell
+maintainer:     arow.okamoto+github@gmail.com
+copyright:      2018 Kadzuya Okamoto
+license:        MIT
+license-file:   LICENSE
+build-type:     Simple
+cabal-version:  >= 1.10
+extra-source-files:
+    README.md
+
+source-repository head
+  type: git
+  location: https://github.com/tonatona-project/tonatona
+
+library
+  exposed-modules:
+      Tonatona.Logger
+  other-modules:
+      Paths_tonatona_logger
+  hs-source-dirs:
+      src
+  default-extensions: AutoDeriveTypeable BangPatterns BinaryLiterals ConstraintKinds DataKinds DefaultSignatures DeriveDataTypeable DeriveFoldable DeriveFunctor DeriveGeneric DeriveTraversable DoAndIfThenElse EmptyDataDecls ExistentialQuantification FlexibleContexts FlexibleInstances FunctionalDependencies GADTs GeneralizedNewtypeDeriving InstanceSigs KindSignatures LambdaCase MonadFailDesugaring MultiParamTypeClasses MultiWayIf NamedFieldPuns NoImplicitPrelude OverloadedStrings PartialTypeSignatures PatternGuards PolyKinds RankNTypes RecordWildCards ScopedTypeVariables StandaloneDeriving TupleSections TypeFamilies TypeSynonymInstances ViewPatterns
+  ghc-options: -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints
+  build-depends:
+      base >=4.7 && <5
+    , rio >=0.1
+    , tonaparser >=0.1
+    , tonatona >=0.1
+  default-language: Haskell2010
+
+test-suite doctest
+  type: exitcode-stdio-1.0
+  main-is: DocTest.hs
+  hs-source-dirs:
+      test
+  default-extensions: AutoDeriveTypeable BangPatterns BinaryLiterals ConstraintKinds DataKinds DefaultSignatures DeriveDataTypeable DeriveFoldable DeriveFunctor DeriveGeneric DeriveTraversable DoAndIfThenElse EmptyDataDecls ExistentialQuantification FlexibleContexts FlexibleInstances FunctionalDependencies GADTs GeneralizedNewtypeDeriving InstanceSigs KindSignatures LambdaCase MonadFailDesugaring MultiParamTypeClasses MultiWayIf NamedFieldPuns NoImplicitPrelude OverloadedStrings PartialTypeSignatures PatternGuards PolyKinds RankNTypes RecordWildCards ScopedTypeVariables StandaloneDeriving TupleSections TypeFamilies TypeSynonymInstances ViewPatterns
+  ghc-options: -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints
+  build-depends:
+      Glob
+    , base >=4.7 && <5
+    , doctest
+    , rio >=0.1
+    , tonaparser >=0.1
+    , tonatona >=0.1
+  default-language: Haskell2010
+
+test-suite spec
+  type: exitcode-stdio-1.0
+  main-is: Spec.hs
+  hs-source-dirs:
+      test
+  default-extensions: AutoDeriveTypeable BangPatterns BinaryLiterals ConstraintKinds DataKinds DefaultSignatures DeriveDataTypeable DeriveFoldable DeriveFunctor DeriveGeneric DeriveTraversable DoAndIfThenElse EmptyDataDecls ExistentialQuantification FlexibleContexts FlexibleInstances FunctionalDependencies GADTs GeneralizedNewtypeDeriving InstanceSigs KindSignatures LambdaCase MonadFailDesugaring MultiParamTypeClasses MultiWayIf NamedFieldPuns NoImplicitPrelude OverloadedStrings PartialTypeSignatures PatternGuards PolyKinds RankNTypes RecordWildCards ScopedTypeVariables StandaloneDeriving TupleSections TypeFamilies TypeSynonymInstances ViewPatterns
+  ghc-options: -Wcompat -Wincomplete-record-updates -Wincomplete-uni-patterns -Wredundant-constraints
+  build-depends:
+      base >=4.7 && <5
+    , rio >=0.1
+    , tonaparser >=0.1
+    , tonatona
+  default-language: Haskell2010
