Passed
Push — develop ( f534b1...a82689 )
by Plexxi
06:09 queued 03:13
created

LoggingMiddleware   A

Complexity

Total Complexity 8

Size/Duplication

Total Lines 69
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 69
rs 10
wmc 8

3 Methods

Rating   Name   Duplication   Size   Complexity  
C __call__() 0 60 7
A __init__() 0 3 1
A custom_start_response() 0 9 3
1
# Licensed to the StackStorm, Inc ('StackStorm') under one or more
2
# contributor license agreements.  See the NOTICE file distributed with
3
# this work for additional information regarding copyright ownership.
4
# The ASF licenses this file to You under the Apache License, Version 2.0
5
# (the "License"); you may not use this file except in compliance with
6
# the License.  You may obtain a copy of the License at
7
#
8
#     http://www.apache.org/licenses/LICENSE-2.0
9
#
10
# Unless required by applicable law or agreed to in writing, software
11
# distributed under the License is distributed on an "AS IS" BASIS,
12
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
# See the License for the specific language governing permissions and
14
# limitations under the License.
15
16
import time
17
import types
18
19
from st2common.constants.api import REQUEST_ID_HEADER
20
from st2common import log as logging
21
from st2common.router import Request
22
23
LOG = logging.getLogger(__name__)
24
25
try:
26
    clock = time.perf_counter
27
except AttributeError:
28
    clock = time.time
29
30
31
class LoggingMiddleware(object):
32
    """
33
    Logs all incoming requests and outgoing responses
34
    """
35
36
    def __init__(self, app, router):
37
        self.app = app
38
        self.router = router
39
40
    def __call__(self, environ, start_response):
41
        start_time = clock()
42
        status_code = []
43
        content_length = []
44
45
        request = Request(environ)
46
47
        # Log the incoming request
48
        values = {
49
            'method': request.method,
50
            'path': request.path,
51
            'remote_addr': request.remote_addr,
52
            'query': request.GET.dict_of_lists(),
53
            'request_id': request.headers.get(REQUEST_ID_HEADER, None)
54
        }
55
56
        LOG.info('%(request_id)s - %(method)s %(path)s with query=%(query)s' %
0 ignored issues
show
Coding Style Best Practice introduced by
Specify string format arguments as logging function parameters
Loading history...
57
                 values, extra=values)
58
59
        def custom_start_response(status, headers, exc_info=None):
60
            status_code.append(int(status.split(' ')[0]))
61
62
            for name, value in headers:
63
                if name.lower() == 'content-length':
64
                    content_length.append(int(value))
65
                    break
66
67
            return start_response(status, headers, exc_info)
68
69
        retval = self.app(environ, custom_start_response)
70
71
        endpoint, path_vars = self.router.match(request)
72
73
        log_result = endpoint.get('x-log-result', True)
74
75
        if isinstance(retval, types.GeneratorType):
76
            content_length = [float('inf')]
77
            log_result = False
78
79
        # Log the incoming request
80
        values = {
81
            'method': request.method,
82
            'path': request.path,
83
            'remote_addr': request.remote_addr,
84
            'status': status_code[0],
85
            'runtime': float("{0:.3f}".format((clock() - start_time) * 10**3)),
86
            'content_length': content_length[0] if content_length else len(b''.join(retval)),
87
            'request_id': request.headers.get(REQUEST_ID_HEADER, None)
88
        }
89
90
        if log_result:
91
            values['result'] = retval[0]
92
            log_msg = '%(request_id)s - %(status)s %(content_length)s %(runtime)sms\n%(result)s'\
93
                      % values
94
        else:
95
            log_msg = '%(request_id)s - %(status)s %(content_length)s %(runtime)sms' % values
96
97
        LOG.info(log_msg, extra=values)
98
99
        return retval
100