aboutsummaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/opentelemetry/sdk/metrics/_internal/view.py
blob: b3fa029d6c78a326517222ca87267bc101d1458c (about) (plain)
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
# Copyright The OpenTelemetry Authors
#
# 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.


from fnmatch import fnmatch
from logging import getLogger
from typing import Callable, Optional, Set, Type

from opentelemetry.metrics import Instrument
from opentelemetry.sdk.metrics._internal.aggregation import (
    Aggregation,
    DefaultAggregation,
    _Aggregation,
    _ExplicitBucketHistogramAggregation,
    _ExponentialBucketHistogramAggregation,
)
from opentelemetry.sdk.metrics._internal.exemplar import (
    AlignedHistogramBucketExemplarReservoir,
    ExemplarReservoirBuilder,
    SimpleFixedSizeExemplarReservoir,
)

_logger = getLogger(__name__)


def _default_reservoir_factory(
    aggregation_type: Type[_Aggregation],
) -> ExemplarReservoirBuilder:
    """Default reservoir factory per aggregation."""
    if issubclass(aggregation_type, _ExplicitBucketHistogramAggregation):
        return AlignedHistogramBucketExemplarReservoir
    if issubclass(aggregation_type, _ExponentialBucketHistogramAggregation):
        return SimpleFixedSizeExemplarReservoir
    return SimpleFixedSizeExemplarReservoir


class View:
    """
    A `View` configuration parameters can be used for the following
    purposes:

    1. Match instruments: When an instrument matches a view, measurements
       received by that instrument will be processed.
    2. Customize metric streams: A metric stream is identified by a match
       between a view and an instrument and a set of attributes. The metric
       stream can be customized by certain attributes of the corresponding view.

    The attributes documented next serve one of the previous two purposes.

    Args:
        instrument_type: This is an instrument matching attribute: the class the
            instrument must be to match the view.

        instrument_name: This is an instrument matching attribute: the name the
            instrument must have to match the view. Wild card characters are supported. Wild
            card characters should not be used with this attribute if the view has also a
            ``name`` defined.

        meter_name: This is an instrument matching attribute: the name the
            instrument meter must have to match the view.

        meter_version: This is an instrument matching attribute: the version
            the instrument meter must have to match the view.

        meter_schema_url: This is an instrument matching attribute: the schema
            URL the instrument meter must have to match the view.

        name: This is a metric stream customizing attribute: the name of the
            metric stream. If `None`, the name of the instrument will be used.

        description: This is a metric stream customizing attribute: the
            description of the metric stream. If `None`, the description of the instrument will
            be used.

        attribute_keys: This is a metric stream customizing attribute: this is
            a set of attribute keys. If not `None` then only the measurement attributes that
            are in ``attribute_keys`` will be used to identify the metric stream.

        aggregation: This is a metric stream customizing attribute: the
            aggregation instance to use when data is aggregated for the
            corresponding metrics stream. If `None` an instance of
            `DefaultAggregation` will be used.

        exemplar_reservoir_factory: This is a metric stream customizing attribute:
            the exemplar reservoir factory

        instrument_unit: This is an instrument matching attribute: the unit the
            instrument must have to match the view.

    This class is not intended to be subclassed by the user.
    """

    _default_aggregation = DefaultAggregation()

    def __init__(
        self,
        instrument_type: Optional[Type[Instrument]] = None,
        instrument_name: Optional[str] = None,
        meter_name: Optional[str] = None,
        meter_version: Optional[str] = None,
        meter_schema_url: Optional[str] = None,
        name: Optional[str] = None,
        description: Optional[str] = None,
        attribute_keys: Optional[Set[str]] = None,
        aggregation: Optional[Aggregation] = None,
        exemplar_reservoir_factory: Optional[
            Callable[[Type[_Aggregation]], ExemplarReservoirBuilder]
        ] = None,
        instrument_unit: Optional[str] = None,
    ):
        if (
            instrument_type
            is instrument_name
            is instrument_unit
            is meter_name
            is meter_version
            is meter_schema_url
            is None
        ):
            # pylint: disable=broad-exception-raised
            raise Exception(
                "Some instrument selection "
                f"criteria must be provided for View {name}"
            )

        if (
            name is not None
            and instrument_name is not None
            and ("*" in instrument_name or "?" in instrument_name)
        ):
            # pylint: disable=broad-exception-raised
            raise Exception(
                f"View {name} declared with wildcard "
                "characters in instrument_name"
            )

        # _name, _description, _aggregation, _exemplar_reservoir_factory and
        # _attribute_keys will be accessed when instantiating a _ViewInstrumentMatch.
        self._name = name
        self._instrument_type = instrument_type
        self._instrument_name = instrument_name
        self._instrument_unit = instrument_unit
        self._meter_name = meter_name
        self._meter_version = meter_version
        self._meter_schema_url = meter_schema_url

        self._description = description
        self._attribute_keys = attribute_keys
        self._aggregation = aggregation or self._default_aggregation
        self._exemplar_reservoir_factory = (
            exemplar_reservoir_factory or _default_reservoir_factory
        )

    # pylint: disable=too-many-return-statements
    # pylint: disable=too-many-branches
    def _match(self, instrument: Instrument) -> bool:
        if self._instrument_type is not None:
            if not isinstance(instrument, self._instrument_type):
                return False

        if self._instrument_name is not None:
            if not fnmatch(instrument.name, self._instrument_name):
                return False

        if self._instrument_unit is not None:
            if not fnmatch(instrument.unit, self._instrument_unit):
                return False

        if self._meter_name is not None:
            if instrument.instrumentation_scope.name != self._meter_name:
                return False

        if self._meter_version is not None:
            if instrument.instrumentation_scope.version != self._meter_version:
                return False

        if self._meter_schema_url is not None:
            if (
                instrument.instrumentation_scope.schema_url
                != self._meter_schema_url
            ):
                return False

        return True