diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,8 @@
+## 3.0.4
+
+* New API: `newFastLogger1` which use only one capability.
+* Making `FD` safer with `invalidFD`.
+
 ## 3.0.3
 
 * Dropping support of GHC 7.x.
diff --git a/System/Log/FastLogger.hs b/System/Log/FastLogger.hs
--- a/System/Log/FastLogger.hs
+++ b/System/Log/FastLogger.hs
@@ -15,6 +15,7 @@
   , LogType
   , LogType'(..)
   , newFastLogger
+  , newFastLogger1
   , withFastLogger
   -- * Timed FastLogger
   , TimedFastLogger
@@ -101,11 +102,17 @@
 --
 -- > newFastLogger :: LogType -> IO (FastLogger, IO ())
 newFastLogger :: LogType' v -> IO (v -> IO (), IO ())
-newFastLogger typ = case typ of
+newFastLogger typ = newFastLoggerCore Nothing typ
+
+newFastLogger1 :: LogType' v -> IO (v -> IO (), IO ())
+newFastLogger1 typ = newFastLoggerCore (Just 1) typ
+
+newFastLoggerCore :: Maybe Int -> LogType' v -> IO (v -> IO (), IO ())
+newFastLoggerCore mn typ = case typ of
     LogNone                        -> return (const noOp, noOp)
     LogStdout bsize                -> newStdoutLoggerSet bsize >>= stdLoggerInit
     LogStderr bsize                -> newStderrLoggerSet bsize >>= stdLoggerInit
-    LogFileNoRotate fp bsize       -> newFileLoggerSet bsize fp >>= fileLoggerInit
+    LogFileNoRotate fp bsize       -> newFileLoggerSet bsize mn fp >>= fileLoggerInit
     LogFile fspec bsize            -> rotateLoggerInit fspec bsize
     LogFileTimedRotate fspec bsize -> timedRotateLoggerInit fspec bsize
     LogCallback cb flush           -> return (\str -> cb str >> flush, noOp)
@@ -113,7 +120,7 @@
     stdLoggerInit lgrset = return (pushLogStr lgrset, rmLoggerSet lgrset)
     fileLoggerInit lgrset = return (pushLogStr lgrset, rmLoggerSet lgrset)
     rotateLoggerInit fspec bsize = do
-        lgrset <- newFileLoggerSet bsize $ log_file fspec
+        lgrset <- newFileLoggerSet bsize mn $ log_file fspec
         ref <- newIORef (0 :: Int)
         mvar <- newMVar ()
         let logger str = do
@@ -124,7 +131,7 @@
     timedRotateLoggerInit fspec bsize = do
         cache <- newTimeCache $ timed_timefmt fspec
         now <- cache
-        lgrset <- newFileLoggerSet bsize $ prefixTime now $ timed_log_file fspec
+        lgrset <- newFileLoggerSet bsize mn $ prefixTime now $ timed_log_file fspec
         ref <- newIORef now
         mvar <- newMVar lgrset
         let logger str = do
@@ -148,7 +155,7 @@
     LogNone                        -> return (const noOp, noOp)
     LogStdout bsize                -> newStdoutLoggerSet bsize >>= stdLoggerInit
     LogStderr bsize                -> newStderrLoggerSet bsize >>= stdLoggerInit
-    LogFileNoRotate fp bsize       -> newFileLoggerSet bsize fp >>= fileLoggerInit
+    LogFileNoRotate fp bsize       -> newFileLoggerSet bsize Nothing fp >>= fileLoggerInit
     LogFile fspec bsize            -> rotateLoggerInit fspec bsize
     LogFileTimedRotate fspec bsize -> timedRotateLoggerInit fspec bsize
     LogCallback cb flush           -> return (\f -> tgetter >>= cb . f >> flush, noOp)
