Skip to content

Commit

Permalink
fix inspectIT mapper
Browse files Browse the repository at this point in the history
  • Loading branch information
EddeCCC committed Aug 26, 2024
1 parent 2296a24 commit 2e721f1
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 57 deletions.
8 changes: 7 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,13 @@ dependencies {
Slightly adapted inspectit-ocelot-config-2.6.5.jar for dqualizer
Changed: Added @JsonIgnore to the methods of InstrumentationScopeSettings
*/
implementation(files("inspectit-ocelot-config-dqualizer.jar"))
implementation(files("inspectit-ocelot/inspectit-ocelot-config-dqualizer.jar"))
// Helpful utility classes to load inspectIT default configuration
implementation(files("inspectit-ocelot/inspectit-ocelot-configurationserver-dqualizer.jar"))
implementation(files("inspectit-ocelot/inspectit-ocelot-configdocsgenerator-dqualizer.jar"))
// Also necessary to load inspectIT default configuration
implementation("io.opentelemetry:opentelemetry-sdk-metrics:1.29.0")
implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310")

implementation("io.github.oshai:kotlin-logging:6.0.9")

Expand Down
File renamed without changes.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
package dqualizer.dqexec.instrumentation.framework.included

import com.fasterxml.jackson.annotation.JsonInclude
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.core.JsonGenerator
import com.fasterxml.jackson.databind.JsonSerializer
import com.fasterxml.jackson.databind.SerializationFeature
import com.fasterxml.jackson.databind.SerializerProvider
import com.fasterxml.jackson.databind.json.JsonMapper
import com.fasterxml.jackson.databind.module.SimpleModule
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
import dqualizer.dqexec.util.take
import inspectit.ocelot.configdocsgenerator.parsing.ConfigParser
import io.github.dqualizer.dqlang.types.dam.DomainArchitectureMapping
import io.github.dqualizer.dqlang.types.dam.architecture.CodeComponent
import io.github.dqualizer.dqlang.types.dam.mapping.ActivityToCallMapping
Expand All @@ -16,8 +23,9 @@ import io.opentelemetry.api.trace.SpanKind
import okhttp3.internal.toImmutableMap
import org.mapstruct.Mapper
import org.springframework.stereotype.Component
import org.yaml.snakeyaml.Yaml
import rocks.inspectit.ocelot.config.loaders.ConfigFileLoader
import rocks.inspectit.ocelot.config.model.InspectitConfig
import rocks.inspectit.ocelot.config.model.instrumentation.InstrumentationSettings
import rocks.inspectit.ocelot.config.model.instrumentation.actions.ActionCallSettings
import rocks.inspectit.ocelot.config.model.instrumentation.actions.GenericActionSettings
import rocks.inspectit.ocelot.config.model.instrumentation.rules.InstrumentationRuleSettings
Expand All @@ -27,30 +35,61 @@ import rocks.inspectit.ocelot.config.model.instrumentation.scope.ElementDescript
import rocks.inspectit.ocelot.config.model.instrumentation.scope.InstrumentationScopeSettings
import rocks.inspectit.ocelot.config.model.instrumentation.scope.MatcherMode
import rocks.inspectit.ocelot.config.model.instrumentation.scope.MethodMatcherSettings
import rocks.inspectit.ocelot.config.model.logging.LoggingSettings
import rocks.inspectit.ocelot.config.model.metrics.MetricsSettings
import rocks.inspectit.ocelot.config.model.metrics.definition.MetricDefinitionSettings
import rocks.inspectit.ocelot.config.model.metrics.definition.ViewDefinitionSettings
import rocks.inspectit.ocelot.config.model.metrics.definition.ViewDefinitionSettings.ViewDefinitionSettingsBuilder
import rocks.inspectit.ocelot.config.model.selfmonitoring.SelfMonitoringSettings
import rocks.inspectit.ocelot.config.model.tracing.LogCorrelationSettings
import rocks.inspectit.ocelot.config.model.tracing.PropagationFormat
import rocks.inspectit.ocelot.config.model.tracing.TraceIdAutoInjectionSettings
import rocks.inspectit.ocelot.config.model.tracing.TracingSettings
import rocks.inspectit.ocelot.agentconfiguration.ObjectStructureMerger
import java.time.Duration
import java.util.*

@Mapper
@Component
class InspectItOcelotInstrumentationPlanMapper() {
class InspectItOcelotInstrumentationPlanMapper {
private val log = KotlinLogging.logger { }

// JsonSerializer to convert Durations properly
class DurationSerializer : JsonSerializer<Duration>() {
override fun serialize(value: Duration?, gen: JsonGenerator, serializers: SerializerProvider) {
if (value != null) {
gen.writeString(value.toString())
}
}
}

private val inspectItMapper =
ObjectMapper().apply {
JsonMapper.builder()
.addModule(JavaTimeModule())
.addModule(SimpleModule().addSerializer(Duration::class.java, DurationSerializer()))
.build().apply {
setSerializationInclusion(JsonInclude.Include.NON_EMPTY)
enable(SerializationFeature.INDENT_OUTPUT)
}

private val defaultConfigString = run {
var mergedConfig: Any? = null
val defaultConfigFiles = ConfigFileLoader.getDefaultConfigFiles()
// Merge all inspectIT default configuration to one object
defaultConfigFiles.forEach {
val filePath = it.key
val fileContent = it.value
mergedConfig = ObjectStructureMerger.loadAndMergeYaml(fileContent, mergedConfig, filePath)
}
Yaml().dump(mergedConfig)
}

fun toYamlString(config: InspectitConfig): String {
return inspectItMapper.writeValueAsString(mapOf(Pair("inspectit", config)))
private fun parseDefaultConfig(config: String): InspectitConfig {
log.info { "Parsing inspectIT Ocelot default configuration..." }
return ConfigParser().parseConfig(config)
}

private fun toYamlString(config: InspectitConfig): String {
val configMap = mapOf(Pair("inspectit", config))
return inspectItMapper.writeValueAsString(configMap)
}

private fun InstrumentLocation.toScopeName() = "s_" + sanitizeName(this.location)
Expand All @@ -68,41 +107,47 @@ class InspectItOcelotInstrumentationPlanMapper() {
instrumentation: ServiceMonitoringConfiguration,
dam: DomainArchitectureMapping
): InspectItOcelotInstrumentationPlan {
val baseConfig = parseDefaultConfig(defaultConfigString)
val serviceName = instrumentation.instrumentationFramework.options
.getOrDefault("INSPECTIT_SERVICE_NAME", "inspectIT-dqualizer")

val metrics = generateMetrics(instrumentation)

val instrumentationSettings = InstrumentationSettings().apply {
this.scopes = generateScopes(dam, instrumentation)
this.actions = generateActions(dam, instrumentation)
this.rules = getRules(dam, instrumentation, metrics, scopes, actions)

val metrics = baseConfig.metrics.apply {
val generatedMetrics = generateMetricsDefinitions(instrumentation)
this.definitions.putAll(generatedMetrics)
}

val config = InspectitConfig().apply {
this.instrumentation = instrumentationSettings
this.metrics = metrics
this.logging = LoggingSettings().apply { this.isDebug = true }
this.tracing = TracingSettings().createTraceSettings(instrumentation)
val instrumentationSettings = baseConfig.instrumentation.apply {
val generatedScopes = generateScopes(dam, instrumentation)
this.scopes.putAll(generatedScopes)
val generatedActions = generateActions(dam, instrumentation)
this.actions.putAll(generatedActions)
val generatedRules = getRules(dam, instrumentation, metrics, this.scopes, this.actions)
this.rules.putAll(generatedRules)
}

// default settings
this.threadPoolSize = 2
this.selfMonitoring = enableSelfMonitoring()
val generatedConfig = baseConfig.apply {
this.serviceName = serviceName
this.logging.isDebug = true
this.logging.configFile = null // prevent AccessDeniedException
this.tracing.createTraceSettings(instrumentation)
this.exporters.tracing.serviceName = serviceName

// We don't need these properties with dqualizer
this.agentCommands = null
this.config.http = null
this.selfMonitoring.agentHealth = null
}

log.info { "Created inspectIT Ocelot configuration: $config" }
log.info { "Created inspectIT Ocelot configuration" }

val yamlString = toYamlString(config)
val yamlString = toYamlString(generatedConfig)
return InspectItOcelotInstrumentationPlan(instrumentation, yamlString);
}

private fun TracingSettings.createTraceSettings(instrumentation: ServiceMonitoringConfiguration): TracingSettings {
isEnabled = instrumentation.instruments.any { it.measurementType == MeasurementType.EXECUTION_TIME }
|| instrumentation.instrumentationFramework.hasTraces

sampleProbability = 1.0

isAddMetricTags = true

propagationFormat = PropagationFormat.TRACE_CONTEXT

logCorrelation = LogCorrelationSettings().apply {
Expand All @@ -115,7 +160,7 @@ class InspectItOcelotInstrumentationPlanMapper() {
return this
}

private fun generateMetrics(instrumentation: ServiceMonitoringConfiguration): MetricsSettings {
private fun generateMetricsDefinitions(instrumentation: ServiceMonitoringConfiguration): Map<String, MetricDefinitionSettings> {
val definitions = instrumentation.instruments.associate {
val type = it.measurementType
val instrumentType = it.instrumentType
Expand Down Expand Up @@ -172,12 +217,7 @@ class InspectItOcelotInstrumentationPlanMapper() {
Pair(definitionNameTemplate.format(""), metricDefinitionSettings);
}


return MetricsSettings().apply {
this.isEnabled = true
this.definitions = definitions
//TODO: add option for resource monitoring
}
return definitions
}

private fun getMetricNameTemplateFromType(type: MeasurementType) = when (type) {
Expand Down Expand Up @@ -354,11 +394,12 @@ class InspectItOcelotInstrumentationPlanMapper() {

MeasurementType.EXECUTION_TIME -> {
handleExecutionTimeInstrumentation(dam, instrument)
.forEach { (k, v) -> rules[k] = v }
.forEach { (ruleName, rule) -> rules[ruleName] = rule }
}

MeasurementType.EXECUTION_COUNT -> {
TODO()
// TODO()
throw NotImplementedError("Execution count measurement not implemented")
}
}

Expand Down Expand Up @@ -404,6 +445,7 @@ class InspectItOcelotInstrumentationPlanMapper() {
val ruleName = "r_" + sanitizeName(instrument.measurementName)

val instrumentationRuleSettings = InstrumentationRuleSettings().apply {
this.include = mapOf(Pair("r_trace_method", true))
this.entry = mapOf(getSimpleAction("method_entry_time", "a_timestamp_ms"))
this.exit = mapOf(Pair("duration", ActionCallSettings().apply {
this.action = "a_calculate_time_difference"
Expand Down Expand Up @@ -553,6 +595,7 @@ class InspectItOcelotInstrumentationPlanMapper() {
this.scopes = scopes
this.metrics = metricsSettings
this.exit = exitActions
this.include["r_trace_method"] = true
}
}

Expand All @@ -564,11 +607,4 @@ class InspectItOcelotInstrumentationPlanMapper() {
ActionCallSettings().apply {
this.action = second
})

private fun enableSelfMonitoring(): SelfMonitoringSettings {
val selfMonitoring = SelfMonitoringSettings()
selfMonitoring.isEnabled = true

return selfMonitoring
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@ class InspectItOcelotInstrumenter(
val instrumentationMapper: InspectItOcelotInstrumentationPlanMapper
) : IRuntimeServiceInstrumenter {

val supportedNames = listOf("inspectit", "ocelot", "inspectit_ocelot", "InspectIT Ocelot")
private val supportedNames = listOf("inspectit", "ocelot", "inspectit_ocelot", "InspectIT Ocelot")
.map { it.lowercase() }.toSet() //case insensitivity

private val log = KotlinLogging.logger { }

private val configFileName = "configuration/plan.yaml"

override fun instrument(
dam: DomainArchitectureMapping,
Expand All @@ -36,26 +37,35 @@ class InspectItOcelotInstrumenter(
) {
val instrumentationPlan = instrumentationMapper.map(serviceMonitoringConfiguration, dam)

val configPath = Path.of(configFileName)

if(Files.notExists(configPath)) {
log.info { "Creating inspectIT ocelot configuration file..." }
Files.createDirectories(configPath.parent)
Files.createFile(configPath)
}

val output = Files.writeString(
Path.of("configuration/plan.yaml"),
configPath,
instrumentationPlan.inspectItConfiguration,
Charsets.UTF_8
)

log.info { "InspectIT Ocelot configuration written to ${output.toAbsolutePath()}" }

//platformAccessor.connect()

//log.info { "Connected to platform" }

/**
* To keep it simple, we already start the demo applications with an attached inspectIT Ocelot agent.
*/

/*
platformAccessor.connect()
log.info { "Connected to platform" }
//TODOs:
// - check if container has internet access, otherwise try download locally
// - location of the jar should be configurable
/* log.info { "Downloading agent" }
log.info { "Downloading agent" }
var response = platformAccessor.executeInServiceContainer(
"""
curl https://github.com/inspectIT/inspectit-oce/releases/download/$INSPECT_IT_OCELOT_VERSION/$INSPECTIT_OCELOT_JAR -o /tmp/$INSPECTIT_OCELOT_JAR
Expand All @@ -68,9 +78,9 @@ class InspectItOcelotInstrumenter(
wget https://github.com/inspectIT/inspectit-oce/releases/download/$INSPECT_IT_OCELOT_VERSION/$INSPECTIT_OCELOT_JAR -O /tmp/$INSPECTIT_OCELOT_JAR
""".trimIndent()
)
}*/
}
/* log.debug { "Response: $response" }
log.debug { "Response: $response" }
val targetProcessId = platformAccessor.getTargetProcessID("java")
log.info { "Target process id: $targetProcessId" }
Expand All @@ -85,15 +95,16 @@ class InspectItOcelotInstrumenter(
val cmd = """
export INSPECTIT_CONFIG_FILE_BASED_ENABLED=true && \
export INSPECTIT_CONFIG_FILE_BASED_PATH=/tmp/inspectit-config.json && \
java -jar /tmp/$INSPECTIT_OCELOT_JAR $targetProcessId
java -jar /tmp/$INSPECTIT_OCELOT_JAR $targetProcessId
""".trimIndent()
val agentResponse = platformAccessor.executeInServiceContainer(cmd)
log.debug { "Response: $agentResponse" }
if (!agentResponse.contains("Agent successfully attached!")) {
throw RuntimeException("Agent could not be started")
}*/
}
*/
}

override fun deinstrument(
Expand Down

0 comments on commit 2e721f1

Please sign in to comment.