context.py 5.4 KB
Newer Older
K
kezhenxu94 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
#
# 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.
#

18
import logging
K
kezhenxu94 已提交
19 20 21
import threading
from typing import List

H
huawei 已提交
22
from skywalking import agent, config
23
from skywalking.trace.carrier import Carrier
K
kezhenxu94 已提交
24 25 26 27
from skywalking.trace.segment import Segment
from skywalking.trace.span import Span, Kind, NoopSpan, EntrySpan, ExitSpan
from skywalking.utils.counter import Counter

28 29
logger = logging.getLogger(__name__)

K
kezhenxu94 已提交
30 31 32

class SpanContext(object):
    def __init__(self):
K
kezhenxu94 已提交
33 34
        self.spans = []  # type: List[Span]
        self.segment = Segment()  # type: Segment
K
kezhenxu94 已提交
35
        self._sid = Counter()
36
        self._correlation = {}  # type: dict
K
kezhenxu94 已提交
37 38

    def new_local_span(self, op: str) -> Span:
H
huawei 已提交
39 40 41 42
        span = self.ignore_check(op, Kind.Local)
        if span is not None:
            return span

K
kezhenxu94 已提交
43
        parent = self.spans[-1] if self.spans else None  # type: Span
K
kezhenxu94 已提交
44 45 46 47

        return Span(
            context=self,
            sid=self._sid.next(),
48
            pid=parent.sid if parent else -1,
K
kezhenxu94 已提交
49 50 51 52
            op=op,
            kind=Kind.Local,
        )

53
    def new_entry_span(self, op: str, carrier: 'Carrier' = None) -> Span:
H
huawei 已提交
54 55 56 57
        span = self.ignore_check(op, Kind.Entry)
        if span is not None:
            return span

K
kezhenxu94 已提交
58
        parent = self.spans[-1] if self.spans else None  # type: Span
K
kezhenxu94 已提交
59

60
        span = parent if parent is not None and parent.kind.is_entry else EntrySpan(
K
kezhenxu94 已提交
61 62
            context=self,
            sid=self._sid.next(),
63
            pid=parent.sid if parent else -1,
K
kezhenxu94 已提交
64
        )
65
        span.op = op
K
kezhenxu94 已提交
66

67
        if carrier is not None and carrier.is_valid:
68
            span.extract(carrier=carrier)
K
kezhenxu94 已提交
69

70
        return span
K
kezhenxu94 已提交
71

72
    def new_exit_span(self, op: str, peer: str, carrier: 'Carrier' = None) -> Span:
H
huawei 已提交
73 74 75 76
        span = self.ignore_check(op, Kind.Exit)
        if span is not None:
            return span

77
        parent = self.spans[-1] if self.spans else None  # type: Span
K
kezhenxu94 已提交
78

79
        span = parent if parent is not None and parent.kind.is_exit else ExitSpan(
K
kezhenxu94 已提交
80 81
            context=self,
            sid=self._sid.next(),
82
            pid=parent.sid if parent else -1,
K
kezhenxu94 已提交
83 84 85 86
            op=op,
            peer=peer,
        )

87 88 89 90 91
        if carrier is not None:
            span.inject(carrier=carrier)

        return span

H
huawei 已提交
92 93 94 95 96 97 98 99 100
    def ignore_check(self, op: str, kind: Kind):
        suffix_idx = op.rfind(".")
        if suffix_idx > -1 and config.ignore_suffix.find(op[suffix_idx:]) > -1:
            return NoopSpan(
                context=NoopContext(),
                kind=kind,
            )
        return None

K
kezhenxu94 已提交
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115
    def start(self, span: Span):
        if span not in self.spans:
            self.spans.append(span)

    def stop(self, span: Span) -> bool:
        assert span is self.spans[-1]

        span.finish(self.segment) and self.spans.pop()

        if len(self.spans) == 0:
            _thread_local.context = None
            agent.archive(self.segment)

        return len(self.spans) == 0

H
huawei 已提交
116 117 118 119 120 121
    def active_span(self):
        if self.spans:
            return self.spans[len(self.spans) - 1]

        return None

122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139
    def get_correlation(self, key):
        if key in self._correlation:
            return self._correlation[key]
        return None

    def put_correlation(self, key, value):
        if key is None:
            return
        if value is None:
            self._correlation.pop(key, value)
            return
        if len(value) > config.correlation_value_max_length:
            return
        if len(self._correlation) > config.correlation_element_max_number:
            return

        self._correlation[key] = value

K
kezhenxu94 已提交
140 141 142 143 144 145

class NoopContext(SpanContext):
    def __init__(self):
        super().__init__()
        self._depth = 0
        self._noop_span = NoopSpan(self, kind=Kind.Local)
146
        self.correlation = {}  # type: dict
K
kezhenxu94 已提交
147 148 149 150 151

    def new_local_span(self, op: str) -> Span:
        self._depth += 1
        return self._noop_span

152
    def new_entry_span(self, op: str, carrier: 'Carrier' = None) -> Span:
K
kezhenxu94 已提交
153
        self._depth += 1
154 155
        if carrier is not None:
            self._noop_span.extract(carrier)
K
kezhenxu94 已提交
156 157
        return self._noop_span

158
    def new_exit_span(self, op: str, peer: str, carrier: 'Carrier' = None) -> Span:
K
kezhenxu94 已提交
159
        self._depth += 1
160 161 162
        if carrier is not None:
            self._noop_span.inject(carrier)

K
kezhenxu94 已提交
163 164 165 166 167 168
        return self._noop_span

    def stop(self, span: Span) -> bool:
        self._depth -= 1
        return self._depth == 0

H
huawei 已提交
169 170 171
    def active_span(self):
        return self._noop_span

K
kezhenxu94 已提交
172 173 174 175 176

_thread_local = threading.local()
_thread_local.context = None


177
def get_context() -> SpanContext:
178 179
    if not hasattr(_thread_local, 'context'):
        _thread_local.context = None
180
    _thread_local.context = _thread_local.context or (SpanContext() if agent.connected() else NoopContext())
K
kezhenxu94 已提交
181 182

    return _thread_local.context