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 : import '../../otel.dart';
6 : import 'sampler.dart';
7 :
8 : /// A sampler that combines multiple samplers using a specified operation.
9 : class CompositeSampler implements Sampler {
10 : final List<Sampler> _samplers;
11 : final _Operation _operation;
12 :
13 0 : @override
14 : String get description =>
15 0 : 'CompositeSampler{${_operation.name},[${_samplers.map((s) => s.description).join(',')}]}';
16 :
17 : /// Creates a CompositeSampler that requires all samplers to accept.
18 1 : const CompositeSampler.and(List<Sampler> samplers)
19 1 : : this._(samplers, _Operation.and);
20 :
21 : /// Creates a CompositeSampler that requires any sampler to accept.
22 1 : const CompositeSampler.or(List<Sampler> samplers)
23 1 : : this._(samplers, _Operation.or);
24 :
25 1 : const CompositeSampler._(this._samplers, this._operation);
26 :
27 1 : @override
28 : SamplingResult shouldSample({
29 : required Context parentContext,
30 : required String traceId,
31 : required String name,
32 : required SpanKind spanKind,
33 : required Attributes? attributes,
34 : required List<SpanLink>? links,
35 : }) {
36 2 : if (_samplers.isEmpty) {
37 : return const SamplingResult(
38 : decision: SamplingDecision.recordAndSample,
39 : source: SamplingDecisionSource.tracerConfig,
40 : );
41 : }
42 :
43 : Attributes? combinedAttributes;
44 :
45 2 : for (final sampler in _samplers) {
46 1 : final result = sampler.shouldSample(
47 : parentContext: parentContext,
48 : traceId: traceId,
49 : name: name,
50 : spanKind: spanKind,
51 : attributes: attributes,
52 : links: links,
53 : );
54 :
55 : // For AND, if any sampler drops, return drop
56 : // For OR, if any sampler samples, return sample
57 2 : if (_operation == _Operation.and &&
58 2 : result.decision == SamplingDecision.drop) {
59 : return result;
60 2 : } else if (_operation == _Operation.or &&
61 2 : result.decision == SamplingDecision.recordAndSample) {
62 : return result;
63 : }
64 :
65 : // Combine attributes if present
66 1 : if (result.attributes != null) {
67 0 : combinedAttributes ?? OTel.attributes(); //TODO simplify
68 0 : combinedAttributes!.copyWithAttributes(result.attributes!);
69 : }
70 : }
71 :
72 : // For AND, all samplers accepted, return recordAndSample
73 : // For OR, no sampler accepted, return drop
74 1 : return SamplingResult(
75 2 : decision: _operation == _Operation.and
76 : ? SamplingDecision.recordAndSample
77 : : SamplingDecision.drop,
78 : source: SamplingDecisionSource.tracerConfig,
79 : attributes: combinedAttributes,
80 : );
81 : }
82 : }
83 :
84 : enum _Operation {
85 : and,
86 : or,
87 : }
|