Skip to content

Commit

Permalink
Forward Dokka Generator messages to Gradle logger (#3833)
Browse files Browse the repository at this point in the history
* Forward Dokka Generator messages to Gradle logger
  • Loading branch information
adam-enko authored Oct 17, 2024
1 parent 0a77c0e commit b887a8d
Show file tree
Hide file tree
Showing 5 changed files with 342 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,30 @@ package org.jetbrains.dokka.gradle.internal

import org.jetbrains.dokka.utilities.DokkaLogger
import org.jetbrains.dokka.utilities.LoggingLevel
import org.jetbrains.dokka.utilities.LoggingLevel.*
import org.slf4j.Logger
import java.io.File
import java.io.Writer
import java.util.concurrent.atomic.AtomicInteger

/**
* Logs all Dokka messages to a file.
* A logger for [org.jetbrains.dokka.DokkaGenerator].
*
* All messages will be written to [logWriter] and forwarded to a Gradle [logger] (at an appropriate log level).
*
* [org.jetbrains.dokka.DokkaGenerator] makes heavy use of coroutines and parallelization,
* so use thread-safe practices when handling logging messages.
*
* @param logTag Prepend all [logger] messages with this tag.
* @see org.jetbrains.dokka.DokkaGenerator
*/
// Gradle causes OOM errors when there is a lot of console output. Logging to file is a workaround.
// https://github.com/gradle/gradle/issues/23965
// https://github.com/gradle/gradle/issues/15621
internal class LoggerAdapter(
outputFile: File
outputFile: File,
private val logger: Logger,
private val logTag: String,
) : DokkaLogger, AutoCloseable {

private val logWriter: Writer
Expand All @@ -43,22 +53,32 @@ internal class LoggerAdapter(
get() = errorsCounter.get()
set(value) = errorsCounter.set(value)

override fun debug(message: String) = log(LoggingLevel.DEBUG, message)
override fun progress(message: String) = log(LoggingLevel.PROGRESS, message)
override fun info(message: String) = log(LoggingLevel.INFO, message)
override fun debug(message: String) = log(DEBUG, message)
override fun progress(message: String) = log(PROGRESS, message)
override fun info(message: String) = log(INFO, message)

override fun warn(message: String) {
warningsCount++
log(LoggingLevel.WARN, message)
log(WARN, message)
}

override fun error(message: String) {
errorsCount++
log(LoggingLevel.ERROR, message)
log(ERROR, message)
}

@Synchronized
private fun log(level: LoggingLevel, message: String) {
when (level) {
PROGRESS,
INFO -> logger.info("[$logTag] " + message.prependIndent().trimStart())

DEBUG -> logger.debug("[$logTag] " + message.prependIndent().trimStart())

WARN -> logger.warn("w: [$logTag] " + message.prependIndent().trimStart())

ERROR -> logger.error("e: [$logTag] " + message.prependIndent().trimStart())
}
logWriter.appendLine("[${level.name}] $message")
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ constructor(
workQueue.submit(DokkaGeneratorWorker::class) {
this.dokkaParameters.set(dokkaConfiguration)
this.logFile.set(workerLogFile)
this.taskPath.set(this@DokkaGenerateTask.path)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
package org.jetbrains.dokka.gradle.workers

import org.gradle.api.file.RegularFileProperty
import org.gradle.api.logging.Logger
import org.gradle.api.logging.Logging
import org.gradle.api.provider.Property
import org.gradle.workers.WorkAction
import org.gradle.workers.WorkParameters
Expand All @@ -27,6 +29,12 @@ abstract class DokkaGeneratorWorker : WorkAction<DokkaGeneratorWorker.Parameters
interface Parameters : WorkParameters {
val dokkaParameters: Property<DokkaConfiguration>
val logFile: RegularFileProperty

/**
* The [org.gradle.api.Task.getPath] of the task that invokes this worker.
* Only used in log messages.
*/
val taskPath: Property<String>
}

override fun execute() {
Expand Down Expand Up @@ -56,7 +64,11 @@ abstract class DokkaGeneratorWorker : WorkAction<DokkaGeneratorWorker.Parameters
logFile: File,
dokkaParameters: DokkaConfiguration
) {
LoggerAdapter(logFile).use { logger ->
LoggerAdapter(
logFile,
logger,
logTag = parameters.taskPath.get(),
).use { logger ->
logger.progress("Executing DokkaGeneratorWorker with dokkaParameters: $dokkaParameters")

val generator = DokkaGenerator(dokkaParameters, logger)
Expand All @@ -69,6 +81,8 @@ abstract class DokkaGeneratorWorker : WorkAction<DokkaGeneratorWorker.Parameters

@DokkaInternalApi
companion object {
private val logger: Logger = Logging.getLogger(DokkaGeneratorWorker::class.java)

// can't use kotlin.Duration or kotlin.time.measureTime {} because
// the implementation isn't stable across Kotlin versions
private fun measureTime(block: () -> Unit): Duration =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package internal

import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.collections.shouldContainExactly
import io.kotest.matchers.shouldBe
import org.jetbrains.dokka.gradle.internal.LoggerAdapter
import org.slf4j.event.SubstituteLoggingEvent
import org.slf4j.helpers.NOPLogger
import org.slf4j.helpers.SubstituteLoggerFactory
import kotlin.io.path.createTempFile
import kotlin.io.path.readText

class LoggerAdapterTest : FunSpec({

test("slf4j logger output") {
val logFactory = SubstituteLoggerFactory()

val loggerAdapter = LoggerAdapter(
createTempFile().toFile(),
logFactory.getLogger("test"),
"LOG-TAG"
)

loggerAdapter.error("an error msg")
loggerAdapter.warn("a warn msg")
loggerAdapter.debug("a debug msg")
loggerAdapter.info("an info msg")
loggerAdapter.progress("a progress msg")

loggerAdapter.errorsCount shouldBe 1
loggerAdapter.warningsCount shouldBe 1

logFactory.eventQueue.map { it.render() }.shouldContainExactly(
"ERROR e: [LOG-TAG] an error msg",
"WARN w: [LOG-TAG] a warn msg",
"DEBUG [LOG-TAG] a debug msg",
"INFO [LOG-TAG] an info msg",
"INFO [LOG-TAG] a progress msg",
)
}

test("logfile output") {
val logFile = createTempFile()

LoggerAdapter(
logFile.toFile(),
NOPLogger.NOP_LOGGER,
"LOG-TAG"
).use { loggerAdapter ->
loggerAdapter.error("an error msg")
loggerAdapter.warn("a warn msg")
loggerAdapter.debug("a debug msg")
loggerAdapter.info("an info msg")
loggerAdapter.progress("a progress msg")

loggerAdapter.errorsCount shouldBe 1
loggerAdapter.warningsCount shouldBe 1
}

logFile.readText() shouldBe """
|[ERROR] an error msg
|[WARN] a warn msg
|[DEBUG] a debug msg
|[INFO] an info msg
|[PROGRESS] a progress msg
|
""".trimMargin()
}

}) {
companion object {
private fun SubstituteLoggingEvent.render(): String = buildString {
append("$level")
append(" ")
append(message)
}
}
}
Loading

0 comments on commit b887a8d

Please sign in to comment.