Statistics
| Branch: | Tag: | Revision:

root / src / Ganeti / Logging.hs @ 27f904f7

History | View | Annotate | Download (4.8 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 (when)
52
import System.Log.Logger
53
import System.Log.Handler.Simple
54
import System.Log.Handler.Syslog
55
import System.Log.Handler (setFormatter, LogHandler)
56
import System.Log.Formatter
57
import System.IO
58

    
59
import Ganeti.THH
60
import qualified Ganeti.ConstantUtils as ConstantUtils
61

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

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

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

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

    
107
  updateGlobalLogger rootLoggerName (setLevel level)
108

    
109
  stderr_handlers <- openFormattedHandler stderr_logging fmt $
110
                     streamHandler stderr level
111

    
112
  file_handlers <- case destf of
113
                     Nothing -> return []
114
                     Just path -> openFormattedHandler file_logging fmt $
115
                                  fileHandler path level
116

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

    
126
-- * Logging function aliases
127

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

    
133
instance MonadLog IO where
134
  logAt = logM rootLoggerName
135

    
136

    
137
-- | Log at debug level.
138
logDebug :: (MonadLog m) => String -> m ()
139
logDebug = logAt DEBUG
140

    
141
-- | Log at info level.
142
logInfo :: (MonadLog m) => String -> m ()
143
logInfo = logAt INFO
144

    
145
-- | Log at notice level.
146
logNotice :: (MonadLog m) => String -> m ()
147
logNotice = logAt NOTICE
148

    
149
-- | Log at warning level.
150
logWarning :: (MonadLog m) => String -> m ()
151
logWarning = logAt WARNING
152

    
153
-- | Log at error level.
154
logError :: (MonadLog m) => String -> m ()
155
logError = logAt ERROR
156

    
157
-- | Log at critical level.
158
logCritical :: (MonadLog m) => String -> m ()
159
logCritical = logAt CRITICAL
160

    
161
-- | Log at alert level.
162
logAlert :: (MonadLog m) => String -> m ()
163
logAlert = logAt ALERT
164

    
165
-- | Log at emergency level.
166
logEmergency :: (MonadLog m) => String -> m ()
167
logEmergency = logAt EMERGENCY