blob: 21aeecd5c08f708d8a8dea43d60e3322bdfa025d [file] [log] [blame]
#
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You 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.
#
from skywalking import Layer, Component, config
from skywalking.trace.carrier import Carrier
from skywalking.trace.context import get_context, NoopContext
from skywalking.trace.span import NoopSpan
from skywalking.trace.tags import TagHttpMethod, TagHttpURL, TagHttpParams, TagHttpStatusCode, TagHttpStatusMsg
link_vector = ['https://falcon.readthedocs.io/en/stable/']
support_matrix = {
'hug': {
'>=3.11': [],
'>=3.10': ['2.5', '2.6'], # api deprecated for 3.10
'>=3.7': ['2.4.1', '2.5', '2.6'], # support begins 2.4.1
}
}
note = """While Falcon is instrumented, only Hug is tested.
Hug is believed to be abandoned project, use this plugin with a bit more caution.
Instead of Hug, plugin test should move to test actual Falcon."""
def install():
from falcon import API, request, RequestOptions
_original_falcon_api = API.__call__
def _sw_falcon_api(this: API, env, start_response):
context = get_context()
carrier = Carrier()
req = request.Request(env, RequestOptions())
headers = req.headers
method = req.method
for item in carrier:
key = item.key.upper()
if key in headers:
item.val = headers[key]
span = NoopSpan(NoopContext()) if config.ignore_http_method_check(method) \
else context.new_entry_span(op=req.path, carrier=carrier)
with span:
span.layer = Layer.Http
span.component = Component.Falcon
span.peer = req.remote_addr
span.tag(TagHttpMethod(method))
span.tag(TagHttpURL(str(req.url)))
if req.params:
span.tag(TagHttpParams(','.join([f'{k}={v}' for k, v in req.params.items()])))
def _start_response(resp_status, headers):
try:
code, msg = resp_status.split(' ', 1)
code = int(code)
except Exception:
code, msg = 500, 'Internal Server Error'
if code >= 400:
span.error_occurred = True
span.tag(TagHttpStatusCode(code))
span.tag(TagHttpStatusMsg(msg))
return start_response(resp_status, headers)
try:
return _original_falcon_api(this, env, _start_response)
except Exception:
span.raised()
raise
API.__call__ = _sw_falcon_api