summaryrefslogtreecommitdiff
path: root/simulator/odcsim/odcsim-engine-omega
diff options
context:
space:
mode:
authorGeorgios Andreadis <info@gandreadis.com>2020-06-29 16:04:57 +0200
committerFabian Mastenbroek <mail.fabianm@gmail.com>2020-08-24 16:18:13 +0200
commit46b06fb446e79c390c01953d31d700b8e73da24d (patch)
treeb2329630ebf2c90d297ba0d3046ccd558d12d042 /simulator/odcsim/odcsim-engine-omega
parentebcacf96fbc1cd16a91523f95dd01db046fb7f90 (diff)
Prepare simulator repository for monorepo
This change prepares the simulator Git repository for the monorepo residing at https://github.com/atlarge-research.com/opendc. To accomodate for this, we move all files into a simulator subdirectory.
Diffstat (limited to 'simulator/odcsim/odcsim-engine-omega')
-rw-r--r--simulator/odcsim/odcsim-engine-omega/build.gradle.kts47
-rw-r--r--simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/OmegaSimulationEngine.kt264
-rw-r--r--simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/OmegaSimulationEngineProvider.kt37
-rw-r--r--simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/logging/LocationAwareLoggerImpl.kt567
-rw-r--r--simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/logging/LocationIgnorantLoggerImpl.kt440
-rw-r--r--simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/logging/LoggerImpl.kt74
-rw-r--r--simulator/odcsim/odcsim-engine-omega/src/main/resources/META-INF/services/com.atlarge.odcsim.SimulationEngineProvider1
7 files changed, 1430 insertions, 0 deletions
diff --git a/simulator/odcsim/odcsim-engine-omega/build.gradle.kts b/simulator/odcsim/odcsim-engine-omega/build.gradle.kts
new file mode 100644
index 00000000..98e2469e
--- /dev/null
+++ b/simulator/odcsim/odcsim-engine-omega/build.gradle.kts
@@ -0,0 +1,47 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2018 atlarge-research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+description = "Single-threaded reference implementation for the odcsim API"
+
+/* Build configuration */
+plugins {
+ `kotlin-library-convention`
+}
+
+/* Project configuration */
+repositories {
+ jcenter()
+}
+
+dependencies {
+ api(project(":odcsim:odcsim-api"))
+
+ implementation(kotlin("stdlib"))
+ implementation("org.jetbrains:annotations:17.0.0")
+
+ testImplementation("org.junit.jupiter:junit-jupiter-api:${Library.JUNIT_JUPITER}")
+ testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${Library.JUNIT_JUPITER}")
+ testImplementation("org.junit.platform:junit-platform-launcher:${Library.JUNIT_PLATFORM}")
+ testRuntimeOnly("org.slf4j:slf4j-simple:${Library.SLF4J}")
+}
diff --git a/simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/OmegaSimulationEngine.kt b/simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/OmegaSimulationEngine.kt
new file mode 100644
index 00000000..e675b877
--- /dev/null
+++ b/simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/OmegaSimulationEngine.kt
@@ -0,0 +1,264 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2018 atlarge-research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.atlarge.odcsim.engine.omega
+
+import com.atlarge.odcsim.Domain
+import com.atlarge.odcsim.SimulationContext
+import com.atlarge.odcsim.SimulationEngine
+import com.atlarge.odcsim.engine.omega.logging.LoggerImpl
+import java.time.Clock
+import java.time.Instant
+import java.time.ZoneId
+import java.util.PriorityQueue
+import java.util.UUID
+import kotlin.coroutines.CoroutineContext
+import kotlin.coroutines.coroutineContext
+import kotlinx.coroutines.CancellableContinuation
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineExceptionHandler
+import kotlinx.coroutines.CoroutineName
+import kotlinx.coroutines.Delay
+import kotlinx.coroutines.DisposableHandle
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.InternalCoroutinesApi
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.Runnable
+import kotlinx.coroutines.SupervisorJob
+import org.jetbrains.annotations.Async
+import org.slf4j.Logger
+
+/**
+ * The reference implementation of the [SimulationEngine] instance for the OpenDC simulation core.
+ *
+ * This engine implementation is a single-threaded implementation, running logical processes synchronously and
+ * provides a single priority queue for all events (messages, ticks, etc) that occur.
+ *
+ * @param name The name of the engine instance.
+ */
+public class OmegaSimulationEngine(override val name: String) : SimulationEngine {
+ /**
+ * The state of the actor system.
+ */
+ private var state: SimulationEngineState = SimulationEngineState.CREATED
+
+ /**
+ * The clock tracking the simulation time.
+ */
+ private val clock: VirtualClock = VirtualClock(0)
+
+ /**
+ * The event queue to process
+ */
+ private val queue: PriorityQueue<Event> = PriorityQueue(Comparator<Event> { lhs, rhs ->
+ // Note that Comparator gives better performance than Comparable according to
+ // profiling
+ val cmp = lhs.time.compareTo(rhs.time)
+ if (cmp == 0) lhs.id.compareTo(rhs.id) else cmp
+ })
+
+ /**
+ * The active processes in the simulation engine.
+ */
+ private val registry: MutableMap<String, Domain> = HashMap()
+
+ /**
+ * A unique increasing identifier assigned to each event, needed because otherwise two events occurring in sequence
+ * (but at the same time) may be differently ordered in the internal priority queue (queue) since it does not
+ * guarantee insertion order.
+ */
+ private var nextId: Long = 0
+
+ override fun newDomain(): Domain = newDomain(null)
+
+ override fun newDomain(name: String): Domain = newDomain(name, null)
+
+ override suspend fun run() {
+ check(state != SimulationEngineState.TERMINATED) { "The simulation engine is terminated" }
+
+ if (state == SimulationEngineState.CREATED) {
+ state = SimulationEngineState.STARTED
+ }
+
+ val job = coroutineContext[Job]
+
+ while (job?.isActive == true) {
+ val event = queue.peek() ?: break
+ val delivery = event.time
+
+ // A message should never be delivered out of order in this single-threaded implementation. Assert for
+ // sanity
+ assert(delivery >= clock.time) { "Message delivered out of order [expected=$delivery, actual=${clock.time}]" }
+
+ clock.time = delivery
+ queue.poll()
+
+ process(event)
+ }
+ }
+
+ override suspend fun terminate() {
+ state = SimulationEngineState.TERMINATED
+ }
+
+ /**
+ * Schedule the specified event to be processed by the engine.
+ */
+ private fun schedule(@Async.Schedule event: Event) {
+ assert(event.time >= clock.time) { "Message scheduled in the past [received=${event.time}, actual=${clock.time}]" }
+ queue.add(event)
+ }
+
+ /**
+ * Process the delivery of an event.
+ */
+ @OptIn(ExperimentalCoroutinesApi::class)
+ private fun process(@Async.Execute event: Event) {
+ // This has been inlined into this method for performance
+ when (event) {
+ is Event.Dispatch ->
+ event.block.run()
+ is Event.Resume ->
+ with(event.continuation) { event.dispatcher.resumeUndispatched(Unit) }
+ is Event.Timeout ->
+ if (!event.isCancelled)
+ event.block.run()
+ }
+ }
+
+ /**
+ * Spawn a new simulation domain.
+ */
+ private fun newDomainImpl(name: String, parent: DomainImpl?): Domain {
+ val domain = DomainImpl(name, parent)
+ require(domain.path !in registry) { "Domain name $name not unique" }
+ registry[domain.path] = domain
+ return domain
+ }
+
+ private fun newDomain(parent: DomainImpl?): Domain {
+ val name = "$" + UUID.randomUUID()
+ return newDomainImpl(name, parent)
+ }
+
+ private fun newDomain(name: String, parent: DomainImpl?): Domain {
+ require(name.isNotEmpty()) { "Domain name may not be empty" }
+ require(!name.startsWith("$")) { "Domain name may not start with $-sign" }
+ require(!name.contains("/")) { "Domain name may not contain /" }
+ return newDomainImpl(name, parent)
+ }
+
+ private inner class DomainImpl(override val name: String, parent: DomainImpl?) : SimulationContext, Domain {
+ val job: Job = SupervisorJob(parent?.job)
+ val path: String = (parent?.path ?: "") + "/$name"
+
+ @InternalCoroutinesApi
+ private val dispatcher = object : CoroutineDispatcher(), Delay {
+ // CoroutineDispatcher
+ override fun dispatch(context: CoroutineContext, block: Runnable) {
+ schedule(Event.Dispatch(clock.time, nextId++, block))
+ }
+
+ // Delay
+ override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation<Unit>) {
+ schedule(Event.Resume(clock.time + timeMillis, nextId++, this, continuation))
+ }
+
+ override fun invokeOnTimeout(timeMillis: Long, block: Runnable): DisposableHandle {
+ val event = Event.Timeout(clock.time + timeMillis, nextId++, block)
+ schedule(event)
+ return event
+ }
+ }
+
+ private val exceptionHandler = CoroutineExceptionHandler { _, exception ->
+ log.error("Uncaught exception", exception)
+ }
+
+ // SimulationContext
+ override val key: CoroutineContext.Key<*> = SimulationContext.Key
+
+ override val domain: Domain = this
+
+ override val clock: VirtualClock
+ get() = this@OmegaSimulationEngine.clock
+
+ override val log: Logger by lazy(LazyThreadSafetyMode.NONE) { LoggerImpl.invoke(this) }
+
+ override fun newDomain(): Domain = this@OmegaSimulationEngine.newDomain(this)
+
+ override fun newDomain(name: String): Domain = this@OmegaSimulationEngine.newDomain(name, this)
+
+ // Domain
+ override val parent: Domain = parent ?: this
+
+ @InternalCoroutinesApi
+ override val coroutineContext: CoroutineContext = this + CoroutineName(name) + dispatcher + job + exceptionHandler
+
+ override fun toString(): String = path
+ }
+
+ /**
+ * Enumeration to track the state of the actor system.
+ */
+ private enum class SimulationEngineState {
+ CREATED, STARTED, TERMINATED
+ }
+
+ /**
+ * A wrapper around a message that has been scheduled for processing.
+ *
+ * @property time The point in time to deliver the message.
+ */
+ private sealed class Event(val time: Long, val id: Long) {
+ class Dispatch(time: Long, id: Long, val block: Runnable) : Event(time, id) {
+ override fun toString(): String = "Dispatch[$time]"
+ }
+
+ class Resume(time: Long, id: Long, val dispatcher: CoroutineDispatcher, val continuation: CancellableContinuation<Unit>) : Event(time, id) {
+ override fun toString(): String = "Resume[$time]"
+ }
+
+ class Timeout(time: Long, id: Long, val block: Runnable, var isCancelled: Boolean = false) : Event(time, id), DisposableHandle {
+ override fun dispose() {
+ isCancelled = true
+ }
+
+ override fun toString(): String = "Timeout[$time]"
+ }
+ }
+
+ /**
+ * A virtual [Clock] implementation for keeping track of simulation time.
+ */
+ private data class VirtualClock(var time: Long) : Clock() {
+ override fun withZone(zone: ZoneId?): Clock = throw NotImplementedError()
+
+ override fun getZone(): ZoneId = ZoneId.systemDefault()
+
+ override fun instant(): Instant = Instant.ofEpochMilli(time)
+
+ override fun millis(): Long = time
+ }
+}
diff --git a/simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/OmegaSimulationEngineProvider.kt b/simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/OmegaSimulationEngineProvider.kt
new file mode 100644
index 00000000..5dba3233
--- /dev/null
+++ b/simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/OmegaSimulationEngineProvider.kt
@@ -0,0 +1,37 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2018 atlarge-research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.atlarge.odcsim.engine.omega
+
+import com.atlarge.odcsim.SimulationEngine
+import com.atlarge.odcsim.SimulationEngineProvider
+import java.util.ServiceLoader
+
+/**
+ * An [SimulationEngineProvider] for the Omega engine, used by the [ServiceLoader] API to create
+ * [OmegaSimulationEngine] instances.
+ */
+public class OmegaSimulationEngineProvider : SimulationEngineProvider {
+ override operator fun invoke(name: String): SimulationEngine = OmegaSimulationEngine(name)
+}
diff --git a/simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/logging/LocationAwareLoggerImpl.kt b/simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/logging/LocationAwareLoggerImpl.kt
new file mode 100644
index 00000000..fca4826e
--- /dev/null
+++ b/simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/logging/LocationAwareLoggerImpl.kt
@@ -0,0 +1,567 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2019 atlarge-research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.atlarge.odcsim.engine.omega.logging
+
+import com.atlarge.odcsim.SimulationContext
+import org.slf4j.Logger
+import org.slf4j.Marker
+import org.slf4j.helpers.MessageFormatter
+import org.slf4j.spi.LocationAwareLogger
+
+/**
+ * An actor-specific [Logger] implementation that is aware of the calling location.
+ *
+ * @param ctx The owning [SimulationContext] of this logger.
+ * @param delegate The [LocationAwareLogger] to delegate the messages to.
+ */
+internal class LocationAwareLoggerImpl(
+ ctx: SimulationContext,
+ private val delegate: LocationAwareLogger
+) : LoggerImpl(ctx), Logger by delegate {
+ /**
+ * The fully qualified name of this class.
+ */
+ private val fqcn = LocationAwareLoggerImpl::class.java.name
+
+ override fun trace(format: String?, arg: Any?) {
+ if (!delegate.isTraceEnabled) {
+ return
+ }
+
+ withMdc {
+ val formattedMessage = MessageFormatter.format(format, arg).message
+ delegate.log(null, fqcn, LocationAwareLogger.TRACE_INT, formattedMessage, arrayOf(arg), null)
+ }
+ }
+
+ override fun trace(format: String?, arg1: Any?, arg2: Any?) {
+ if (!delegate.isTraceEnabled) {
+ return
+ }
+
+ withMdc {
+ val formattedMessage = MessageFormatter.format(format, arg1, arg2).message
+ delegate.log(null, fqcn, LocationAwareLogger.TRACE_INT, formattedMessage, arrayOf(arg1, arg2), null)
+ }
+ }
+
+ override fun trace(format: String?, argArray: Array<Any?>) {
+ if (!delegate.isTraceEnabled) {
+ return
+ }
+
+ withMdc {
+ val formattedMessage = MessageFormatter.arrayFormat(format, argArray).message
+ delegate.log(null, fqcn, LocationAwareLogger.TRACE_INT, formattedMessage, argArray, null)
+ }
+ }
+
+ override fun trace(msg: String?, t: Throwable?) {
+ if (!delegate.isTraceEnabled) {
+ return
+ }
+
+ withMdc {
+ delegate.log(null, fqcn, LocationAwareLogger.TRACE_INT, msg, null, t)
+ }
+ }
+
+ override fun trace(marker: Marker?, msg: String?) {
+ if (!delegate.isTraceEnabled) {
+ return
+ }
+
+ withMdc {
+ delegate.log(marker, fqcn, LocationAwareLogger.TRACE_INT, msg, null, null)
+ }
+ }
+
+ override fun trace(marker: Marker?, format: String?, arg: Any?) {
+ if (!delegate.isTraceEnabled) {
+ return
+ }
+
+ withMdc {
+ val formattedMessage = MessageFormatter.format(format, arg).message
+ delegate.log(marker, fqcn, LocationAwareLogger.TRACE_INT, formattedMessage, arrayOf(arg), null)
+ }
+ }
+
+ override fun trace(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) {
+ if (!delegate.isTraceEnabled) {
+ return
+ }
+
+ withMdc {
+ val formattedMessage = MessageFormatter.format(format, arg1, arg2).message
+ delegate.log(marker, fqcn, LocationAwareLogger.TRACE_INT, formattedMessage, arrayOf(arg1, arg2), null)
+ }
+ }
+
+ override fun trace(marker: Marker?, format: String?, argArray: Array<Any?>) {
+ if (!delegate.isTraceEnabled) {
+ return
+ }
+
+ withMdc {
+ val formattedMessage = MessageFormatter.arrayFormat(format, argArray).message
+ delegate.log(marker, fqcn, LocationAwareLogger.TRACE_INT, formattedMessage, argArray, null)
+ }
+ }
+
+ override fun trace(marker: Marker?, msg: String?, t: Throwable?) {
+ if (!delegate.isTraceEnabled) {
+ return
+ }
+
+ withMdc {
+ delegate.log(marker, fqcn, LocationAwareLogger.TRACE_INT, msg, null, t)
+ }
+ }
+
+ override fun debug(msg: String?) {
+ if (!delegate.isDebugEnabled) {
+ return
+ }
+
+ withMdc {
+ delegate.log(null, fqcn, LocationAwareLogger.DEBUG_INT, msg, null, null)
+ }
+ }
+
+ override fun debug(format: String?, arg: Any?) {
+ if (!delegate.isDebugEnabled) {
+ return
+ }
+
+ withMdc {
+ val formattedMessage = MessageFormatter.format(format, arg).message
+ delegate.log(null, fqcn, LocationAwareLogger.DEBUG_INT, formattedMessage, arrayOf(arg), null)
+ }
+ }
+
+ override fun debug(format: String?, arg1: Any?, arg2: Any?) {
+ if (!delegate.isDebugEnabled) {
+ return
+ }
+
+ withMdc {
+ val formattedMessage = MessageFormatter.format(format, arg1, arg2).message
+ delegate.log(null, fqcn, LocationAwareLogger.DEBUG_INT, formattedMessage, arrayOf(arg1, arg2), null)
+ }
+ }
+
+ override fun debug(format: String?, argArray: Array<Any?>) {
+ if (!delegate.isDebugEnabled) {
+ return
+ }
+
+ withMdc {
+ val ft = MessageFormatter.arrayFormat(format, argArray)
+ delegate.log(null, fqcn, LocationAwareLogger.DEBUG_INT, ft.message, ft.argArray, ft.throwable)
+ }
+ }
+
+ override fun debug(msg: String?, t: Throwable?) {
+ if (!delegate.isDebugEnabled) {
+ return
+ }
+
+ withMdc {
+ delegate.log(null, fqcn, LocationAwareLogger.DEBUG_INT, msg, null, t)
+ }
+ }
+
+ override fun debug(marker: Marker?, msg: String?) {
+ if (!delegate.isDebugEnabled) {
+ return
+ }
+
+ withMdc {
+ delegate.log(marker, fqcn, LocationAwareLogger.DEBUG_INT, msg, null, null)
+ }
+ }
+
+ override fun debug(marker: Marker?, format: String?, arg: Any?) {
+ if (!delegate.isDebugEnabled) {
+ return
+ }
+
+ withMdc {
+ val ft = MessageFormatter.format(format, arg)
+ delegate.log(marker, fqcn, LocationAwareLogger.DEBUG_INT, ft.message, ft.argArray, ft.throwable)
+ }
+ }
+
+ override fun debug(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) {
+ if (!delegate.isDebugEnabled) {
+ return
+ }
+
+ withMdc {
+ val formattedMessage = MessageFormatter.format(format, arg1, arg2).message
+ delegate.log(marker, fqcn, LocationAwareLogger.DEBUG_INT, formattedMessage, arrayOf(arg1, arg2), null)
+ }
+ }
+
+ override fun debug(marker: Marker?, format: String?, argArray: Array<Any?>) {
+ if (!delegate.isDebugEnabled) {
+ return
+ }
+
+ withMdc {
+ val ft = MessageFormatter.arrayFormat(format, argArray)
+ delegate.log(marker, fqcn, LocationAwareLogger.DEBUG_INT, ft.message, argArray, ft.throwable)
+ }
+ }
+
+ override fun debug(marker: Marker?, msg: String?, t: Throwable?) {
+ if (!delegate.isDebugEnabled) {
+ return
+ }
+
+ withMdc {
+ delegate.log(marker, fqcn, LocationAwareLogger.DEBUG_INT, msg, null, t)
+ }
+ }
+
+ override fun info(msg: String?) {
+ if (!delegate.isInfoEnabled) {
+ return
+ }
+
+ withMdc {
+ delegate.log(null, fqcn, LocationAwareLogger.INFO_INT, msg, null, null)
+ }
+ }
+
+ override fun info(format: String?, arg: Any?) {
+ if (!delegate.isInfoEnabled) {
+ return
+ }
+
+ withMdc {
+ val formattedMessage = MessageFormatter.format(format, arg).message
+ delegate.log(null, fqcn, LocationAwareLogger.INFO_INT, formattedMessage, arrayOf(arg), null)
+ }
+ }
+
+ override fun info(format: String?, arg1: Any?, arg2: Any?) {
+ if (!delegate.isInfoEnabled) {
+ return
+ }
+
+ withMdc {
+ val formattedMessage = MessageFormatter.format(format, arg1, arg2).message
+ delegate.log(null, fqcn, LocationAwareLogger.INFO_INT, formattedMessage, arrayOf(arg1, arg2), null)
+ }
+ }
+
+ override fun info(format: String?, argArray: Array<Any?>) {
+ if (!delegate.isInfoEnabled) {
+ return
+ }
+
+ withMdc {
+ val formattedMessage = MessageFormatter.arrayFormat(format, argArray).message
+ delegate.log(null, fqcn, LocationAwareLogger.INFO_INT, formattedMessage, argArray, null)
+ }
+ }
+
+ override fun info(msg: String?, t: Throwable?) {
+ if (!delegate.isInfoEnabled) {
+ return
+ }
+
+ withMdc {
+ delegate.log(null, fqcn, LocationAwareLogger.INFO_INT, msg, null, t)
+ }
+ }
+
+ override fun info(marker: Marker?, msg: String?) {
+ if (!delegate.isInfoEnabled) {
+ return
+ }
+
+ withMdc {
+ delegate.log(marker, fqcn, LocationAwareLogger.INFO_INT, msg, null, null)
+ }
+ }
+
+ override fun info(marker: Marker?, format: String?, arg: Any?) {
+ if (!delegate.isInfoEnabled) {
+ return
+ }
+
+ withMdc {
+ val formattedMessage = MessageFormatter.format(format, arg).message
+ delegate.log(marker, fqcn, LocationAwareLogger.INFO_INT, formattedMessage, arrayOf(arg), null)
+ }
+ }
+
+ override fun info(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) {
+ if (!delegate.isInfoEnabled) {
+ return
+ }
+
+ withMdc {
+ val formattedMessage = MessageFormatter.format(format, arg1, arg2).message
+ delegate.log(marker, fqcn, LocationAwareLogger.INFO_INT, formattedMessage, arrayOf(arg1, arg2), null)
+ }
+ }
+
+ override fun info(marker: Marker?, format: String?, argArray: Array<Any?>) {
+ if (!delegate.isInfoEnabled) {
+ return
+ }
+
+ withMdc {
+ val formattedMessage = MessageFormatter.arrayFormat(format, argArray).message
+ delegate.log(marker, fqcn, LocationAwareLogger.INFO_INT, formattedMessage, argArray, null)
+ }
+ }
+
+ override fun info(marker: Marker?, msg: String?, t: Throwable?) {
+ if (!delegate.isInfoEnabled) {
+ return
+ }
+
+ withMdc {
+ delegate.log(marker, fqcn, LocationAwareLogger.INFO_INT, msg, null, t)
+ }
+ }
+
+ override fun warn(msg: String?) {
+ if (!delegate.isWarnEnabled) {
+ return
+ }
+
+ withMdc {
+ delegate.log(null, fqcn, LocationAwareLogger.WARN_INT, msg, null, null)
+ }
+ }
+
+ override fun warn(format: String?, arg: Any?) {
+ if (!delegate.isWarnEnabled) {
+ return
+ }
+
+ withMdc {
+ val formattedMessage = MessageFormatter.format(format, arg).message
+ delegate.log(null, fqcn, LocationAwareLogger.WARN_INT, formattedMessage, arrayOf(arg), null)
+ }
+ }
+
+ override fun warn(format: String?, arg1: Any?, arg2: Any?) {
+ if (!delegate.isWarnEnabled) {
+ return
+ }
+
+ withMdc {
+ val formattedMessage = MessageFormatter.format(format, arg1, arg2).message
+ delegate.log(null, fqcn, LocationAwareLogger.WARN_INT, formattedMessage, arrayOf(arg1, arg2), null)
+ }
+ }
+
+ override fun warn(format: String?, argArray: Array<Any?>) {
+ if (!delegate.isWarnEnabled) {
+ return
+ }
+
+ withMdc {
+ val formattedMessage = MessageFormatter.arrayFormat(format, argArray).message
+ delegate.log(null, fqcn, LocationAwareLogger.WARN_INT, formattedMessage, argArray, null)
+ }
+ }
+
+ override fun warn(msg: String?, t: Throwable?) {
+ if (!delegate.isWarnEnabled) {
+ return
+ }
+
+ withMdc {
+ delegate.log(null, fqcn, LocationAwareLogger.WARN_INT, msg, null, t)
+ }
+ }
+
+ override fun warn(marker: Marker?, msg: String?) {
+ if (!delegate.isWarnEnabled) {
+ return
+ }
+
+ withMdc {
+ delegate.log(marker, fqcn, LocationAwareLogger.WARN_INT, msg, null, null)
+ }
+ }
+
+ override fun warn(marker: Marker?, format: String?, arg: Any?) {
+ if (!delegate.isWarnEnabled) {
+ return
+ }
+
+ withMdc {
+ val formattedMessage = MessageFormatter.format(format, arg).message
+ delegate.log(marker, fqcn, LocationAwareLogger.WARN_INT, formattedMessage, arrayOf(arg), null)
+ }
+ }
+
+ override fun warn(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) {
+ if (!delegate.isWarnEnabled) {
+ return
+ }
+
+ withMdc {
+ val formattedMessage = MessageFormatter.format(format, arg1, arg2).message
+ delegate.log(marker, fqcn, LocationAwareLogger.WARN_INT, formattedMessage, arrayOf(arg1, arg2), null)
+ }
+ }
+
+ override fun warn(marker: Marker?, format: String?, argArray: Array<Any?>) {
+ if (!delegate.isWarnEnabled) {
+ return
+ }
+
+ withMdc {
+ val formattedMessage = MessageFormatter.arrayFormat(format, argArray).message
+ delegate.log(marker, fqcn, LocationAwareLogger.WARN_INT, formattedMessage, argArray, null)
+ }
+ }
+
+ override fun warn(marker: Marker?, msg: String?, t: Throwable?) {
+ if (!delegate.isWarnEnabled) {
+ return
+ }
+
+ withMdc {
+ delegate.log(marker, fqcn, LocationAwareLogger.WARN_INT, msg, null, t)
+ }
+ }
+
+ override fun error(msg: String?) {
+ if (!delegate.isErrorEnabled) {
+ return
+ }
+
+ withMdc {
+ delegate.log(null, fqcn, LocationAwareLogger.ERROR_INT, msg, null, null)
+ }
+ }
+
+ override fun error(format: String?, arg: Any?) {
+ if (!delegate.isErrorEnabled) {
+ return
+ }
+
+ withMdc {
+ val formattedMessage = MessageFormatter.format(format, arg).message
+ delegate.log(null, fqcn, LocationAwareLogger.ERROR_INT, formattedMessage, arrayOf(arg), null)
+ }
+ }
+
+ override fun error(format: String?, arg1: Any?, arg2: Any?) {
+ if (!delegate.isErrorEnabled) {
+ return
+ }
+
+ withMdc {
+ val formattedMessage = MessageFormatter.format(format, arg1, arg2).message
+ delegate.log(null, fqcn, LocationAwareLogger.ERROR_INT, formattedMessage, arrayOf(arg1, arg2), null)
+ }
+ }
+
+ override fun error(format: String?, argArray: Array<Any?>) {
+ if (!delegate.isErrorEnabled) {
+ return
+ }
+
+ withMdc {
+ val formattedMessage = MessageFormatter.arrayFormat(format, argArray).message
+ delegate.log(null, fqcn, LocationAwareLogger.ERROR_INT, formattedMessage, argArray, null)
+ }
+ }
+
+ override fun error(msg: String?, t: Throwable?) {
+ if (!delegate.isErrorEnabled) {
+ return
+ }
+
+ withMdc {
+ delegate.log(null, fqcn, LocationAwareLogger.ERROR_INT, msg, null, t)
+ }
+ }
+
+ override fun error(marker: Marker?, msg: String?) {
+ if (!delegate.isErrorEnabled) {
+ return
+ }
+
+ withMdc {
+ delegate.log(marker, fqcn, LocationAwareLogger.ERROR_INT, msg, null, null)
+ }
+ }
+
+ override fun error(marker: Marker?, format: String?, arg: Any?) {
+ if (!delegate.isErrorEnabled) {
+ return
+ }
+
+ withMdc {
+ val formattedMessage = MessageFormatter.format(format, arg).message
+ delegate.log(marker, fqcn, LocationAwareLogger.ERROR_INT, formattedMessage, arrayOf(arg), null)
+ }
+ }
+
+ override fun error(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) {
+ if (!delegate.isErrorEnabled) {
+ return
+ }
+
+ withMdc {
+ val formattedMessage = MessageFormatter.format(format, arg1, arg2).message
+ delegate.log(marker, fqcn, LocationAwareLogger.ERROR_INT, formattedMessage, arrayOf(arg1, arg2), null)
+ }
+ }
+
+ override fun error(marker: Marker?, format: String?, argArray: Array<Any?>) {
+ if (!delegate.isErrorEnabled) {
+ return
+ }
+
+ withMdc {
+ val formattedMessage = MessageFormatter.arrayFormat(format, argArray).message
+ delegate.log(marker, fqcn, LocationAwareLogger.ERROR_INT, formattedMessage, argArray, null)
+ }
+ }
+
+ override fun error(marker: Marker?, msg: String?, t: Throwable?) {
+ if (!delegate.isErrorEnabled) {
+ return
+ }
+
+ withMdc {
+ delegate.log(marker, fqcn, LocationAwareLogger.ERROR_INT, msg, null, t)
+ }
+ }
+}
diff --git a/simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/logging/LocationIgnorantLoggerImpl.kt b/simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/logging/LocationIgnorantLoggerImpl.kt
new file mode 100644
index 00000000..856cecfa
--- /dev/null
+++ b/simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/logging/LocationIgnorantLoggerImpl.kt
@@ -0,0 +1,440 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2019 atlarge-research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.atlarge.odcsim.engine.omega.logging
+
+import com.atlarge.odcsim.SimulationContext
+import org.slf4j.Logger
+import org.slf4j.Marker
+
+/**
+ * A [Logger] implementation that is not aware of the calling location.
+ *
+ * @param ctx The owning [SimulationContext] of this logger.
+ * @param delegate The [Logger] to delegate the messages to.
+ */
+internal class LocationIgnorantLoggerImpl(
+ ctx: SimulationContext,
+ private val delegate: Logger
+) : LoggerImpl(ctx), Logger by delegate {
+ override fun warn(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) {
+ if (!isWarnEnabled) {
+ return
+ }
+
+ withMdc { delegate.warn(marker, format, arg1, arg2) }
+ }
+
+ override fun warn(format: String?, arg1: Any?, arg2: Any?) {
+ if (!isWarnEnabled) {
+ return
+ }
+
+ withMdc { delegate.warn(format, arg1, arg2) }
+ }
+
+ override fun warn(msg: String?) {
+ if (!isWarnEnabled) {
+ return
+ }
+
+ withMdc { delegate.warn(msg) }
+ }
+
+ override fun warn(marker: Marker?, format: String?, arg: Any?) {
+ if (!isWarnEnabled) {
+ return
+ }
+
+ withMdc { delegate.warn(marker, format, arg) }
+ }
+
+ override fun warn(marker: Marker?, format: String?, vararg arguments: Any?) {
+ if (!isWarnEnabled) {
+ return
+ }
+
+ withMdc { delegate.warn(marker, format, arguments) }
+ }
+
+ override fun warn(format: String?, arg: Any?) {
+ if (!isWarnEnabled) {
+ return
+ }
+
+ withMdc { delegate.warn(format, arg) }
+ }
+
+ override fun warn(marker: Marker?, msg: String?) {
+ if (!isWarnEnabled) {
+ return
+ }
+
+ withMdc { delegate.warn(marker, msg) }
+ }
+
+ override fun warn(msg: String?, t: Throwable?) {
+ if (!isWarnEnabled) {
+ return
+ }
+
+ withMdc { delegate.warn(msg, t) }
+ }
+
+ override fun warn(format: String?, vararg arguments: Any?) {
+ if (!isWarnEnabled) {
+ return
+ }
+
+ withMdc { delegate.warn(format, *arguments) }
+ }
+
+ override fun warn(marker: Marker?, msg: String?, t: Throwable?) {
+ if (!isWarnEnabled) {
+ return
+ }
+
+ withMdc { delegate.warn(marker, msg, t) }
+ }
+
+ override fun info(marker: Marker?, format: String?, vararg arguments: Any?) {
+ if (!isInfoEnabled) {
+ return
+ }
+
+ withMdc { delegate.info(marker, format, *arguments) }
+ }
+
+ override fun info(format: String?, arg: Any?) {
+ if (!isInfoEnabled) {
+ return
+ }
+
+ withMdc { delegate.info(format, arg) }
+ }
+
+ override fun info(marker: Marker?, msg: String?, t: Throwable?) {
+ if (!isInfoEnabled) {
+ return
+ }
+
+ withMdc { delegate.info(marker, msg, t) }
+ }
+
+ override fun info(msg: String?) {
+ if (!isInfoEnabled) {
+ return
+ }
+
+ withMdc { delegate.info(msg) }
+ }
+
+ override fun info(format: String?, vararg arguments: Any?) {
+ if (!isInfoEnabled) {
+ return
+ }
+
+ withMdc { delegate.info(format, *arguments) }
+ }
+
+ override fun info(format: String?, arg1: Any?, arg2: Any?) {
+ if (!isInfoEnabled) {
+ return
+ }
+
+ withMdc { delegate.info(format, arg1, arg2) }
+ }
+
+ override fun info(marker: Marker?, msg: String?) {
+ if (!isInfoEnabled) {
+ return
+ }
+
+ withMdc { delegate.info(marker, msg) }
+ }
+
+ override fun info(marker: Marker?, format: String?, arg: Any?) {
+ if (!isInfoEnabled) {
+ return
+ }
+
+ withMdc { delegate.info(marker, format, arg) }
+ }
+
+ override fun info(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) {
+ if (!isInfoEnabled) {
+ return
+ }
+
+ withMdc { delegate.info(marker, format, arg1, arg2) }
+ }
+
+ override fun info(msg: String?, t: Throwable?) {
+ if (!isInfoEnabled) {
+ return
+ }
+
+ withMdc { delegate.info(msg, t) }
+ }
+
+ override fun error(msg: String?) {
+ if (!isErrorEnabled) {
+ return
+ }
+
+ withMdc { delegate.error(msg) }
+ }
+
+ override fun error(marker: Marker?, msg: String?) {
+ if (!isErrorEnabled) {
+ return
+ }
+
+ withMdc { delegate.error(marker, msg) }
+ }
+
+ override fun error(format: String?, vararg arguments: Any?) {
+ if (!isErrorEnabled) {
+ return
+ }
+
+ withMdc { delegate.error(format, *arguments) }
+ }
+
+ override fun error(format: String?, arg: Any?) {
+ if (!isErrorEnabled) {
+ return
+ }
+
+ withMdc { delegate.error(format, arg) }
+ }
+
+ override fun error(msg: String?, t: Throwable?) {
+ if (!isErrorEnabled) {
+ return
+ }
+
+ withMdc { delegate.error(msg, t) }
+ }
+
+ override fun error(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) {
+ if (!isErrorEnabled) {
+ return
+ }
+
+ withMdc { delegate.error(marker, format, arg1, arg2) }
+ }
+
+ override fun error(marker: Marker?, format: String?, vararg arguments: Any?) {
+ if (!isErrorEnabled) {
+ return
+ }
+
+ withMdc { delegate.error(marker, format, *arguments) }
+ }
+
+ override fun error(marker: Marker?, msg: String?, t: Throwable?) {
+ if (!isErrorEnabled) {
+ return
+ }
+
+ withMdc { delegate.error(marker, msg, t) }
+ }
+
+ override fun error(format: String?, arg1: Any?, arg2: Any?) {
+ if (!isErrorEnabled) {
+ return
+ }
+
+ withMdc { delegate.error(format, arg1, arg2) }
+ }
+
+ override fun error(marker: Marker?, format: String?, arg: Any?) {
+ if (!isErrorEnabled) {
+ return
+ }
+
+ withMdc { delegate.error(marker, format, arg) }
+ }
+
+ override fun debug(format: String?, vararg arguments: Any?) {
+ if (!isDebugEnabled) {
+ return
+ }
+
+ withMdc { delegate.debug(format, *arguments) }
+ }
+
+ override fun debug(format: String?, arg1: Any?, arg2: Any?) {
+ if (!isDebugEnabled) {
+ return
+ }
+
+ withMdc { delegate.debug(format, arg1, arg2) }
+ }
+
+ override fun debug(msg: String?, t: Throwable?) {
+ if (!isDebugEnabled) {
+ return
+ }
+
+ withMdc { delegate.debug(msg, t) }
+ }
+
+ override fun debug(format: String?, arg: Any?) {
+ if (!isDebugEnabled) {
+ return
+ }
+
+ withMdc { delegate.debug(format, arg) }
+ }
+
+ override fun debug(marker: Marker?, msg: String?) {
+ if (!isDebugEnabled) {
+ return
+ }
+
+ withMdc { delegate.debug(marker, msg) }
+ }
+
+ override fun debug(msg: String?) {
+ if (!isDebugEnabled) {
+ return
+ }
+
+ withMdc { delegate.debug(msg) }
+ }
+
+ override fun debug(marker: Marker?, msg: String?, t: Throwable?) {
+ if (!isDebugEnabled) {
+ return
+ }
+
+ withMdc { delegate.debug(marker, msg, t) }
+ }
+
+ override fun debug(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) {
+ if (!isDebugEnabled) {
+ return
+ }
+
+ withMdc { delegate.debug(marker, format, arg1, arg2) }
+ }
+
+ override fun debug(marker: Marker?, format: String?, arg: Any?) {
+ if (!isDebugEnabled) {
+ return
+ }
+
+ withMdc { delegate.debug(marker, format, arg) }
+ }
+
+ override fun debug(marker: Marker?, format: String?, vararg arguments: Any?) {
+ if (!isDebugEnabled) {
+ return
+ }
+
+ withMdc { delegate.debug(marker, format, *arguments) }
+ }
+
+ override fun trace(format: String?, arg: Any?) {
+ if (!isTraceEnabled) {
+ return
+ }
+
+ withMdc { delegate.trace(format, arg) }
+ }
+
+ override fun trace(marker: Marker?, msg: String?) {
+ if (!isTraceEnabled) {
+ return
+ }
+
+ withMdc { delegate.trace(marker, msg) }
+ }
+
+ override fun trace(msg: String?) {
+ if (!isTraceEnabled) {
+ return
+ }
+
+ withMdc { delegate.trace(msg) }
+ }
+
+ override fun trace(msg: String?, t: Throwable?) {
+ if (!isTraceEnabled) {
+ return
+ }
+
+ withMdc { delegate.trace(msg, t) }
+ }
+
+ override fun trace(format: String?, arg1: Any?, arg2: Any?) {
+ if (!isTraceEnabled) {
+ return
+ }
+
+ withMdc { delegate.trace(format, arg1, arg2) }
+ }
+
+ override fun trace(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) {
+ if (!isTraceEnabled) {
+ return
+ }
+
+ withMdc { delegate.trace(marker, format, arg1, arg2) }
+ }
+
+ override fun trace(marker: Marker?, format: String?, arg: Any?) {
+ if (!isTraceEnabled) {
+ return
+ }
+
+ withMdc { delegate.trace(marker, format, arg) }
+ }
+
+ override fun trace(marker: Marker?, format: String?, vararg argArray: Any?) {
+ if (!isTraceEnabled) {
+ return
+ }
+
+ withMdc { delegate.trace(marker, format, *argArray) }
+ }
+
+ override fun trace(marker: Marker?, msg: String?, t: Throwable?) {
+ if (!isTraceEnabled) {
+ return
+ }
+
+ withMdc { delegate.trace(marker, msg, t) }
+ }
+
+ override fun trace(format: String?, vararg arguments: Any?) {
+ if (!isTraceEnabled) {
+ return
+ }
+
+ withMdc { delegate.trace(format, *arguments) }
+ }
+}
diff --git a/simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/logging/LoggerImpl.kt b/simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/logging/LoggerImpl.kt
new file mode 100644
index 00000000..1adcfdc0
--- /dev/null
+++ b/simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/logging/LoggerImpl.kt
@@ -0,0 +1,74 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2019 atlarge-research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package com.atlarge.odcsim.engine.omega.logging
+
+import com.atlarge.odcsim.SimulationContext
+import org.slf4j.Logger
+import org.slf4j.LoggerFactory
+import org.slf4j.MDC
+import org.slf4j.spi.LocationAwareLogger
+
+/**
+ * An actor-specific [Logger] implementation.
+ *
+ * @param ctx The owning [SimulationContext] of this logger.
+ */
+internal abstract class LoggerImpl internal constructor(protected val ctx: SimulationContext) : Logger {
+ /**
+ * Configure [MDC] with actor-specific information.
+ */
+ protected inline fun withMdc(block: () -> Unit) {
+ MDC.put(MDC_PROCESS_REF, ctx.domain.name)
+ MDC.put(MDC_PROCESS_TIME, String.format("%d", ctx.clock.millis()))
+ try {
+ block()
+ } finally {
+ MDC.remove(MDC_PROCESS_TIME)
+ MDC.remove(MDC_PROCESS_REF)
+ }
+ }
+
+ /**
+ * Mapped Diagnostic Context (MDC) attribute names.
+ */
+ companion object {
+ val MDC_PROCESS_TIME = "process.time"
+ val MDC_PROCESS_REF = "process.ref"
+
+ /**
+ * Create a [Logger] for the specified [ActorContext].
+ *
+ * @param ctx The actor context to create the logger for.
+ */
+ operator fun invoke(ctx: SimulationContext): Logger {
+ val logger = LoggerFactory.getLogger(ctx.javaClass)
+ return if (logger is LocationAwareLogger) {
+ LocationAwareLoggerImpl(ctx, logger)
+ } else {
+ LocationIgnorantLoggerImpl(ctx, logger)
+ }
+ }
+ }
+}
diff --git a/simulator/odcsim/odcsim-engine-omega/src/main/resources/META-INF/services/com.atlarge.odcsim.SimulationEngineProvider b/simulator/odcsim/odcsim-engine-omega/src/main/resources/META-INF/services/com.atlarge.odcsim.SimulationEngineProvider
new file mode 100644
index 00000000..1131cebd
--- /dev/null
+++ b/simulator/odcsim/odcsim-engine-omega/src/main/resources/META-INF/services/com.atlarge.odcsim.SimulationEngineProvider
@@ -0,0 +1 @@
+com.atlarge.odcsim.engine.omega.OmegaSimulationEngineProvider