Skip to content

Commit 2229770

Browse files
committed
Merge remote-tracking branch 'origin/logsplit'
2 parents 6b79916 + 816a65a commit 2229770

3 files changed

Lines changed: 170 additions & 0 deletions

File tree

simpledaemonlog/__init__.py

Whitespace-only changes.

simpledaemonlog/daemonarguments.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"""daemonarguments.py: Common options for daemons with argconfparse and simplelogging."""
2+
3+
import simplelogging.logsetup
4+
from argconfparse.argconfparse import arg_str2bool
5+
6+
7+
__author__ = 'Raido Pahtma'
8+
__license__ = "MIT"
9+
10+
11+
def add_daemon_arguments(parser):
12+
parser.add_argument("--daemon", default=False, type=arg_str2bool, help="Daemon mode, no logging to console.")
13+
parser.add_argument("-d", dest="daemon", action="store_true", help="Daemon mode, no logging to console.")
14+
parser.add_argument("--logdir", default=None, help="Folder where logfiles should be stored.")
15+
parser.add_argument("--colorlog", default=False, type=arg_str2bool, help="Color logs for terminal output.")
16+
17+
18+
def setup_daemon(args, name):
19+
if args.daemon is False:
20+
simplelogging.logsetup.setup_console(color=args.colorlog)
21+
22+
if args.logdir is not None:
23+
simplelogging.logsetup.setup_file(name, logdir=args.logdir)
24+
elif args.daemon:
25+
print "WARNING Logging not configured!"
26+
print args

simpledaemonlog/logsetup.py

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
"""logsetup.py: A simple python logging setup for console and local log files."""
2+
3+
import os
4+
import time
5+
import sys
6+
import logging.config
7+
import logging.handlers
8+
import yaml
9+
10+
import logging
11+
log = logging.getLogger(__name__)
12+
13+
14+
__author__ = 'Raido Pahtma'
15+
__license__ = "MIT"
16+
17+
18+
DEFAULT_FORMAT_STRING = '%(asctime)s|%(levelname)8s|%(module)20s|%(lineno)4s| %(message)s'
19+
COLORED_FORMAT_STRING = '%(log_color)s%(asctime)s%(reset)s|%(module)20s|%(lineno)4s| %(log_color)s%(message)s'
20+
21+
22+
class StdLogger(object):
23+
def __init__(self, out, log):
24+
self._out = out
25+
self._log = log
26+
self.isatty = sys.__stdout__.isatty()
27+
28+
def _wrt_flt_std_log(self, txt):
29+
if len(txt) > 0:
30+
self._log(txt)
31+
32+
def write(self, txt):
33+
self._out.write(txt)
34+
self._wrt_flt_std_log(txt.rstrip())
35+
36+
37+
class PrintfFilter(object):
38+
39+
def filter(self, record):
40+
if record.funcName == "_wrt_flt_std_log":
41+
return 0
42+
else:
43+
return True
44+
45+
46+
def _load_settings(path=None):
47+
if path is not None and os.path.exists(path):
48+
with open(path, 'rt') as f:
49+
config = yaml.load(f.read())
50+
logging.config.dictConfig(config)
51+
return path
52+
return None
53+
54+
55+
def setup_console(level=logging.NOTSET, fs=DEFAULT_FORMAT_STRING, settings=None, color=False):
56+
loaded = _load_settings(settings)
57+
58+
console = logging.StreamHandler()
59+
console.addFilter(PrintfFilter())
60+
61+
if color:
62+
""" https://pypi.python.org/pypi/colorlog """
63+
from colorlog import ColoredFormatter
64+
formatter = ColoredFormatter(
65+
COLORED_FORMAT_STRING, datefmt=None, reset=True,
66+
log_colors={
67+
#'DEBUG': 'cyan',
68+
'INFO': 'white',
69+
'WARNING': 'yellow',
70+
'ERROR': 'red',
71+
'CRITICAL': 'red,bg_white',
72+
},
73+
secondary_log_colors={},
74+
style='%'
75+
)
76+
else:
77+
formatter = logging.Formatter(fs)
78+
79+
console.setFormatter(formatter)
80+
console.setLevel(level)
81+
82+
rootlogger = logging.getLogger("")
83+
rootlogger.setLevel(min(level, rootlogger.getEffectiveLevel()))
84+
rootlogger.addHandler(console)
85+
if loaded:
86+
log.debug("logging config loaded from {:s}".format(loaded))
87+
88+
89+
def setup_file(application_name, logdir="log", level=logging.NOTSET, fs=DEFAULT_FORMAT_STRING, settings=None, backups=8):
90+
"""
91+
Directs printf to file with INFO level.
92+
"""
93+
if not os.path.isdir(logdir):
94+
os.makedirs(logdir)
95+
96+
loaded = _load_settings(settings)
97+
98+
utc = time.gmtime()
99+
ts = time.strftime("%Y%m%d_%H%M%S%Z", utc)
100+
101+
logfilename = "log_{}_{}.txt".format(application_name, ts)
102+
loglatest = "log_{}_latest.txt".format(application_name)
103+
logfilepath = os.path.join(logdir, logfilename)
104+
loglinkpath = os.path.join(logdir, loglatest)
105+
logfile = logging.handlers.TimedRotatingFileHandler(logfilepath, when="W6", backupCount=backups)
106+
107+
if os.path.islink(loglinkpath):
108+
os.unlink(loglinkpath)
109+
110+
if hasattr(os, "symlink"):
111+
os.symlink(logfilename, loglinkpath)
112+
113+
formatter = logging.Formatter(fs)
114+
logfile.setFormatter(formatter)
115+
logfile.setLevel(level)
116+
117+
rootlogger = logging.getLogger("")
118+
rootlogger.setLevel(min(level, rootlogger.getEffectiveLevel()))
119+
rootlogger.addHandler(logfile)
120+
121+
sys.stderr = StdLogger(sys.stderr, logging.error)
122+
sys.stdout = StdLogger(sys.stdout, logging.info)
123+
if loaded:
124+
log.debug("logging config loaded from {:s}".format(loaded))
125+
126+
127+
if __name__ == "__main__":
128+
setup_console()
129+
setup_file("logsetup_test")
130+
131+
log = logging.getLogger(__name__)
132+
133+
log.debug("Some debug")
134+
log.info("A piece of info")
135+
log.warning("A small warning")
136+
log.error("A big error")
137+
log.critical("A critical message")
138+
139+
try:
140+
raise TypeError("An ugly TypeError")
141+
except TypeError:
142+
log.exception("The description of an exception")
143+
144+
print("The fine print")

0 commit comments

Comments
 (0)