diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,7 @@
+## 2.4.11
+
+* Give an explicit definition for (<>) in LogStr's Semigroup instance. [#155](https://github.com/kazu-yamamoto/logger/pull/155)
+
 ## 2.4.10
 
 * Fix Windows build on GHC 7.8. [#121](https://github.com/kazu-yamamoto/logger/pull/121)
diff --git a/System/Log/FastLogger.hs b/System/Log/FastLogger.hs
--- a/System/Log/FastLogger.hs
+++ b/System/Log/FastLogger.hs
@@ -182,7 +182,8 @@
     = LogNone                     -- ^ No logging.
     | LogStdout BufSize           -- ^ Logging to stdout.
                                   --   'BufSize' is a buffer size
-    | LogStderr BufSize           -- ^ Logging to stdout.
+                                  --   for each capability.
+    | LogStderr BufSize           -- ^ Logging to stderr.
                                   --   'BufSize' is a buffer size
                                   --   for each capability.
     | LogFileNoRotate FilePath BufSize
diff --git a/System/Log/FastLogger/LogStr.hs b/System/Log/FastLogger/LogStr.hs
--- a/System/Log/FastLogger/LogStr.hs
+++ b/System/Log/FastLogger/LogStr.hs
@@ -25,7 +25,7 @@
 import Data.Monoid ((<>))
 #endif
 #if MIN_VERSION_base(4,9,0)
-import Data.Semigroup (Semigroup)
+import qualified Data.Semigroup as Semi (Semigroup(..))
 #endif
 import Data.String (IsString(..))
 import qualified Data.Text as T
@@ -56,7 +56,8 @@
 data LogStr = LogStr !Int Builder
 
 #if MIN_VERSION_base(4,9,0)
-instance Semigroup LogStr
+instance Semi.Semigroup LogStr where
+    LogStr s1 b1 <> LogStr s2 b2 = LogStr (s1 + s2) (b1 <> b2)
 #endif
 
 instance Monoid LogStr where
@@ -81,6 +82,12 @@
     toLogStr = toLogStr . T.encodeUtf8
 instance ToLogStr TL.Text where
     toLogStr = toLogStr . TL.encodeUtf8
+
+instance Show LogStr where
+  show = show . T.decodeUtf8 . fromLogStr
+
+instance Eq LogStr where
+  a == b = fromLogStr a == fromLogStr b
 
 -- | Obtaining the length of 'LogStr'.
 logStrLength :: LogStr -> Int
diff --git a/fast-logger.cabal b/fast-logger.cabal
--- a/fast-logger.cabal
+++ b/fast-logger.cabal
@@ -1,5 +1,5 @@
 Name:                   fast-logger
-Version:                2.4.10
+Version:                2.4.11
 Author:                 Kazu Yamamoto <kazu@iij.ad.jp>
 Maintainer:             Kazu Yamamoto <kazu@iij.ad.jp>
 License:                BSD3
@@ -47,6 +47,7 @@
     Type:            exitcode-stdio-1.0
 
     Ghc-Options:     -Wall -threaded
+    Other-Modules:   FastLoggerSpec
     Build-Depends:   base >= 4 && < 5
                    , bytestring
                    , directory
diff --git a/test/FastLoggerSpec.hs b/test/FastLoggerSpec.hs
new file mode 100644
--- /dev/null
+++ b/test/FastLoggerSpec.hs
@@ -0,0 +1,83 @@
+{-# LANGUAGE OverloadedStrings, BangPatterns, CPP #-}
+
+module FastLoggerSpec where
+
+#if __GLASGOW_HASKELL__ < 709
+import Control.Applicative ((<$>))
+#endif
+import Control.Exception (finally)
+import Control.Monad (when)
+import qualified Data.ByteString.Char8 as BS
+import Data.Monoid ((<>))
+import Data.String (IsString(fromString))
+import System.Directory (doesFileExist, removeFile)
+import System.Log.FastLogger
+import Test.Hspec
+import Test.Hspec.QuickCheck (prop)
+
+spec :: Spec
+spec = do
+  describe "instance Show LogStr" $ do
+    prop "it should be consistent with instance IsString" $ \str ->
+      let logstr :: LogStr
+          logstr = fromString str
+      in show logstr == show str
+  describe "instance Eq LogStr" $ do
+    prop "it should be consistent with instance IsString" $ \str1 str2 ->
+      let logstr1, logstr2 :: LogStr
+          logstr1 = fromString str1
+          logstr2 = fromString str2
+      in (logstr1 == logstr2) == (str1 == str2)
+  describe "pushLogMsg" $ do
+    it "is safe for a large message" $ safeForLarge [
+        100
+      , 1000
+      , 10000
+      , 100000
+      , 1000000
+      ]
+    it "logs all messages" logAllMsgs
+
+nullLogger :: IO LoggerSet
+#ifdef mingw32_HOST_OS
+nullLogger = newFileLoggerSet 4096 "nul"
+#else
+nullLogger = newFileLoggerSet 4096 "/dev/null"
+#endif
+
+safeForLarge :: [Int] -> IO ()
+safeForLarge ns = mapM_ safeForLarge' ns
+
+safeForLarge' :: Int -> IO ()
+safeForLarge' n = flip finally (cleanup tmpfile) $ do
+    cleanup tmpfile
+    lgrset <- newFileLoggerSet defaultBufSize tmpfile
+    let xs = toLogStr $ BS.pack $ take (abs n) (cycle ['a'..'z'])
+        lf = "x"
+    pushLogStr lgrset $ xs <> lf
+    flushLogStr lgrset
+    rmLoggerSet lgrset
+    bs <- BS.readFile tmpfile
+    bs `shouldBe` BS.pack (take (abs n) (cycle ['a'..'z']) <> "x")
+    where
+        tmpfile = "test/temp"
+
+cleanup :: FilePath -> IO ()
+cleanup file = do
+    exist <- doesFileExist file
+    when exist $ removeFile file
+
+logAllMsgs :: IO ()
+logAllMsgs = logAll "LICENSE" `finally` cleanup tmpfile
+  where
+    tmpfile = "test/temp"
+    logAll file = do
+        cleanup tmpfile
+        lgrset <- newFileLoggerSet 512 tmpfile
+        src <- BS.readFile file
+        let bs = (<> "\n") . toLogStr <$> BS.lines src
+        mapM_ (pushLogStr lgrset) bs
+        flushLogStr lgrset
+        rmLoggerSet lgrset
+        dst <- BS.readFile tmpfile
+        dst `shouldBe` src
