Line data Source code
1 : // Licensed under the Apache License, Version 2.0
2 : // Copyright 2025, Michael Bushe, All rights reserved.
3 :
4 : import 'package:dartastic_opentelemetry_api/dartastic_opentelemetry_api.dart';
5 :
6 : /// Aggregation defines how measurements for a metric are aggregated.
7 : enum AggregationType {
8 : /// Sum aggregation accumulates the sum of measurements.
9 : sum,
10 :
11 : /// LastValue aggregation stores the last reported value.
12 : lastValue,
13 :
14 : /// Histogram aggregation computes statistics over measurements.
15 : histogram,
16 :
17 : /// Drop aggregation discards all measurements.
18 : drop,
19 :
20 : /// Default aggregation selects the appropriate aggregation based on instrument type.
21 : defaultAggregation,
22 : }
23 :
24 : /// View allows for customizing how metrics are collected and exported.
25 : ///
26 : /// A View can:
27 : /// - Filter which instruments are processed
28 : /// - Customize aggregation
29 : /// - Specify which attributes to include
30 : /// - Rename metrics
31 : class View {
32 : /// The name to use for the metric stream.
33 : /// If null, the original instrument name is used.
34 : final String? name;
35 :
36 : /// The description to use for the metric.
37 : /// If null, the original instrument description is used.
38 : final String? description;
39 :
40 : /// The instrument name pattern to match.
41 : /// Supports * as a wildcard.
42 : final String instrumentNamePattern;
43 :
44 : /// The instrument type to match.
45 : /// If null, all instrument types are matched.
46 : final Type? instrumentType;
47 :
48 : /// The meter name to match.
49 : /// If null, all meter names are matched.
50 : final String? meterName;
51 :
52 : /// The aggregation type to use.
53 : final AggregationType aggregationType;
54 :
55 : /// The attributes to include.
56 : /// If null, all attributes are included.
57 : final List<String>? attributeKeys;
58 :
59 : /// Creates a new View.
60 : ///
61 : /// [instrumentNamePattern] The pattern to match instrument names against.
62 : /// Use * as a wildcard to match multiple instruments.
63 3 : View({
64 : this.name,
65 : this.description,
66 : required this.instrumentNamePattern,
67 : this.instrumentType,
68 : this.meterName,
69 : this.aggregationType = AggregationType.defaultAggregation,
70 : this.attributeKeys,
71 : });
72 :
73 : /// Creates a view that matches all instruments.
74 1 : factory View.all({
75 : String? name,
76 : String? description,
77 : AggregationType aggregationType = AggregationType.defaultAggregation,
78 : List<String>? attributeKeys,
79 : }) {
80 1 : return View(
81 : name: name,
82 : description: description,
83 : instrumentNamePattern: '*',
84 : aggregationType: aggregationType,
85 : attributeKeys: attributeKeys,
86 : );
87 : }
88 :
89 : /// Checks if this view matches the given instrument.
90 0 : bool matches(String instrumentName, APIInstrument instrument) {
91 : // Check instrument name pattern
92 0 : if (!_matchesPattern(instrumentName, instrumentNamePattern)) {
93 : return false;
94 : }
95 :
96 : // Check instrument type if specified
97 0 : if (instrumentType != null) {
98 0 : if (instrumentType == APICounter && !_isCounter(instrument)) {
99 : return false;
100 0 : } else if (instrumentType == APIUpDownCounter &&
101 0 : !_isUpDownCounter(instrument)) {
102 : return false;
103 0 : } else if (instrumentType == APIHistogram && !_isHistogram(instrument)) {
104 : return false;
105 0 : } else if (instrumentType == APIGauge && !_isGauge(instrument)) {
106 : return false;
107 0 : } else if (instrumentType == APIObservableCounter &&
108 0 : !_isObservableCounter(instrument)) {
109 : return false;
110 0 : } else if (instrumentType == APIObservableUpDownCounter &&
111 0 : !_isObservableUpDownCounter(instrument)) {
112 : return false;
113 0 : } else if (instrumentType == APIObservableGauge &&
114 0 : !_isObservableGauge(instrument)) {
115 : return false;
116 : }
117 : }
118 :
119 : // Check meter name if specified
120 0 : if (meterName != null && meterName != instrument.meter.name) {
121 : return false;
122 : }
123 :
124 : return true;
125 : }
126 :
127 0 : bool _matchesPattern(String name, String pattern) {
128 0 : if (pattern == '*') {
129 : return true;
130 : }
131 :
132 : // Simple pattern matching for * wildcards
133 0 : if (pattern.contains('*')) {
134 0 : final regex = RegExp('^${pattern.replaceAll('*', '.*')}\$');
135 0 : return regex.hasMatch(name);
136 : }
137 :
138 0 : return name == pattern;
139 : }
140 :
141 0 : bool _isCounter(APIInstrument instrument) {
142 0 : return instrument is APICounter;
143 : }
144 :
145 0 : bool _isUpDownCounter(APIInstrument instrument) {
146 0 : return instrument is APIUpDownCounter;
147 : }
148 :
149 0 : bool _isHistogram(APIInstrument instrument) {
150 0 : return instrument is APIHistogram;
151 : }
152 :
153 0 : bool _isGauge(APIInstrument instrument) {
154 0 : return instrument is APIGauge;
155 : }
156 :
157 0 : bool _isObservableCounter(APIInstrument instrument) {
158 0 : return instrument is APIObservableCounter;
159 : }
160 :
161 0 : bool _isObservableUpDownCounter(APIInstrument instrument) {
162 0 : return instrument is APIObservableUpDownCounter;
163 : }
164 :
165 0 : bool _isObservableGauge(APIInstrument instrument) {
166 0 : return instrument is APIObservableGauge;
167 : }
168 : }
|