1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
# Copyright 2014 Mirantis Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import six
import webob.dec
from osprofiler import _utils as utils
from osprofiler import profiler
# Trace keys that are required or optional, any other
# keys that are present will cause the trace to be rejected...
_REQUIRED_KEYS = ("base_id", "hmac_key")
_OPTIONAL_KEYS = ("parent_id",)
def get_trace_id_headers():
"""Adds the trace id headers (and any hmac) into provided dictionary."""
p = profiler.get()
if p and p.hmac_key:
data = {"base_id": p.get_base_id(), "parent_id": p.get_id()}
pack = utils.signed_pack(data, p.hmac_key)
return {
"X-Trace-Info": pack[0],
"X-Trace-HMAC": pack[1]
}
return {}
_DISABLED = False
_HMAC_KEYS = None
def disable():
"""Disable middleware.
This is the alternative way to disable middleware. It will be used to be
able to disable middleware via oslo.config.
"""
global _DISABLED
_DISABLED = True
def enable(hmac_keys=None):
"""Enable middleware."""
global _DISABLED, _HMAC_KEYS
_DISABLED = False
_HMAC_KEYS = utils.split(hmac_keys or "")
class WsgiMiddleware(object):
"""WSGI Middleware that enables tracing for an application."""
def __init__(self, application, hmac_keys=None, enabled=False):
"""Initialize middleware with api-paste.ini arguments.
:application: wsgi app
:hmac_keys: Only trace header that was signed with one of these
hmac keys will be processed. This limitation is
essential, because it allows to profile OpenStack
by only those who knows this key which helps
avoid DDOS.
:enabled: This middleware can be turned off fully if enabled is False.
"""
self.application = application
self.name = "wsgi"
self.enabled = enabled
self.hmac_keys = utils.split(hmac_keys or "")
@classmethod
def factory(cls, global_conf, **local_conf):
def filter_(app):
return cls(app, **local_conf)
return filter_
def _trace_is_valid(self, trace_info):
if not isinstance(trace_info, dict):
return False
trace_keys = set(six.iterkeys(trace_info))
if not all(k in trace_keys for k in _REQUIRED_KEYS):
return False
if trace_keys.difference(_REQUIRED_KEYS + _OPTIONAL_KEYS):
return False
return True
@webob.dec.wsgify
def __call__(self, request):
if _DISABLED or not self.enabled:
return request.get_response(self.application)
trace_info = utils.signed_unpack(request.headers.get("X-Trace-Info"),
request.headers.get("X-Trace-HMAC"),
_HMAC_KEYS or self.hmac_keys)
if not self._trace_is_valid(trace_info):
return request.get_response(self.application)
profiler.init(**trace_info)
info = {
"request": {
"host_url": request.host_url,
"path": request.path,
"query": request.query_string,
"method": request.method,
"scheme": request.scheme
}
}
with profiler.Trace(self.name, info=info):
return request.get_response(self.application)
|