@@ -156,7 +163,7 @@
     stdLoggerInit lgrset = return ( \f -> tgetter >>= pushLogStr lgrset . f, rmLoggerSet lgrset)
     fileLoggerInit lgrset = return (\f -> tgetter >>= pushLogStr lgrset . f, rmLoggerSet lgrset)
     rotateLoggerInit fspec bsize = do
-        lgrset <- newFileLoggerSet bsize $ log_file fspec
+        lgrset <- newFileLoggerSet bsize Nothing $ log_file fspec
         ref <- newIORef (0 :: Int)
         mvar <- newMVar ()
         let logger f = do
@@ -168,7 +175,7 @@
     timedRotateLoggerInit fspec bsize = do
         cache <- newTimeCache $ timed_timefmt fspec
         now <- cache
-        lgrset <- newFileLoggerSet bsize $ prefixTime now $ timed_log_file fspec
+        lgrset <- newFileLoggerSet bsize Nothing $ prefixTime now $ timed_log_file fspec
         ref <- newIORef now
         mvar <- newMVar lgrset
         let logger f = do
diff --git a/System/Log/FastLogger/FileIO.hs b/System/Log/FastLogger/FileIO.hs
--- a/System/Log/FastLogger/FileIO.hs
+++ b/System/Log/FastLogger/FileIO.hs
@@ -25,4 +25,13 @@
 writeRawBufferPtr2FD :: IORef FD -> Ptr Word8 -> Int -> IO Int
 writeRawBufferPtr2FD fdref bf len = do
     fd <- readIORef fdref
-    fromIntegral <$> writeRawBufferPtr "write" fd bf 0 (fromIntegral len)
+    if isFDValid fd then
+        fromIntegral <$> writeRawBufferPtr "write" fd bf 0 (fromIntegral len)
+      else
+        return (-1)
+
+invalidFD :: POSIX.FD
+invalidFD = stdout { POSIX.fdFD = -1 }
+
+isFDValid :: POSIX.FD -> Bool
+isFDValid fd = POSIX.fdFD fd /= -1
diff --git a/System/Log/FastLogger/Logger.hs b/System/Log/FastLogger/Logger.hs
--- a/System/Log/FastLogger/Logger.hs
+++ b/System/Log/FastLogger/Logger.hs
@@ -83,5 +83,5 @@
   where
     loop bf !len = do
         written <- writeRawBufferPtr2FD fdref bf len
-        when (written < len) $
+        when (0 <= written && written < len) $
             loop (bf `plusPtr` fromIntegral written) (len - written)
diff --git a/System/Log/FastLogger/LoggerSet.hs b/System/Log/FastLogger/LoggerSet.hs
--- a/System/Log/FastLogger/LoggerSet.hs
+++ b/System/Log/FastLogger/LoggerSet.hs
@@ -38,29 +38,31 @@
 data LoggerSet = LoggerSet (Maybe FilePath) (IORef FD) (Array Int Logger) (IO ())
 
 -- | Creating a new 'LoggerSet' using a file.
-newFileLoggerSet :: BufSize -> FilePath -> IO LoggerSet
-newFileLoggerSet size file = openFileFD file >>= newFDLoggerSet size (Just file)
+newFileLoggerSet :: BufSize -> Maybe Int -> FilePath -> IO LoggerSet
+newFileLoggerSet size mn file = openFileFD file >>= newFDLoggerSet size mn (Just file)
 
 -- | Creating a new 'LoggerSet' using stdout.
 newStdoutLoggerSet :: BufSize -> IO LoggerSet
-newStdoutLoggerSet size = getStdoutFD >>= newFDLoggerSet size Nothing
+newStdoutLoggerSet size = getStdoutFD >>= newFDLoggerSet size Nothing Nothing
 
 -- | Creating a new 'LoggerSet' using stderr.
 newStderrLoggerSet :: BufSize -> IO LoggerSet
