Completed
Push — master ( 0bc61b...16fc24 )
by Thomas
8s
created

doorpi.init_logger()   A

Complexity

Conditions 3

Size

Total Lines 14

Duplication

Lines 0
Ratio 0 %
Metric Value
cc 3
dl 0
loc 14
rs 9.4285
1
#!/usr/bin/python
2
# -*- coding: utf-8 -*-
3
4
import argparse
5
import sys
6
import logging
7
import logging.handlers
8
import os
9
import metadata
10
import doorpi
11
from resource import getrlimit, RLIMIT_NOFILE
12
13
TRACE_LEVEL = 5
14
LOG_FORMAT = '%(asctime)s [%(levelname)s]  \t[%(name)s] %(message)s'
15
16
logger = logging.getLogger(__name__)
17
18
log_level = logging.INFO
19
20
21
def add_trace_level():
22
    logging.addLevelName(TRACE_LEVEL, "TRACE")
23
    def trace(self, message, *args, **kws):
24
        # Yes, logger takes its '*args' as 'args'.
25
        self._log(TRACE_LEVEL, message, args, **kws)
26
    logging.Logger.trace = trace
27
28
29
def init_logger(arguments):
30
    add_trace_level()
31
32
    global log_level
0 ignored issues
show
Coding Style introduced by Thomas Meissner
Usage of the global statement should be avoided.

Usage of global can make code hard to read and test, its usage is generally not recommended unless you are dealing with legacy code.

Loading history...
33
    if '--debug' in arguments: log_level = logging.DEBUG
34
    if '--trace' in arguments: log_level = TRACE_LEVEL
35
36
    logging.basicConfig(
37
        level = log_level,
38
        format = LOG_FORMAT
39
    #    datefmt = '%m/%d/%Y %I:%M:%S %p'
40
    )
41
42
    return logging.getLogger(__name__)
43
44
45
def parse_arguments(argv):
46
    arg_parser = argparse.ArgumentParser(
47
        prog=argv[0],
48
        formatter_class=argparse.RawDescriptionHelpFormatter,
49
        description=metadata.description,
50
        epilog = metadata.epilog
51
    )
52
53
    arg_parser.add_argument(
54
        '-V', '--version',
55
        action='version',
56
        version='{0} {1}'.format(metadata.project, metadata.version)
57
    )
58
    arg_parser.add_argument('--debug', action="store_true")
59
    arg_parser.add_argument('--trace', action="store_true")
60
    arg_parser.add_argument('--test', action="store_true")
61
    arg_parser.add_argument(
62
        '-c', '--configfile',
63
        help='configfile for DoorPi - https://github.com/motom001/DoorPi/wiki for more help',
64
        dest='configfile'
65
    )
66
    try:
67
        if len(sys.argv) > 1 and sys.argv[1] in ['start', 'stop', 'restart', 'status']:
68
            return arg_parser.parse_args(args=sys.argv[2:])
69
        else:
70
            return arg_parser.parse_args(args=sys.argv[1:])
71
    except IOError:
72
        print("EXCEPTION: configfile does not exist or is not readable")
73
        print("please refer to the DoorPi wiki for more information ")
74
        print("<https://github.com/motom001/DoorPi/wiki>")
75
        raise SystemExit(1)
76
77
78
def files_preserve_by_path(*paths):
79
    wanted = []
80
    for path in paths:
81
        fd = os.open(path, os.O_RDONLY)
82
        try:
83
            wanted.append(os.fstat(fd)[1:3])
84
        finally:
85
            os.close(fd)
86
87
    def fd_wanted(fd):
88
        try:
89
            return os.fstat(fd)[1:3] in wanted
90
        except OSError:
91
            return False
92
93
    fd_max = getrlimit(RLIMIT_NOFILE)[1]
94
    return [fd for fd in xrange(fd_max) if fd_wanted(fd)]
0 ignored issues
show
Comprehensibility Best Practice introduced by Thomas Meissner
Undefined variable 'xrange'
Loading history...
95
96
97
def main_as_daemon(argv):
98
    if argv[1] is 'reload':
