diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Alexander Thiemann (c) 2016
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Alexander Thiemann nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
new file mode 100644
--- /dev/null
+++ b/README.md
@@ -0,0 +1,17 @@
+# Control.Logger.Simple
+
+A small and fast opinionated logging framework. Needs GHC >=7.10
+
+## Example
+
+```haskell
+{-# LANGUAGE OverloadedStrings #-}
+module Main where
+
+import Control.Logger.Simple
+
+main :: IO ()
+main =
+    withGlobalLogging (LogConfig (Just "logfile.txt") True) $
+    do logInfo "Hi!"
+```
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/package.yaml b/package.yaml
new file mode 100644
--- /dev/null
+++ b/package.yaml
@@ -0,0 +1,23 @@
+name: simple-logger
+version: 0.0.1
+synopsis: A very simple but efficient logging framework
+maintainer: Alexander Thiemann <mail@athiemann.net>
+license: MIT
+github: agrafix/simple-logger
+extra-source-files:
+  - README.md
+  - package.yaml
+
+ghc-options: -Wall
+
+dependencies:
+  - base >= 4.8 && < 5
+
+library:
+  source-dirs: src
+  dependencies:
+    - fast-logger
+    - text
+    - mtl
+  exposed-modules:
+    - Control.Logger.Simple
diff --git a/simple-logger.cabal b/simple-logger.cabal
new file mode 100644
--- /dev/null
+++ b/simple-logger.cabal
@@ -0,0 +1,37 @@
+-- This file has been generated from package.yaml by hpack version 0.14.0.
+--
+-- see: https://github.com/sol/hpack
+
+name:           simple-logger
+version:        0.0.1
+synopsis:       A very simple but efficient logging framework
+homepage:       https://github.com/agrafix/simple-logger#readme
+bug-reports:    https://github.com/agrafix/simple-logger/issues
+maintainer:     Alexander Thiemann <mail@athiemann.net>
+license:        MIT
+license-file:   LICENSE
+build-type:     Simple
+cabal-version:  >= 1.10
+
+extra-source-files:
+    package.yaml
+    README.md
+
+source-repository head
+  type: git
+  location: https://github.com/agrafix/simple-logger
+
+library
+  hs-source-dirs:
+      src
+  ghc-options: -Wall
+  build-depends:
+      base >= 4.8 && < 5
+    , fast-logger
+    , text
+    , mtl
+  exposed-modules:
+      Control.Logger.Simple
+  other-modules:
+      Paths_simple_logger
+  default-language: Haskell2010
diff --git a/src/Control/Logger/Simple.hs b/src/Control/Logger/Simple.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Logger/Simple.hs
@@ -0,0 +1,157 @@
+{-# LANGUAGE ImplicitParams #-}
+{-# LANGUAGE OverloadedStrings #-}
+module Control.Logger.Simple
+    ( withGlobalLogging, LogConfig(..)
+    , setLogLevel, LogLevel(..)
+    , logTrace, logDebug, logInfo, logNote, logWarn, logError
+    , logFail
+    , showText, (<>)
+    )
+where
+
+import Control.Exception
+import Control.Monad
+import Control.Monad.Trans
+import Data.IORef
+import Data.Monoid
+import System.IO.Unsafe
+import System.Log.FastLogger
+import qualified Data.Text as T
+import qualified Data.Traversable as T
+import qualified GHC.SrcLoc as GHC
+import qualified GHC.Stack as GHC
+
+data Loggers
+    = Loggers
+    { l_file :: Maybe (FastLogger, IO ())
+    , l_stderr :: Maybe (FastLogger, IO ())
+    , l_timeCache :: IO FormattedTime
+    }
+
+data LogConfig
+    = LogConfig
+    { lc_file :: Maybe FilePath
+    , lc_stderr :: Bool
+    }
+
+data LogLevel
+    = LogTrace
+    | LogDebug
+    | LogInfo
+    | LogNote
+    | LogWarn
+    | LogError
+    deriving (Eq, Show, Read, Ord)
+
+showText :: Show a => a -> T.Text
+showText = T.pack . show
+
+logTrace :: (?callStack :: GHC.CallStack) => MonadIO m => T.Text -> m ()
+logTrace = doLog LogTrace
+
+logDebug :: (?callStack :: GHC.CallStack) => MonadIO m => T.Text -> m ()
+logDebug = doLog LogDebug
+
+logInfo :: (?callStack :: GHC.CallStack) => MonadIO m => T.Text -> m ()
+logInfo = doLog LogInfo
+
+logNote :: (?callStack :: GHC.CallStack) => MonadIO m => T.Text -> m ()
+logNote = doLog LogNote
+
+logWarn :: (?callStack :: GHC.CallStack) => MonadIO m => T.Text -> m ()
+logWarn = doLog LogWarn
+
+logError :: (?callStack :: GHC.CallStack) => MonadIO m => T.Text -> m ()
+logError = doLog LogError
+
+-- | Log on error level and calls 'fail'
+logFail :: (?callStack :: GHC.CallStack) => MonadIO m => T.Text -> m a
+logFail t =
+    do doLog LogError t
+       fail (T.unpack t)
+
+doLog :: (?callStack :: GHC.CallStack) => MonadIO m => LogLevel -> T.Text -> m ()
+doLog ll txt =
+    liftIO $
+    readIORef logLevel >>= \logLim ->
+    when (ll >= logLim) $
+    do lgrs <- readIORef loggers
+       time <- l_timeCache lgrs
+       let loc =
+               case GHC.getCallStack ?callStack of
+                   ((_, l):_) ->
+                       GHC.srcLocFile l <> ":" <> show (GHC.srcLocStartLine l)
+                   _ -> "unknown"
+           msg =
+               "[" <> renderLevel <> " "
+               <> toLogStr time
+               <> " "
+               <> toLogStr loc
+               <> "] "
+               <> toLogStr txt
+               <> "\n"
+       forM_ (l_stderr lgrs) $ \(writeLog, _) -> writeLog (renderColor <> msg <> resetColor)
+       forM_ (l_file lgrs) $ \(writeLog, _) -> writeLog msg
+    where
+        renderLevel =
+            case ll of
+              LogTrace -> "TRACE"
+              LogDebug -> "DEBUG"
+              LogInfo -> "INFO"
+              LogNote -> "NOTE"
+              LogWarn -> "WARN"
+              LogError -> "ERROR"
+        resetColor =
+            "\o33[0;0m"
+        renderColor =
+            case ll of
+              LogTrace -> "\o33[0;30m"
+              LogDebug -> "\o33[0;34m"
+              LogInfo -> "\o33[0;34m"
+              LogNote -> "\o33[1;32m"
+              LogWarn -> "\o33[0;33m"
+              LogError -> "\o33[1;31m"
+
+loggers :: IORef Loggers
+loggers =
+    unsafePerformIO $
+    do tc <- newTimeCache timeFormat
+       newIORef (Loggers Nothing Nothing tc)
+{-# NOINLINE loggers #-}
+
+logLevel :: IORef LogLevel
+logLevel = unsafePerformIO $ newIORef LogDebug
+{-# NOINLINE logLevel #-}
+
+-- | Set the verbosity level. Messages at our higher than this level are
+-- displayed.  It defaults to 'LogDebug'.
+setLogLevel :: LogLevel -> IO ()
+setLogLevel = atomicWriteIORef logLevel
+
+-- | Setup global logging. Wrap your 'main' function with this.
+withGlobalLogging :: LogConfig -> IO a -> IO a
+withGlobalLogging lc f =
+    bracket initLogger flushLogger (const f)
+    where
+      flushLogger (Loggers a b _) =
+          do forM_ a $ \(_, flush) -> flush
+             forM_ b $ \(_, flush) -> flush
+      initLogger =
+          do fileLogger <-
+                 flip T.mapM (lc_file lc) $ \fp ->
+                 do let spec =
+                            FileLogSpec
+                            { log_file = fp
+                            , log_file_size = 1024 * 1024 * 50
+                            , log_backup_number = 5
+                            }
+                    newFastLogger (LogFile spec defaultBufSize)
+             stderrLogger <-
+                 if lc_stderr lc then Just <$> newFastLogger (LogStderr defaultBufSize) else pure Nothing
+             tc <- newTimeCache timeFormat
+             let lgrs = Loggers fileLogger stderrLogger tc
+             writeIORef loggers lgrs
+             pure lgrs
+
+timeFormat :: TimeFormat
+timeFormat = "%Y-%m-%d %T %z"
