diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,7 @@
+# Change Log
+
+## [0.0.1 -- 2019-04-13]
+
+### Added
+
+- Basic functions.
diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,29 @@
+BSD 3-Clause License
+
+Copyright (c) 2019, Akihito KIRISAKI
+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 the copyright holder nor the names of its
+  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 HOLDER 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,114 @@
+# caster
+caster is a multicast, thread-safe and fast logger.
+It's convenient when log towards multiple outputs, 
+for example, when you want to log to stdout and files same time.
+It's possible to change format and log level each outputs.
+Also, it converts text-like values and Show instances into log messages automatically.
+
+## Usage
+
+First, the logger requires concurrency.
+
+```haskell
+import Control.Concurrent
+```
+
+Then, prepare to use the logger. 
+In following code, make `LogQueue`, `LogChan` and `Listener`,
+start threads which relay messages from `LogChan` to the outputs 
+and one which broadcasts messages to `LogChan`.
+Be careful not to change the order of `relayLog` and `broadcastLog`.
+It causes that messages at the first are not logged correctly.
+
+```haskell
+import System.IO
+import System.Log.Caster
+
+main = do
+  chan <- newLogChan
+  lq <- newLogQueue
+
+  -- log to a file..
+  handle <- openFile "./foo.log" "caster_test_0.log"
+  let FileListener = handleListener defaultFormatter handle
+  _ <- forkIO $ relayLog chan LogDebug fileListener
+
+  -- log to stdout.
+  _ <- forkIO $ relayLog chan LogInfo stdoutListener
+
+  -- start to broadcast.
+  _ <- forkIO $ broadcastLog lq chan
+  
+  -- give the LogQueue to the function which you want to log in.
+  someFunc lq
+
+```
+
+Last, push a message into the `LogQueue` with given functions in order to log.
+
+``` haskell
+
+someFunc :: LogQueue -> IO ()
+someFunc lq = do
+
+  -- log levels are matched to syslog.
+  -- if you use OverloadedStrings, need to add type annotation.
+  debug lq ("debug message" :: String)
+  
+  -- or you can use helper operator or helper function.
+  info lq $: "info messages"
+  info lq $ fix  "info messages"
+  
+  -- if the type is obviously, need not to annotate.
+  let msg = Data.Text.pack "notice message"
+  notice lq msg
+  
+  -- it's possible to give incetanse of Show.
+  warn lq True
+  
+  -- there is the useful operator which concatrates text-like values.
+  -- the values are converted into byte string as utf-8.
+  let text = "foo" :: Data.Text.Text
+  let bs = "bar" :: Data.ByteString.Lazy.ByteString
+  err lq $ text <:> bs <:> fix "baz"
+  
+```
+
+The logger requires to be given `LogQueue`, 
+so functions which log need to take `LogQueue` as a parameter. 
+You can inject `LogQueue` with Reader Monad and so on, 
+but I recommend to use easily [Data\.Reflection](https://hackage.haskell.org/package/reflection).
+
+
+```haskell
+{-# LANGUAGE FlexibleContexts          #-}
+{-# LANGUAGE RankNTypes                #-}
+
+import Control.Concurrent
+import Control.Monad
+import Data.Reflection
+import System.Log.Caster
+
+type UseLogger = Given LogQueue
+
+useLogger :: UseLogger => LogQueue
+useLogger = given
+
+someIO :: UseLogger => IO ()
+someIO = do
+  critical useLogger "critical message"
+  alert useLogger "alert message"
+  emergency useLogger "..."
+  
+inject :: (UseLogger => a) -> IO a
+inject io = do
+  lq <- newLogQueue
+  give io lq
+  
+main :: IO ()
+main = do
+  chan <- newLogChan
+  _ <- forkIO $ relayLog chan LogDebug stdoutListener
+  join $ inject someIO
+  
+```
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/caster.cabal b/caster.cabal
new file mode 100644
--- /dev/null
+++ b/caster.cabal
@@ -0,0 +1,60 @@
+name:                caster
+version:             0.0.1.0
+synopsis:            Multicast, thread-safe, and fast logger.
+description:         Please see the README on GitHub at <https://github.com/kirisaki/caster#readme>
+homepage:            https://github.com/kirisaki/caster#readme
+bug-reports:         https://github.com/kirisaki/caster/issues
+license:             BSD3
+license-file:        LICENSE
+author:              Akihito KIRISAKI
+maintainer:          kirisaki@klaraworks.net
+copyright:           Akihito KIRISAKI
+category:            System
+build-type:          Simple
+extra-source-files:  CHANGELOG.md, README.md
+cabal-version:       >=1.10
+
+source-repository head
+  type: git
+  location: https://github.com/kirisaki/caster
+
+library
+  exposed-modules: System.Log.Caster
+  -- other-extensions:
+  build-depends:       base >= 4.10
+                     , bytestring >= 0.10.8.2
+                     , fast-builder >= 0.1.0.0
+                     , stm >= 2.5.0.0
+                     , text >= 1.2.3.1
+                     , unix-time >= 0.4.5
+  hs-source-dirs:      src
+  default-language:    Haskell2010
+  default-extensions: LambdaCase
+                    , OverloadedStrings
+                    , FlexibleInstances
+                    , FlexibleContexts
+                    , TypeSynonymInstances
+                    , MultiParamTypeClasses
+                    , ExistentialQuantification
+
+test-suite test
+  type: exitcode-stdio-1.0
+  main-is: Driver.hs
+  other-modules:
+                CasterTest
+  default-language:    Haskell2010
+  hs-source-dirs:
+                 test
+  build-depends:
+                base >= 4 && < 5
+              , caster
+              , bytestring
+              , directory
+              , text
+              , fast-builder
+              , QuickCheck
+              , quickcheck-instances
+              , tasty-hunit
+              , tasty
+              , tasty-discover
+              , tasty-quickcheck
diff --git a/src/System/Log/Caster.hs b/src/System/Log/Caster.hs
new file mode 100644
--- /dev/null
+++ b/src/System/Log/Caster.hs
@@ -0,0 +1,231 @@
+{-|
+Module      : System.Log.Caster
+Description : Multicast, thread-safe, and not slow logger.
+Copyright   : (c) Akihito KIRISAKI
+
+License     : BSD3
+Maintainer  : Akihito KIRISAKI
+Stability   : experimental
+-}
+{-# LANGUAGE UndecidableInstances #-}
+module System.Log.Caster
+  ( -- * Basics
+    LogMsg(..)
+  , broadcastLog
+  , LogQueue(..)
+  , newLogQueue
+  , LogChan(..)
+  , newLogChan
+  , Formatter
+  , Listener
+  , relayLog
+  -- * Listeners
+  , stdoutListener
+  , stdoutListenerWith
+  , handleListener
+  , handleListenerFlush
+  -- * Formatter
+  , defaultFormatter
+  -- * Log levels
+  , LogLevel(..)
+  , logAs
+  , debug
+  , info
+  , notice
+  , warn
+  , err
+  , critical
+  , alert
+  , emergency
+  -- * Useful string class and operator
+  , ToBuilder(..)
+  , fix
+  , ($:)
+  , (<:>)
+  ) where
+
+
+import           Control.Concurrent.STM
+import           Control.Monad
+import           Control.Monad.IO.Class      (MonadIO (..))
+import qualified Data.ByteString             as SBS
+import qualified Data.ByteString.Builder     as BB
+import qualified Data.ByteString.FastBuilder as FB
+import qualified Data.ByteString.Lazy        as LBS
+import           Data.Semigroup
+import qualified Data.Text                   as ST
+import qualified Data.Text.Encoding          as STE
+import qualified Data.Text.Lazy              as LT
+import qualified Data.Text.Lazy.Encoding     as LTE
+import           Data.UnixTime               (Format, UnixTime (..),
+                                              formatUnixTime, getUnixTime)
+import           GHC.IO.Unsafe               (unsafePerformIO)
+import           System.IO                   (Handle, hFlush, stdout)
+
+-- | Types which are able to be converted into @'FB.Builder' Builder@
+--   @toBuilde@ encodes @String@ and @Text@ as utf-8.
+class ToBuilder a where
+  toBuilder :: a -> FB.Builder
+
+instance ToBuilder FB.Builder where
+  toBuilder = id
+
+instance ToBuilder String where
+  toBuilder = FB.stringUtf8
+
+instance ToBuilder ST.Text where
+  toBuilder = FB.byteString . STE.encodeUtf8
+
+instance ToBuilder LT.Text where
+  toBuilder = FB.byteString . LBS.toStrict . LTE.encodeUtf8
+
+instance ToBuilder SBS.ByteString where
+  toBuilder = FB.byteString
+
+instance ToBuilder LBS.ByteString where
+  toBuilder = FB.byteString . LBS.toStrict
+
+instance ToBuilder BB.Builder where
+  toBuilder = FB.byteString . LBS.toStrict . BB.toLazyByteString
+
+instance {-# OVERLAPPABLE #-} Show a => ToBuilder a where
+  toBuilder = FB.stringUtf8 . show
+
+-- | If you turn @OverloadedStrings@ extension on, GHC can't deduce the type of string literal.
+--   This function fix the type to @'FB.Builder' Builder@ without type annotation.
+fix :: FB.Builder -> FB.Builder
+fix = id
+
+-- | Infix version of @fix@.
+infixr 0 $:
+($:) :: ToBuilder b => (FB.Builder -> b) -> FB.Builder -> b
+($:) = ($)
+
+-- | Concat @ToBuilder@ strings as @'FB.Builder' Builder@.
+infixr 6 <:>
+(<:>) :: (ToBuilder a, ToBuilder b) => a -> b -> FB.Builder
+a <:> b = toBuilder a <> toBuilder b
+
+-- |Log levels. These are matched to syslog.
+data LogLevel
+  = LogDebug
+  | LogInfo
+  | LogNotice
+  | LogWarn
+  | LogError
+  | LogCritical
+  | LogAlert
+  | LogEmergency
+  deriving (Show, Eq, Ord)
+
+-- | Log message.
+data LogMsg = LogMsg
+  { logMsgLevel   :: LogLevel
+  , logMsgTime    :: UnixTime
+  , logMsgBuilder :: FB.Builder
+  }
+
+-- | Queue of @LogMsg@.
+newtype LogQueue = LogQueue (TQueue LogMsg)
+
+-- | Channel of @LogMsg@.
+newtype LogChan = LogChan (TChan LogMsg)
+
+-- | Make new @LogQueue@
+newLogQueue :: IO LogQueue
+newLogQueue = LogQueue <$> newTQueueIO
+
+-- | Make new @LogChan@.
+newLogChan :: IO LogChan
+newLogChan = LogChan <$> newBroadcastTChanIO
+
+-- | Connect @LogQueue@ and @TChan@ @LogMsg@.
+broadcastLog :: LogQueue -> LogChan -> IO ()
+broadcastLog (LogQueue q) (LogChan c) =  forever $
+  atomically $ readTQueue q >>= writeTChan c
+
+-- | Formatter.
+type Formatter = LogMsg -> FB.Builder
+
+-- | IO function takes @LogMsg@.
+type Listener = LogMsg -> IO ()
+
+-- | Listen @LogChan@ and give the @LogMsg@ to given @Listener@.
+relayLog :: LogChan -> LogLevel -> Listener -> IO ()
+relayLog (LogChan bchan) logLevel listener = do
+  chan <- atomically $ dupTChan bchan
+  forever $ do
+    msg <- atomically $ readTChan chan
+    when (logMsgLevel msg >= logLevel) $ listener msg
+
+-- | Make @Listener@ from @Handle@
+handleListener :: Formatter -> Handle -> Listener
+handleListener f h = FB.hPutBuilder h . f
+
+-- | Make @Listener@ flushing buffer after getting @LogMsg@
+handleListenerFlush :: Formatter -> Handle -> Listener
+handleListenerFlush f h msg = FB.hPutBuilder h (f msg) >> hFlush h
+
+-- | Stdout listener with @Formatter@.
+stdoutListenerWith :: Formatter -> Listener
+stdoutListenerWith f = handleListenerFlush f stdout
+
+-- | Stdout listener.
+stdoutListener :: Listener
+stdoutListener = stdoutListenerWith defaultFormatter
+
+
+-- | Default log formatter.
+defaultFormatter :: Formatter
+defaultFormatter (LogMsg lev ut str) =
+  formatTime ut <> " - [" <> logLevelToBuilder lev <> "] " <> str <> "\n"
+
+logLevelToBuilder :: LogLevel -> FB.Builder
+logLevelToBuilder = \case
+  LogDebug -> "DEBUG"
+  LogInfo  -> "INFO"
+  LogNotice  -> "NOTICE"
+  LogWarn  -> "WARN"
+  LogError -> "ERROR"
+  LogCritical -> "CRITICAL"
+  LogAlert -> "ALERT"
+  LogEmergency -> "EMERGEBCY"
+
+{-# NOINLINE formatTime #-}
+formatTime :: UnixTime -> FB.Builder
+formatTime ut =
+  let
+    ut' = FB.byteString . unsafePerformIO $ formatUnixTime "%Y-%m-d %T" ut
+    utMilli = FB.string7 . tail . show $ utMicroSeconds ut `div` 1000 + 1000
+  in
+    ut' <> "." <> utMilli
+
+-- | Push a message to @LogQueue@.
+logAs :: (MonadIO m, ToBuilder s) => LogQueue -> LogLevel -> s -> m ()
+logAs (LogQueue q) l s = liftIO $ do
+  ut <- getUnixTime
+  atomically $ writeTQueue q (LogMsg l ut (toBuilder s))
+
+debug :: (MonadIO m, ToBuilder s) => LogQueue -> s -> m ()
+debug q = logAs q LogDebug
+
+info :: (MonadIO m, ToBuilder s) => LogQueue -> s -> m ()
+info q = logAs q LogInfo
+
+notice :: (MonadIO m, ToBuilder s) => LogQueue -> s -> m ()
+notice q = logAs q LogNotice
+
+warn :: (MonadIO m, ToBuilder s) => LogQueue -> s -> m ()
+warn q = logAs q LogWarn
+
+err :: (MonadIO m, ToBuilder s) => LogQueue -> s -> m ()
+err q = logAs q LogError
+
+critical :: (MonadIO m, ToBuilder s) => LogQueue -> s -> m ()
+critical q = logAs q LogCritical
+
+alert :: (MonadIO m, ToBuilder s) => LogQueue -> s -> m ()
+alert q = logAs q LogAlert
+
+emergency :: (MonadIO m, ToBuilder s) => LogQueue -> s -> m ()
+emergency q = logAs q LogEmergency
diff --git a/test/CasterTest.hs b/test/CasterTest.hs
new file mode 100644
--- /dev/null
+++ b/test/CasterTest.hs
@@ -0,0 +1,92 @@
+{-# LANGUAGE BangPatterns #-}
+module CasterTest where
+
+import           System.Log.Caster
+import           Test.QuickCheck.Instances
+import           Test.QuickCheck.Monadic     as QCM
+import           Test.Tasty
+import           Test.Tasty.HUnit
+import           Test.Tasty.QuickCheck
+
+import           Control.Concurrent
+import           Control.Monad
+import qualified Data.ByteString             as SBS
+import qualified Data.ByteString.Builder     as BB
+import qualified Data.ByteString.FastBuilder as FB
+import qualified Data.ByteString.Lazy        as LBS
+import           Data.Semigroup
+import qualified Data.Text                   as ST
+import qualified Data.Text.Encoding          as STE
+import qualified Data.Text.Lazy              as LT
+import qualified Data.Text.Lazy.Encoding     as LTE
+import           System.Directory
+import           System.IO
+
+prop_toBuilder_String :: String -> Bool
+prop_toBuilder_String str = (LT.unpack . LTE.decodeUtf8 . FB.toLazyByteString $ toBuilder str) == str
+
+prop_toBuilder_strict_Text :: ST.Text -> Bool
+prop_toBuilder_strict_Text str = (LT.toStrict . LTE.decodeUtf8 . FB.toLazyByteString $ toBuilder str) == str
+
+prop_toBuilder_lazy_Text :: LT.Text -> Bool
+prop_toBuilder_lazy_Text str = (LTE.decodeUtf8 . FB.toLazyByteString $ toBuilder str) == str
+
+prop_toBuilder_strict_ByteString :: SBS.ByteString -> Bool
+prop_toBuilder_strict_ByteString str = FB.toStrictByteString (toBuilder str) == str
+
+prop_toBuilder_lazy_ByteString :: LBS.ByteString -> Bool
+prop_toBuilder_lazy_ByteString str = FB.toLazyByteString (toBuilder str) == str
+
+data TestShow = Foo | Bar | Baz deriving (Show)
+instance Arbitrary TestShow where
+  arbitrary = elements [Foo, Bar, Baz]
+
+prop_toBuilder_Show :: TestShow -> Bool
+prop_toBuilder_Show x = FB.toLazyByteString (toBuilder x) == (LTE.encodeUtf8 . LT.pack $ show x)
+
+prop_concat :: String -> String -> Bool
+prop_concat str0 str1 = (LT.unpack . LTE.decodeUtf8 . FB.toLazyByteString $ str0 <:> str1) == str0 <> str1
+
+instance Arbitrary LogLevel where
+  arbitrary = elements [LogDebug, LogInfo, LogNotice, LogWarn, LogError, LogCritical, LogAlert, LogEmergency]
+
+prop_broadcastLog :: [(LogLevel, String)] -> Property
+prop_broadcastLog msgs = monadicIO $ do
+  result <- run $ do
+    chan <- newLogChan
+    lq <- newLogQueue
+
+    (file0, handle0) <- openTempFile "/tmp" "caster_test_0.log"
+    let listener0 = handleListenerFlush defaultFormatter handle0
+    thread0 <- forkIO $ relayLog chan LogDebug listener0
+
+    (file1, handle1) <- openTempFile "/tmp" "caster_test_1.log"
+    let listener1 = handleListenerFlush defaultFormatter handle1
+    thread1 <- forkIO $ relayLog chan LogDebug listener1
+
+    (file2, handle2) <- openTempFile "/tmp" "caster_test_2.log"
+    let listener2 = handleListenerFlush defaultFormatter handle2
+    thread2 <- forkIO $ relayLog chan LogDebug listener2
+
+    threadb <- forkIO $ broadcastLog lq chan
+
+    mapM_ (uncurry $ logAs lq) msgs
+
+    log0 <- hGetContents handle0
+    log1 <- hGetContents handle1
+    log2 <- hGetContents handle2
+
+    let !res = log0 == log1 && log1 == log2
+
+    killThread thread0
+    killThread thread1
+    killThread thread2
+    killThread threadb
+
+    removeFile file0
+    removeFile file1
+    removeFile file2
+
+    pure res
+
+  QCM.assert result
diff --git a/test/Driver.hs b/test/Driver.hs
new file mode 100644
--- /dev/null
+++ b/test/Driver.hs
@@ -0,0 +1,1 @@
+{-# OPTIONS_GHC -F -pgmF tasty-discover #-}