99
        print('not implemeted yet - use restart instead')
100
        return 1
101
    if argv[1] in ['stop']:
102
        parsed_arguments = None
103
    else:
104
        parsed_arguments = parse_arguments(argv)
105
106
    if not os.path.exists(metadata.log_folder):
107
        os.makedirs(metadata.log_folder)
108
109
    log_file = os.path.join(metadata.log_folder, "doorpi.log")
110
    logrotating = logging.handlers.RotatingFileHandler(
111
          log_file,
112
          maxBytes=5000000,
113
          backupCount=10
114
    )
115
    global log_level
0 ignored issues
show
Unused Code introduced by Thomas Meissner
The variable log_level was imported from global scope, but was never written to.
Loading history...
116
    logrotating.setLevel(log_level)
117
    logrotating.setFormatter(logging.Formatter(LOG_FORMAT))
118
119
    logging.getLogger('').addHandler(logrotating)
120
121
    print(metadata.epilog)
122
123
    from daemon import runner
0 ignored issues
show
Bug introduced by Thomas Meissner
The name runner does not seem to exist in module daemon.
Loading history...
124
    from daemon.runner import DaemonRunnerInvalidActionError
0 ignored issues
show
Bug introduced by Thomas Meissner
The name runner does not seem to exist in module daemon.
Loading history...
Unused Code introduced by Thomas Meissner
The variable DaemonRunnerInvalidActionError seems to be unused.
Loading history...
125
    from daemon.runner import DaemonRunnerStartFailureError
0 ignored issues
show
Bug introduced by Thomas Meissner
The name runner does not seem to exist in module daemon.
Loading history...
126
    from daemon.runner import DaemonRunnerStopFailureError
0 ignored issues
show
Bug introduced by Thomas Meissner
The name runner does not seem to exist in module daemon.
Loading history...
127
128
    daemon_runner = runner.DaemonRunner(doorpi.DoorPi(parsed_arguments))
129
    #This ensures that the logger file handle does not get closed during daemonization
130
    daemon_runner.daemon_context.files_preserve = files_preserve_by_path(log_file)
131
    try:
132
        daemon_runner.do_action()
133
    except DaemonRunnerStopFailureError as ex:
134
        print("can't stop DoorPi daemon - maybe it's not running? (Message: %s)" % ex)
135
        return 1
136
    except DaemonRunnerStartFailureError as ex:
137
        print("can't start DoorPi daemon - maybe it's running already? (Message: %s)" % ex)
138
        return 1
139
    except Exception as ex:
140
        print("Exception NameError: %s" % ex)
141
    finally:
142
        doorpi.DoorPi().destroy()
143
    return 0
144
145
146
def main_as_application(argv):
147
148
    parsed_arguments = parse_arguments(argv)
149
    logger.info(metadata.epilog)
150
    logger.debug('loaded with arguments: %s', str(argv))
151
152
    try:                        doorpi.DoorPi(parsed_arguments).run()
153
    except KeyboardInterrupt:   logger.info("KeyboardInterrupt -> DoorPi will shutdown")
154
    except Exception as ex:     logger.exception("Exception NameError: %s", ex)
155
    finally:                    doorpi.DoorPi().destroy()
156
157
    return 0
158
159
160
def entry_point():
161
    init_logger(sys.argv)
162
163
    """Zero-argument entry point for use with setuptools/distribute."""
164
    if len(sys.argv) > 1 and sys.argv[1] in ['status']:
165
        raise SystemExit(get_status_from_doorpi(sys.argv))
0 ignored issues
show
Comprehensibility Best Practice introduced by Thomas Meissner
Undefined variable 'get_status_from_doorpi'
Loading history...
166
    elif len(sys.argv) > 1 and sys.argv[1] in ['start', 'stop', 'restart', 'reload']:
167
        raise SystemExit(main_as_daemon(sys.argv))
168
    else:
169
        raise SystemExit(main_as_application(sys.argv))
170
171
if __name__ == '__main__':
172
    entry_point()
173