context.py 6.8 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 import ID
24
from skywalking.trace.carrier import Carrier
25 26
from skywalking.trace.segment import Segment, SegmentRef
from skywalking.trace.snapshot import Snapshot
K
kezhenxu94 已提交
27
from skywalking.trace.span import Span, Kind, NoopSpan, EntrySpan, ExitSpan
H
huawei 已提交
28
from skywalking.utils.ant_matcher import fast_path_match
K
kezhenxu94 已提交
29 30
from skywalking.utils.counter import Counter

31 32
logger = logging.getLogger(__name__)

K
kezhenxu94 已提交
33 34 35

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

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

K
kezhenxu94 已提交
46
        parent = self.spans[-1] if self.spans else None  # type: Span
K
kezhenxu94 已提交
47 48 49 50

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

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

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

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

70
        if carrier is not None and carrier.is_valid:
71
            span.extract(carrier=carrier)
K
kezhenxu94 已提交
72

73
        return span
K
kezhenxu94 已提交
74

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

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

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

90 91 92 93 94
        if carrier is not None:
            span.inject(carrier=carrier)

        return span

H
huawei 已提交
95 96 97 98 99 100 101
    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,
            )
H
huawei 已提交
102 103 104 105 106 107 108 109
        if config.trace_ignore:
            for pattern in config.trace_ignore_path:
                if fast_path_match(pattern, op):
                    return NoopSpan(
                        context=NoopContext(),
                        kind=kind,
                    )

H
huawei 已提交
110 111
        return None

K
kezhenxu94 已提交
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
    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 已提交
127 128 129 130 131 132
    def active_span(self):
        if self.spans:
            return self.spans[len(self.spans) - 1]

        return None

133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
    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

151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172
    def capture(self):
        if len(self.spans) == 0:
            return None

        return Snapshot(
            segment_id=str(self.segment.segment_id),
            span_id=self.active_span().sid,
            trace_id=self.segment.related_traces[0],
            endpoint=self.spans[0].op,
            correlation=self._correlation,
        )

    def continued(self, snapshot: 'Snapshot'):
        if snapshot is None:
            return None
        if not snapshot.is_from_current(self) and snapshot.is_valid():
            ref = SegmentRef.build_ref(snapshot)
            span = self.active_span()
            span.refs.append(ref)
            self.segment.relate(ID(ref.trace_id))
            self._correlation.update(snapshot.correlation)

K
kezhenxu94 已提交
173 174 175 176 177 178

class NoopContext(SpanContext):
    def __init__(self):
        super().__init__()
        self._depth = 0
        self._noop_span = NoopSpan(self, kind=Kind.Local)
179
        self.correlation = {}  # type: dict
K
kezhenxu94 已提交
180 181 182 183 184

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

185
    def new_entry_span(self, op: str, carrier: 'Carrier' = None) -> Span:
K
kezhenxu94 已提交
186
        self._depth += 1
187 188
        if carrier is not None:
            self._noop_span.extract(carrier)
K
kezhenxu94 已提交
189 190
        return self._noop_span

191
    def new_exit_span(self, op: str, peer: str, carrier: 'Carrier' = None) -> Span:
K
kezhenxu94 已提交
192
        self._depth += 1
193 194 195
        if carrier is not None:
            self._noop_span.inject(carrier)

K
kezhenxu94 已提交
196 197 198 199 200 201
        return self._noop_span

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

H
huawei 已提交
202 203 204
    def active_span(self):
        return self._noop_span

205 206 207 208 209 210 211 212 213 214 215 216
    def capture(self):
        return Snapshot(
            segment_id=None,
            span_id=-1,
            trace_id=None,
            endpoint=None,
            correlation=self._correlation,
        )

    def continued(self, snapshot: 'Snapshot'):
        self._correlation.update(snapshot.correlation)

K
kezhenxu94 已提交
217 218 219 220 221

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


222
def get_context() -> SpanContext:
223 224
    if not hasattr(_thread_local, 'context'):
        _thread_local.context = None
225
    _thread_local.context = _thread_local.context or (SpanContext() if agent.connected() else NoopContext())
K
kezhenxu94 已提交
226 227

    return _thread_local.context