|
16 | 16 | package io.micrometer.registry.otlp;
|
17 | 17 |
|
18 | 18 | import io.micrometer.common.lang.Nullable;
|
| 19 | +import io.micrometer.common.util.StringUtils; |
19 | 20 | import io.micrometer.common.util.internal.logging.InternalLogger;
|
20 | 21 | import io.micrometer.common.util.internal.logging.InternalLoggerFactory;
|
21 |
| -import io.micrometer.core.instrument.Timer; |
22 | 22 | import io.micrometer.core.instrument.*;
|
| 23 | +import io.micrometer.core.instrument.Timer; |
23 | 24 | import io.micrometer.core.instrument.config.NamingConvention;
|
24 | 25 | import io.micrometer.core.instrument.distribution.*;
|
25 | 26 | import io.micrometer.core.instrument.distribution.pause.PauseDetector;
|
@@ -82,6 +83,10 @@ public class OtlpMeterRegistry extends PushMeterRegistry {
|
82 | 83 |
|
83 | 84 | private final OtlpMetricsSender metricsSender;
|
84 | 85 |
|
| 86 | + private final HistogramFlavorPerMeterLookup histogramFlavorPerMeterLookup; |
| 87 | + |
| 88 | + private final MaxBucketsPerMeterLookup maxBucketsPerMeterLookup; |
| 89 | + |
85 | 90 | private final Resource resource;
|
86 | 91 |
|
87 | 92 | private final AggregationTemporality aggregationTemporality;
|
@@ -120,6 +125,8 @@ private OtlpMeterRegistry(OtlpConfig config, Clock clock, ThreadFactory threadFa
|
120 | 125 | this.config = config;
|
121 | 126 | this.baseTimeUnit = config.baseTimeUnit();
|
122 | 127 | this.metricsSender = metricsSender;
|
| 128 | + this.histogramFlavorPerMeterLookup = HistogramFlavorPerMeterLookup.DEFAULT; |
| 129 | + this.maxBucketsPerMeterLookup = MaxBucketsPerMeterLookup.DEFAULT; |
123 | 130 | this.resource = Resource.newBuilder().addAllAttributes(getResourceAttributes()).build();
|
124 | 131 | this.aggregationTemporality = config.aggregationTemporality();
|
125 | 132 | config().namingConvention(NamingConvention.dot);
|
@@ -430,14 +437,16 @@ private Histogram getHistogram(Meter.Id id, DistributionStatisticConfig distribu
|
430 | 437 | }
|
431 | 438 |
|
432 | 439 | private int getMaxBuckets(Meter.Id id) {
|
433 |
| - return config.maxBucketsPerMeter().getOrDefault(id.getName(), config.maxBucketCount()); |
| 440 | + Integer maxBuckets = maxBucketsPerMeterLookup.getMaxBuckets(config.maxBucketsPerMeter(), id); |
| 441 | + return (maxBuckets == null) ? config.maxBucketCount() : maxBuckets; |
434 | 442 | }
|
435 | 443 |
|
436 | 444 | private HistogramFlavor histogramFlavor(Meter.Id id, OtlpConfig otlpConfig,
|
437 | 445 | DistributionStatisticConfig distributionStatisticConfig) {
|
438 |
| - HistogramFlavor preferredHistogramFlavor = otlpConfig.histogramFlavorPerMeter() |
439 |
| - .getOrDefault(id.getName(), otlpConfig.histogramFlavor()); |
440 |
| - |
| 446 | + HistogramFlavor preferredHistogramFlavor = histogramFlavorPerMeterLookup |
| 447 | + .getHistogramFlavor(otlpConfig.histogramFlavorPerMeter(), id); |
| 448 | + preferredHistogramFlavor = preferredHistogramFlavor == null ? otlpConfig.histogramFlavor() |
| 449 | + : preferredHistogramFlavor; |
441 | 450 | final double[] serviceLevelObjectiveBoundaries = distributionStatisticConfig
|
442 | 451 | .getServiceLevelObjectiveBoundaries();
|
443 | 452 | if (distributionStatisticConfig.isPublishingHistogram()
|
@@ -497,6 +506,91 @@ static double[] getSloWithPositiveInf(DistributionStatisticConfig distributionSt
|
497 | 506 | return sloWithPositiveInf;
|
498 | 507 | }
|
499 | 508 |
|
| 509 | + /** |
| 510 | + * Overridable lookup mechanism for {@link HistogramFlavor}. |
| 511 | + */ |
| 512 | + // VisibleForTesting |
| 513 | + @FunctionalInterface |
| 514 | + interface HistogramFlavorPerMeterLookup { |
| 515 | + |
| 516 | + /** |
| 517 | + * Default implementation. |
| 518 | + */ |
| 519 | + HistogramFlavorPerMeterLookup DEFAULT = OtlpMeterRegistry::lookup; |
| 520 | + |
| 521 | + /** |
| 522 | + * Looks up the histogram flavor to use on a per-meter level. This will override |
| 523 | + * the default {@link OtlpConfig#histogramFlavor()} for matching Meters. |
| 524 | + * {@link OtlpConfig#histogramFlavorPerMeter()} provides the data while this |
| 525 | + * method provides the logic for the lookup, and you can override them |
| 526 | + * independently. |
| 527 | + * @param perMeterMapping configured mapping data |
| 528 | + * @param id the {@link Meter.Id} the {@link HistogramFlavor} is configured for |
| 529 | + * @return the histogram flavor mapped to the {@link Meter.Id} or {@code null} if |
| 530 | + * mapping is undefined |
| 531 | + * @see OtlpConfig#histogramFlavorPerMeter() |
| 532 | + * @see OtlpConfig#histogramFlavor() |
| 533 | + */ |
| 534 | + @Nullable |
| 535 | + HistogramFlavor getHistogramFlavor(Map<String, HistogramFlavor> perMeterMapping, Meter.Id id); |
| 536 | + |
| 537 | + } |
| 538 | + |
| 539 | + /** |
| 540 | + * Overridable lookup mechanism for max bucket count. This has no effect on a meter if |
| 541 | + * it does not have an exponential bucket histogram configured. |
| 542 | + */ |
| 543 | + // VisibleForTesting |
| 544 | + @FunctionalInterface |
| 545 | + interface MaxBucketsPerMeterLookup { |
| 546 | + |
| 547 | + /** |
| 548 | + * Default implementation. |
| 549 | + */ |
| 550 | + MaxBucketsPerMeterLookup DEFAULT = OtlpMeterRegistry::lookup; |
| 551 | + |
| 552 | + /** |
| 553 | + * Looks up the max bucket count to use on a per-meter level. This will override |
| 554 | + * the default {@link OtlpConfig#maxBucketCount()} for matching Meters. |
| 555 | + * {@link OtlpConfig#maxBucketsPerMeter()} provides the data while this method |
| 556 | + * provides the logic for the lookup, and you can override them independently. |
| 557 | + * This has no effect on a meter if it does not have an exponential bucket |
| 558 | + * histogram configured. |
| 559 | + * @param perMeterMapping configured mapping data |
| 560 | + * @param id the {@link Meter.Id} the max bucket count is configured for |
| 561 | + * @return the max bucket count mapped to the {@link Meter.Id} or {@code null} if |
| 562 | + * the mapping is undefined |
| 563 | + * @see OtlpConfig#maxBucketsPerMeter() |
| 564 | + * @see OtlpConfig#maxBucketCount() |
| 565 | + */ |
| 566 | + @Nullable |
| 567 | + Integer getMaxBuckets(Map<String, Integer> perMeterMapping, Meter.Id id); |
| 568 | + |
| 569 | + } |
| 570 | + |
| 571 | + @Nullable |
| 572 | + private static <T> T lookup(Map<String, T> values, Meter.Id id) { |
| 573 | + if (values.isEmpty()) { |
| 574 | + return null; |
| 575 | + } |
| 576 | + return doLookup(values, id); |
| 577 | + } |
| 578 | + |
| 579 | + @Nullable |
| 580 | + private static <T> T doLookup(Map<String, T> values, Meter.Id id) { |
| 581 | + String name = id.getName(); |
| 582 | + while (StringUtils.isNotEmpty(name)) { |
| 583 | + T result = values.get(name); |
| 584 | + if (result != null) { |
| 585 | + return result; |
| 586 | + } |
| 587 | + int lastDot = name.lastIndexOf('.'); |
| 588 | + name = (lastDot != -1) ? name.substring(0, lastDot) : ""; |
| 589 | + } |
| 590 | + |
| 591 | + return null; |
| 592 | + } |
| 593 | + |
500 | 594 | /**
|
501 | 595 | * Builder for {@link OtlpMeterRegistry}.
|
502 | 596 | *
|
|
0 commit comments