aboutsummaryrefslogtreecommitdiff
path: root/kamon-core/src/main/scala/kamon/ModuleLoading.scala
blob: bc90c65679a7fd1664e220516abc380fd5fefb28 (plain) (blame)
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
package kamon

import com.typesafe.config.Config
import kamon.metric.{MetricsSnapshot, PeriodSnapshot}
import kamon.module.Module
import kamon.util.Registration
import kamon.module.{MetricReporter => NewMetricReporter}
import kamon.module.{SpanReporter => NewSpanReporter}
import kamon.module.Module.{Registration => NewRegistration}
import kamon.trace.Span

import scala.concurrent.Future

@deprecated("Use kamon.module.Module instead", "1.2.0")
sealed trait Reporter extends Module { }

@deprecated("Use kamon.module.MetricReporter instead", "1.2.0")
trait MetricReporter extends kamon.module.MetricReporter { }

@deprecated("Use kamon.module.SpanReporter instead", "1.2.0")
trait SpanReporter extends kamon.module.SpanReporter { }

/**
  * Handles the lifecycle of all modules known by Kamon. The most common implementations of modules are metrics and
  * span reporters, but modules can be used to encapsulate any process that should be started automatically by Kamon and
  * stopped when all modules are stopped (usually during shutdown).
  *
  * Modules can be automatically discovered from the kamon.modules configuration key, using the following schema:
  *
  *   kamon.modules {
  *     module-name {
  *       enabled = true
  *       class = "com.example.MyModule"
  *     }
  *   }
  *
  */
trait ModuleLoading { self: ClassLoading with Configuration with Utilities with Metrics with Tracing =>
  protected val _moduleRegistry = new Module.Registry(self, self, clock(), self.metricRegistry(), self.tracer())
  self.onReconfigure(newConfig => self._moduleRegistry.reconfigure(newConfig))


  /**
    * Register a module instantiated by the user.
    *
    * @param name Module name. Registration will fail if a module with the given name already exists.
    * @param module The module instance.
    * @return A Registration that can be used to de-register the module at any time.
    */
  def registerModule(name: String, module: Module): NewRegistration =
    _moduleRegistry.register(name, module)

  /**
    * Loads modules from Kamon's configuration.
    */
  def loadModules(): Unit =
    _moduleRegistry.load(self.config())

  /**
    * Stops all registered modules. This includes automatically and programmatically registered modules.
    *
    * @return A future that completes when the stop callback on all available modules have been completed.
    */
  def stopModules(): Future[Unit] =
    _moduleRegistry.stop()



  // Compatibility with Kamon <1.2.0

  @deprecated("Use registerModule instead", "1.2.0")
  def addReporter(reporter: MetricReporter): Registration =
    wrapRegistration(_moduleRegistry.register(reporter.getClass.getName(), wrapLegacyMetricReporter(reporter)))

  @deprecated("Use registerModule instead", "1.2.0")
  def addReporter(reporter: MetricReporter, name: String): Registration =
    wrapRegistration(_moduleRegistry.register(name, wrapLegacyMetricReporter(reporter)))

  @deprecated("Use registerModule instead", "1.2.0")
  def addReporter(reporter: MetricReporter, name: String, filter: String): Registration =
    wrapRegistration(_moduleRegistry.register(name, wrapLegacyMetricReporter(reporter, Some(filter))))

  @deprecated("Use registerModule instead", "1.2.0")
  def addReporter(reporter: SpanReporter): Registration =
    wrapRegistration(_moduleRegistry.register(reporter.getClass.getName(), wrapLegacySpanReporter(reporter)))

  @deprecated("Use registerModule instead", "1.2.0")
  def addReporter(reporter: SpanReporter, name: String): Registration =
    wrapRegistration(_moduleRegistry.register(name, wrapLegacySpanReporter(reporter)))

  @deprecated("Use stopModules instead", "1.2.0")
  def stopAllReporters(): Future[Unit] =
    _moduleRegistry.stop()

  @deprecated("Use loadModules instead", "1.2.0")
  def loadReportersFromConfig(): Unit =
    loadModules()


  private def wrapRegistration(registration: NewRegistration): Registration = new Registration {
    override def cancel(): Boolean = {
      registration.cancel()
      true
    }
  }

  private def wrapLegacyMetricReporter(reporter: MetricReporter, filter: Option[String] = None): NewMetricReporter = new NewMetricReporter {
    override def reportPeriodSnapshot(snapshot: PeriodSnapshot): Unit = {
      val filteredSnapshot = filter
        .map(f => filterMetrics(f, snapshot))
        .getOrElse(snapshot)
      reporter.reportPeriodSnapshot(filteredSnapshot)
    }

    private def filterMetrics(filterName: String, periodSnapshot: PeriodSnapshot): PeriodSnapshot = {
      val metricFilter = Kamon.filter(filterName)
      val counters = periodSnapshot.metrics.counters.filter(c => metricFilter.accept(c.name))
      val gauges = periodSnapshot.metrics.gauges.filter(g => metricFilter.accept(g.name))
      val histograms = periodSnapshot.metrics.histograms.filter(h => metricFilter.accept(h.name))
      val rangeSamplers = periodSnapshot.metrics.rangeSamplers.filter(rs => metricFilter.accept(rs.name))

      periodSnapshot.copy(metrics = MetricsSnapshot(
        histograms, rangeSamplers, gauges, counters
      ))
    }

    override def start(): Unit = reporter.start()
    override def stop(): Unit = reporter.stop()
    override def reconfigure(config: Config): Unit = reporter.reconfigure(config)
  }

  private def wrapLegacySpanReporter(reporter: SpanReporter): NewSpanReporter = new NewSpanReporter {
    override def reportSpans(spans: Seq[Span.FinishedSpan]): Unit = reporter.reportSpans(spans)
    override def start(): Unit = reporter.start()
    override def stop(): Unit = reporter.stop()
    override def reconfigure(newConfig: Config): Unit = reporter.reconfigure(newConfig)
  }

}