Statistics
| Branch: | Tag: | Revision:

root / src / Ganeti / Logging.hs @ d2029364

History | View | Annotate | Download (5.1 kB)

1
{-# LANGUAGE TemplateHaskell #-}
2

    
3
{-| Implementation of the Ganeti logging functionality.
4

    
5
This currently lacks the following (FIXME):
6

    
7
- log file reopening
8

    
9
Note that this requires the hslogger library version 1.1 and above.
10

    
11
-}
12

    
13
{-
14

    
15
Copyright (C) 2011, 2012, 2013 Google Inc.
16

    
17
This program is free software; you can redistribute it and/or modify
18
it under the terms of the GNU General Public License as published by
19
the Free Software Foundation; either version 2 of the License, or
20
(at your option) any later version.
21

    
22
This program is distributed in the hope that it will be useful, but
23
WITHOUT ANY WARRANTY; without even the implied warranty of
24
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25
General Public License for more details.
26

    
27
You should have received a copy of the GNU General Public License
28
along with this program; if not, write to the Free Software
29
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
30
02110-1301, USA.
31

    
32
-}
33

    
34
module Ganeti.Logging
35
  ( setupLogging
36
  , MonadLog(..)
37
  , Priority(..)
38
  , logDebug
39
  , logInfo
40
  , logNotice
41
  , logWarning
42
  , logError
43
  , logCritical
44
  , logAlert
45
  , logEmergency
46
  , SyslogUsage(..)
47
  , syslogUsageToRaw
48
  , syslogUsageFromRaw
49
  ) where
50

    
51
import Control.Monad
52
import Control.Monad.Error (Error(..))
53
import Control.Monad.Reader
54
import System.Log.Logger
55
import System.Log.Handler.Simple
56
import System.Log.Handler.Syslog
57
import System.Log.Handler (setFormatter, LogHandler)
58
import System.Log.Formatter
59
import System.IO
60

    
61
import Ganeti.BasicTypes (ResultT(..))
62
import Ganeti.THH
63
import qualified Ganeti.ConstantUtils as ConstantUtils
64

    
65
-- | Syslog usage type.
66
$(declareLADT ''String "SyslogUsage"
67
  [ ("SyslogNo",   "no")
68
  , ("SyslogYes",  "yes")
69
  , ("SyslogOnly", "only")
70
  ])
71

    
72
-- | Builds the log formatter.
73
logFormatter :: String  -- ^ Program
74
             -> Bool    -- ^ Multithreaded
75
             -> Bool    -- ^ Syslog
76
             -> LogFormatter a
77
logFormatter prog mt syslog =
78
  let parts = [ if syslog
79
                  then "[$pid]:"
80
                  else "$time: " ++ prog ++ " pid=$pid"
81
              , if mt then if syslog then " ($tid)" else "/$tid"
82
                  else ""
83
              , " $prio $msg"
84
              ]
85
  in tfLogFormatter "%F %X,%q %Z" $ concat parts
86

    
87
-- | Helper to open and set the formatter on a log if enabled by a
88
-- given condition, otherwise returning an empty list.
89
openFormattedHandler :: (LogHandler a) => Bool
90
                     -> LogFormatter a -> IO a -> IO [a]
91
openFormattedHandler False _ _ = return []
92
openFormattedHandler True fmt opener = do
93
  handler <- opener
94
  return [setFormatter handler fmt]
95

    
96
-- | Sets up the logging configuration.
97
setupLogging :: Maybe String    -- ^ Log file
98
             -> String    -- ^ Program name
99
             -> Bool      -- ^ Debug level
100
             -> Bool      -- ^ Log to stderr
101
             -> Bool      -- ^ Log to console
102
             -> SyslogUsage -- ^ Syslog usage
103
             -> IO ()
104
setupLogging logf program debug stderr_logging console syslog = do
105
  let level = if debug then DEBUG else INFO
106
      destf = if console then Just ConstantUtils.devConsole else logf
107
      fmt = logFormatter program False False
108
      file_logging = syslog /= SyslogOnly
109

    
110
  updateGlobalLogger rootLoggerName (setLevel level)
111

    
112
  stderr_handlers <- openFormattedHandler stderr_logging fmt $
113
                     streamHandler stderr level
114

    
115
  file_handlers <- case destf of
116
                     Nothing -> return []
117
                     Just path -> openFormattedHandler file_logging fmt $
118
                                  fileHandler path level
119

    
120
  let handlers = file_handlers ++ stderr_handlers
121
  updateGlobalLogger rootLoggerName $ setHandlers handlers
122
  -- syslog handler is special (another type, still instance of the
123
  -- typeclass, and has a built-in formatter), so we can't pass it in
124
  -- the above list
125
  when (syslog /= SyslogNo) $ do
126
    syslog_handler <- openlog program [PID] DAEMON INFO
127
    updateGlobalLogger rootLoggerName $ addHandler syslog_handler
128

    
129
-- * Logging function aliases
130

    
131
-- | A monad that allows logging.
132
class Monad m => MonadLog m where
133
  -- | Log at a given level.
134
  logAt :: Priority -> String -> m ()
135

    
136
instance MonadLog IO where
137
  logAt = logM rootLoggerName
138

    
139
instance (MonadLog m) => MonadLog (ReaderT r m) where
140
  logAt p x = lift $ logAt p x
141

    
142
instance (MonadLog m, Error e) => MonadLog (ResultT e m) where
143
  logAt p = lift . logAt p
144

    
145
-- | Log at debug level.
146
logDebug :: (MonadLog m) => String -> m ()
147
logDebug = logAt DEBUG
148

    
149
-- | Log at info level.
150
logInfo :: (MonadLog m) => String -> m ()
151
logInfo = logAt INFO
152

    
153
-- | Log at notice level.
154
logNotice :: (MonadLog m) => String -> m ()
155
logNotice = logAt NOTICE
156

    
157
-- | Log at warning level.
158
logWarning :: (MonadLog m) => String -> m ()
159
logWarning = logAt WARNING
160

    
161
-- | Log at error level.
162
logError :: (MonadLog m) => String -> m ()
163
logError = logAt ERROR
164

    
165
-- | Log at critical level.
166
logCritical :: (MonadLog m) => String -> m ()
167
logCritical = logAt CRITICAL
168

    
169
-- | Log at alert level.
170
logAlert :: (MonadLog m) => String -> m ()
171
logAlert = logAt ALERT
172

    
173
-- | Log at emergency level.
174
logEmergency :: (MonadLog m) => String -> m ()
175
logEmergency = logAt EMERGENCY