Repository: ktorio/ktor
File: ktor-shared/ktor-websockets/common/src/io/ktor/websocket/DefaultWebSocketSession.kt (Kotlin)

Code before:
        }

    override var pingIntervalMillis: Long = pingInterval
        set(newValue) {
            field = newValue
            runOrCancelPinger()
        }

    override var timeoutMillis: Long = timeoutMillis
        set(newValue) {
            field = newValue
            runOrCancelPinger()
        }

    override val closeReason: Deferred<CloseReason?> = closeReasonRef

    @OptIn(InternalAPI::class)
    override fun start(negotiatedExtensions: List<WebSocketExtension<*>>) {
        if (!started.compareAndSet(false, true)) {
            error("WebSocket session $this is already started.")
        }

        if (LOGGER.isTraceEnabled) {
            LOGGER.trace(
                "Starting default WebSocketSession($this) " +
                    "with negotiated extensions: ${negotiatedExtensions.joinToString()}"
            )
        }

        _extensions.addAll(negotiatedExtensions)
        runOrCancelPinger()
        runIncomingProcessor(ponger(outgoing))
        runOutgoingProcessor()
    }

    /**
     * Close session with GOING_AWAY reason
     */
    suspend fun goingAway(message: String = "Server is going down") {
        sendCloseSequence(CloseReason(CloseReason.Codes.GOING_AWAY, message))
    }

    override suspend fun flush() {
        raw.flush()
    }

    @Deprecated(
        "Use cancel() instead.",
        ReplaceWith("cancel()", "kotlinx.coroutines.cancel"),
        level = DeprecationLevel.ERROR
    )

Review comment (suggestion):
Instead of duplicating the check here, could you please introduce an inline function in `ktor-utils/common/src/io/ktor/util/logging/Logger.kt`?

```kotlin
/**
 * Check `isTraceEnabled` flag before logging to save some memory allocations.
 */
public inline fun Logger.trace(message: () -> String) {
    if (isTraceEnabled) trace(message())
}
```

Then we can start replacing our other trace calls with this to save on memory allocations.

Code after:
        }

    override var pingIntervalMillis: Long = pingInterval
        set(newValue) {
            field = newValue
            runOrCancelPinger()
        }

    override var timeoutMillis: Long = timeoutMillis
        set(newValue) {
            field = newValue
            runOrCancelPinger()
        }

    override val closeReason: Deferred<CloseReason?> = closeReasonRef

    @OptIn(InternalAPI::class)
    override fun start(negotiatedExtensions: List<WebSocketExtension<*>>) {
        if (!started.compareAndSet(false, true)) {
            error("WebSocket session $this is already started.")
        }

        LOGGER.trace {
            "Starting default WebSocketSession($this) " +
                "with negotiated extensions: ${negotiatedExtensions.joinToString()}"
        }

        _extensions.addAll(negotiatedExtensions)
        runOrCancelPinger()
        runIncomingProcessor(ponger(outgoing))
        runOutgoingProcessor()
    }

    /**
     * Close session with GOING_AWAY reason
     */
    suspend fun goingAway(message: String = "Server is going down") {
        sendCloseSequence(CloseReason(CloseReason.Codes.GOING_AWAY, message))
    }

    override suspend fun flush() {
        raw.flush()
    }

    @Deprecated(
        "Use cancel() instead.",
        ReplaceWith("cancel()", "kotlinx.coroutines.cancel"),
        level = DeprecationLevel.ERROR
    )
    override fun terminate() {
        context.cancel()