-newStderrLoggerSet size = getStderrFD >>= newFDLoggerSet size Nothing
+newStderrLoggerSet size = getStderrFD >>= newFDLoggerSet size Nothing Nothing
 
 {-# DEPRECATED newLoggerSet "Use newFileLoggerSet etc instead" #-}
 -- | Creating a new 'LoggerSet'.
 --   If 'Nothing' is specified to the second argument,
 --   stdout is used.
 --   Please note that the minimum 'BufSize' is 1.
-newLoggerSet :: BufSize -> Maybe FilePath -> IO LoggerSet
-newLoggerSet size = maybe (newStdoutLoggerSet size) (newFileLoggerSet size)
+newLoggerSet :: BufSize -> Maybe Int -> Maybe FilePath -> IO LoggerSet
+newLoggerSet size mn = maybe (newStdoutLoggerSet size) (newFileLoggerSet size mn)
 
 -- | Creating a new 'LoggerSet' using a FD.
-newFDLoggerSet :: BufSize -> Maybe FilePath -> FD -> IO LoggerSet
-newFDLoggerSet size mfile fd = do
-    n <- getNumCapabilities
+newFDLoggerSet :: BufSize -> Maybe Int -> Maybe FilePath -> FD -> IO LoggerSet
+newFDLoggerSet size mn mfile fd = do
+    n <- case mn of
+      Just n' -> return n'
+      Nothing -> getNumCapabilities
     loggers <- replicateM n $ newLogger (max 1 size)
     let arr = listArray (0,n-1) loggers
     fref <- newIORef fd
@@ -121,12 +123,14 @@
 --   and freeing the buffers.
 rmLoggerSet :: LoggerSet -> IO ()
 rmLoggerSet (LoggerSet mfile fdref arr _) = do
-    let (l,u) = bounds arr
-    let nums = [l .. u]
-    mapM_ flushIt nums
-    mapM_ freeIt nums
     fd <- readIORef fdref
-    when (isJust mfile) $ closeFD fd
+    when (isFDValid fd) $ do
+        let (l,u) = bounds arr
+        let nums = [l .. u]
+        mapM_ flushIt nums
+        mapM_ freeIt nums
+        when (isJust mfile) $ closeFD fd
+        writeIORef fdref invalidFD
   where
     flushIt i = flushLog fdref (arr ! i)
     freeIt i = do
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:                3.0.3
+Version:                3.0.4
 Author:                 Kazu Yamamoto <kazu@iij.ad.jp>
 Maintainer:             Kazu Yamamoto <kazu@iij.ad.jp>
 License:                BSD3
diff --git a/test/FastLoggerSpec.hs b/test/FastLoggerSpec.hs
--- a/test/FastLoggerSpec.hs
+++ b/test/FastLoggerSpec.hs
@@ -40,9 +40,9 @@
 
 nullLogger :: IO LoggerSet
 #ifdef mingw32_HOST_OS
-nullLogger = newFileLoggerSet 4096 "nul"
+nullLogger = newFileLoggerSet 4096 Nothing "nul"
 #else
-nullLogger = newFileLoggerSet 4096 "/dev/null"
+nullLogger = newFileLoggerSet 4096 Nothing "/dev/null"
 #endif
 
 safeForLarge :: [Int] -> IO ()
@@ -51,7 +51,7 @@
 safeForLarge' :: Int -> IO ()
 safeForLarge' n = flip finally (cleanup tmpfile) $ do
     cleanup tmpfile
-    lgrset <- newFileLoggerSet defaultBufSize tmpfile
+    lgrset <- newFileLoggerSet defaultBufSize Nothing tmpfile
     let xs = toLogStr $ BS.pack $ take (abs n) (cycle ['a'..'z'])
         lf = "x"
     pushLogStr lgrset $ xs <> lf
@@ -73,7 +73,7 @@
     tmpfile = "test/temp"
     logAll file = do
         cleanup tmpfile
-        lgrset <- newFileLoggerSet 512 tmpfile
+        lgrset <- newFileLoggerSet 512 Nothing tmpfile
         src <- BS.readFile file
         let bs = (<> "\n") . toLogStr <$> BS.lines src
         mapM_ (pushLogStr lgrset) bs
