05505233bd6d33bfe6263636ad25a6a60323df3a
[OpenSRF.git] / src / python / osrf / log.py
1 # -----------------------------------------------------------------------
2 # Copyright (C) 2007  Georgia Public Library Service
3 # Bill Erickson <billserickson@gmail.com>
4
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
9
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 # -----------------------------------------------------------------------
15
16 import traceback, sys, os, re, threading
17 from osrf.const import OSRF_LOG_DEBUG, OSRF_LOG_ERR, OSRF_LOG_INFO, \
18     OSRF_LOG_INTERNAL, OSRF_LOG_TYPE_FILE, OSRF_LOG_TYPE_STDERR, \
19     OSRF_LOG_TYPE_SYSLOG, OSRF_LOG_WARN
20 LOG_SEMAPHORE = threading.BoundedSemaphore(value=1)
21
22
23 LOG_LEVEL = OSRF_LOG_DEBUG
24 LOG_TYPE = OSRF_LOG_TYPE_STDERR
25 LOG_FILE = None
26 FRGX = re.compile('/.*/')
27
28
29 def initialize(level, facility=None, logfile=None):
30     """Initialize the logging subsystem."""
31     global LOG_LEVEL, LOG_TYPE, LOG_FILE
32
33     LOG_LEVEL = level
34
35     if facility: 
36         try:
37             import syslog
38         except ImportError:
39             sys.stderr.write("syslog not found, logging to stderr\n")
40             return
41
42         LOG_TYPE = OSRF_LOG_TYPE_SYSLOG
43         initialize_syslog(facility, level)
44         return
45         
46     if logfile:
47         LOG_TYPE = OSRF_LOG_TYPE_FILE
48         LOG_FILE = logfile
49
50
51 # -----------------------------------------------------------------------
52 # Define wrapper functions for the log levels
53 # -----------------------------------------------------------------------
54 def log_internal(debug_str):
55     __log(OSRF_LOG_INTERNAL, debug_str)
56 def log_debug(debug_str):
57     __log(OSRF_LOG_DEBUG, debug_str)
58 def log_info(debug_str):
59     __log(OSRF_LOG_INFO, debug_str)
60 def log_warn(debug_str):
61     __log(OSRF_LOG_WARN, debug_str)
62 def log_error(debug_str):
63     __log(OSRF_LOG_ERR, debug_str)
64
65 def __log(level, msg):
66     """Builds the log message and passes the message off to the logger."""
67     global LOG_LEVEL, LOG_TYPE
68
69     try:
70         import syslog
71     except:
72         if level == OSRF_LOG_ERR:
73             sys.stderr.write('ERR ' + msg)
74         return
75         
76     if int(level) > int(LOG_LEVEL): return
77
78     # find the caller info for logging the file and line number
79     tb = traceback.extract_stack(limit=3)
80     tb = tb[0]
81     lvl = 'DEBG'
82
83     if level == OSRF_LOG_INTERNAL:
84         lvl = 'INT '
85     if level == OSRF_LOG_INFO:
86         lvl = 'INFO'
87     if level == OSRF_LOG_WARN:
88         lvl = 'WARN'
89     if level == OSRF_LOG_ERR:
90         lvl = 'ERR '
91
92     filename = FRGX.sub('', tb[0])
93     msg = '[%s:%d:%s:%s:%s] %s' % (lvl, os.getpid(), filename, tb[1], threading.currentThread().getName(), msg)
94
95     if LOG_TYPE == OSRF_LOG_TYPE_SYSLOG:
96         __log_syslog(level, msg)
97     else:
98         if LOG_TYPE == OSRF_LOG_TYPE_FILE:
99             __log_file(msg)
100         else:
101             sys.stderr.write("%s\n" % msg)
102
103     if level == OSRF_LOG_ERR and LOG_TYPE != OSRF_LOG_TYPE_STDERR:
104         sys.stderr.write(msg + '\n')
105
106 def __log_syslog(level, msg):
107     ''' Logs the message to syslog '''
108     import syslog
109
110     slvl = syslog.LOG_DEBUG
111     if level == OSRF_LOG_INTERNAL:
112         slvl = syslog.LOG_DEBUG
113     if level == OSRF_LOG_INFO:
114         slvl = syslog.LOG_INFO
115     if level == OSRF_LOG_WARN:
116         slvl = syslog.LOG_WARNING
117     if level == OSRF_LOG_ERR:
118         slvl = syslog.LOG_ERR
119
120     syslog.syslog(slvl, msg)
121
122 def __log_file(msg):
123     ''' Logs the message to a file. '''
124
125     global LOG_TYPE
126
127     logfile = None
128     try:
129         logfile = open(LOG_FILE, 'a')
130     except:
131         sys.stderr.write("cannot open log file for writing: %s\n", LOG_FILE)
132         LOG_TYPE = OSRF_LOG_TYPE_STDERR
133         return
134     try:
135         LOG_SEMAPHORE.acquire()
136         logfile.write("%s\n" % msg)
137     finally:
138         LOG_SEMAPHORE.release()
139         
140     logfile.close()
141
142 def initialize_syslog(facility, level):
143     """Connect to syslog and set the logmask based on the level provided."""
144
145     import syslog
146     level = int(level)
147
148     if facility == 'local0':
149         facility = syslog.LOG_LOCAL0
150     if facility == 'local1':
151         facility = syslog.LOG_LOCAL1
152     if facility == 'local2':
153         facility = syslog.LOG_LOCAL2
154     if facility == 'local3':
155         facility = syslog.LOG_LOCAL3
156     if facility == 'local4':
157         facility = syslog.LOG_LOCAL4
158     if facility == 'local5':
159         facility = syslog.LOG_LOCAL5
160     if facility == 'local6':
161         facility = syslog.LOG_LOCAL6
162     # add other facility maps if necessary...
163
164     syslog.openlog(sys.argv[0], 0, facility)
165