package kamon
import com.typesafe.config.Config
import kamon.metric.{MetricsSnapshot, PeriodSnapshot}
import kamon.module.Module
import kamon.module.ModuleRegistry
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
* description = "A module description"
* kind = "combined | metric | span | plain"
* class = "com.example.MyModule"
* }
* }
*
*/
trait ModuleLoading { self: ClassLoading with Configuration with Utilities with Metrics with Tracing =>
protected val _moduleRegistry = new ModuleRegistry(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)
}
}