Skip to content

Commit

Permalink
Logging in CLI
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcinAman committed Jun 22, 2021
1 parent 2832b9a commit c1f87fa
Show file tree
Hide file tree
Showing 19 changed files with 181 additions and 82 deletions.
24 changes: 23 additions & 1 deletion core/api/core.api
Expand Up @@ -4197,10 +4197,13 @@ public final class org/jetbrains/dokka/utilities/AssociateWithNotNullKt {
}

public final class org/jetbrains/dokka/utilities/DokkaConsoleLogger : org/jetbrains/dokka/utilities/DokkaLogger {
public static final field INSTANCE Lorg/jetbrains/dokka/utilities/DokkaConsoleLogger;
public fun <init> ()V
public fun <init> (Lorg/jetbrains/dokka/utilities/LoggingLevel;Lorg/jetbrains/dokka/utilities/MessageEmitter;)V
public synthetic fun <init> (Lorg/jetbrains/dokka/utilities/LoggingLevel;Lorg/jetbrains/dokka/utilities/MessageEmitter;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun debug (Ljava/lang/String;)V
public fun error (Ljava/lang/String;)V
public fun getErrorsCount ()I
public final fun getMinLevel ()Lorg/jetbrains/dokka/utilities/LoggingLevel;
public fun getWarningsCount ()I
public fun info (Ljava/lang/String;)V
public fun progress (Ljava/lang/String;)V
Expand Down Expand Up @@ -4236,6 +4239,25 @@ public final class org/jetbrains/dokka/utilities/JsonKt {
public static final fun toJsonString (Ljava/lang/Object;)Ljava/lang/String;
}

public final class org/jetbrains/dokka/utilities/LoggingLevel : java/lang/Enum {
public static final field DEBUG Lorg/jetbrains/dokka/utilities/LoggingLevel;
public static final field ERROR Lorg/jetbrains/dokka/utilities/LoggingLevel;
public static final field INFO Lorg/jetbrains/dokka/utilities/LoggingLevel;
public static final field PROGRESS Lorg/jetbrains/dokka/utilities/LoggingLevel;
public static final field WARN Lorg/jetbrains/dokka/utilities/LoggingLevel;
public final fun getIndex ()I
public static fun valueOf (Ljava/lang/String;)Lorg/jetbrains/dokka/utilities/LoggingLevel;
public static fun values ()[Lorg/jetbrains/dokka/utilities/LoggingLevel;
}

public abstract interface class org/jetbrains/dokka/utilities/MessageEmitter : kotlin/jvm/functions/Function1 {
public static final field Companion Lorg/jetbrains/dokka/utilities/MessageEmitter$Companion;
}

public final class org/jetbrains/dokka/utilities/MessageEmitter$Companion {
public final fun getConsoleEmitter ()Lorg/jetbrains/dokka/utilities/MessageEmitter;
}

public final class org/jetbrains/dokka/utilities/ParallelCollectionOperationsKt {
public static final fun parallelForEach (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
public static final fun parallelMap (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function2;Lkotlin/coroutines/Continuation;)Ljava/lang/Object;
Expand Down
59 changes: 47 additions & 12 deletions core/src/main/kotlin/utilities/DokkaLogging.kt
Expand Up @@ -11,28 +11,63 @@ interface DokkaLogger {
}

fun DokkaLogger.report() {
if (DokkaConsoleLogger.warningsCount > 0 || DokkaConsoleLogger.errorsCount > 0) {
info("Generation completed with ${DokkaConsoleLogger.warningsCount} warning" +
(if(DokkaConsoleLogger.warningsCount == 1) "" else "s") +
" and ${DokkaConsoleLogger.errorsCount} error" +
if(DokkaConsoleLogger.errorsCount == 1) "" else "s"
if (warningsCount > 0 || errorsCount > 0) {
info(
"Generation completed with $warningsCount warning" +
(if (warningsCount == 1) "" else "s") +
" and $errorsCount error" +
if (errorsCount == 1) "" else "s"
)
} else {
info("generation completed successfully")
info("Generation completed successfully")
}
}

object DokkaConsoleLogger : DokkaLogger {
enum class LoggingLevel(val index: Int) {
DEBUG(0), PROGRESS(1), INFO(2), WARN(3), ERROR(4);
}

/**
* Used to decouple the transport layer from logger and make it convenient for testing
*/
fun interface MessageEmitter : (String) -> Unit {
companion object {
val consoleEmitter: MessageEmitter = MessageEmitter { message -> println(message) }
}
}

class DokkaConsoleLogger(
val minLevel: LoggingLevel = LoggingLevel.DEBUG,
private val emitter: MessageEmitter = MessageEmitter.consoleEmitter
) : DokkaLogger {
override var warningsCount: Int = 0
override var errorsCount: Int = 0

override fun debug(message: String)= println(message)
override fun debug(message: String) {
if (shouldBeDisplayed(LoggingLevel.DEBUG)) emitter(message)
}

override fun progress(message: String) = println("PROGRESS: $message")
override fun progress(message: String) {
if (shouldBeDisplayed(LoggingLevel.PROGRESS)) emitter("PROGRESS: $message")
}

override fun info(message: String) = println(message)
override fun info(message: String) {
if (shouldBeDisplayed(LoggingLevel.INFO)) emitter(message)
}

override fun warn(message: String) = println("WARN: $message").also { warningsCount++ }
override fun warn(message: String) {
if (shouldBeDisplayed(LoggingLevel.WARN)) {
emitter("WARN: $message")
}
warningsCount++
}

override fun error(message: String) {
if (shouldBeDisplayed(LoggingLevel.ERROR)) {
emitter("ERROR: $message")
}
errorsCount++
}

override fun error(message: String) = println("ERROR: $message").also { errorsCount++ }
private fun shouldBeDisplayed(messageLevel: LoggingLevel): Boolean = messageLevel.index >= minLevel.index
}
23 changes: 0 additions & 23 deletions core/test-api/api/test-api.api
Expand Up @@ -10,29 +10,6 @@ public final class org/jetbrains/dokka/testApi/context/MockContext : org/jetbrai
public fun single (Lorg/jetbrains/dokka/plugability/ExtensionPoint;)Ljava/lang/Object;
}

public final class org/jetbrains/dokka/testApi/logger/FilteringLogger : org/jetbrains/dokka/utilities/DokkaLogger {
public fun <init> (Lorg/jetbrains/dokka/testApi/logger/FilteringLogger$Level;Lorg/jetbrains/dokka/utilities/DokkaLogger;)V
public fun debug (Ljava/lang/String;)V
public fun error (Ljava/lang/String;)V
public fun getErrorsCount ()I
public fun getWarningsCount ()I
public fun info (Ljava/lang/String;)V
public fun progress (Ljava/lang/String;)V
public fun setErrorsCount (I)V
public fun setWarningsCount (I)V
public fun warn (Ljava/lang/String;)V
}

public final class org/jetbrains/dokka/testApi/logger/FilteringLogger$Level : java/lang/Enum {
public static final field Debug Lorg/jetbrains/dokka/testApi/logger/FilteringLogger$Level;
public static final field Error Lorg/jetbrains/dokka/testApi/logger/FilteringLogger$Level;
public static final field Info Lorg/jetbrains/dokka/testApi/logger/FilteringLogger$Level;
public static final field Progress Lorg/jetbrains/dokka/testApi/logger/FilteringLogger$Level;
public static final field Warn Lorg/jetbrains/dokka/testApi/logger/FilteringLogger$Level;
public static fun valueOf (Ljava/lang/String;)Lorg/jetbrains/dokka/testApi/logger/FilteringLogger$Level;
public static fun values ()[Lorg/jetbrains/dokka/testApi/logger/FilteringLogger$Level;
}

public final class org/jetbrains/dokka/testApi/logger/TestLogger : org/jetbrains/dokka/utilities/DokkaLogger {
public fun <init> (Lorg/jetbrains/dokka/utilities/DokkaLogger;)V
public fun debug (Ljava/lang/String;)V
Expand Down
3 changes: 2 additions & 1 deletion core/test-api/src/main/kotlin/testApi/context/MockContext.kt
Expand Up @@ -5,6 +5,7 @@ import org.jetbrains.dokka.plugability.DokkaContext
import org.jetbrains.dokka.plugability.DokkaPlugin
import org.jetbrains.dokka.plugability.ExtensionPoint
import org.jetbrains.dokka.utilities.DokkaConsoleLogger
import org.jetbrains.dokka.utilities.LoggingLevel
import kotlin.reflect.KClass
import kotlin.reflect.KMutableProperty
import kotlin.reflect.full.memberProperties
Expand All @@ -31,7 +32,7 @@ class MockContext(

override fun <T : Any, E : ExtensionPoint<T>> single(point: E): T = get(point).single()

override val logger = DokkaConsoleLogger
override val logger = DokkaConsoleLogger(LoggingLevel.DEBUG)

override val configuration: DokkaConfiguration
get() = testConfiguration ?: throw IllegalStateException("This mock context doesn't provide configuration")
Expand Down
31 changes: 0 additions & 31 deletions core/test-api/src/main/kotlin/testApi/logger/TestLogger.kt
Expand Up @@ -46,34 +46,3 @@ class TestLogger(private val logger: DokkaLogger) : DokkaLogger {
logger.error(message)
}
}

class FilteringLogger(
private val minLevel: Level,
private val downstream: DokkaLogger
) : DokkaLogger {
enum class Level { Debug, Info, Progress, Warn, Error }

override var warningsCount: Int by downstream::warningsCount

override var errorsCount by downstream::errorsCount

override fun debug(message: String) {
if (minLevel <= Level.Debug) downstream.debug(message)
}

override fun info(message: String) {
if (minLevel <= Level.Info) downstream.info(message)
}

override fun progress(message: String) {
if (minLevel <= Level.Progress) downstream.progress(message)
}

override fun warn(message: String) {
if (minLevel <= Level.Warn) downstream.warn(message)
}

override fun error(message: String) {
if (minLevel <= Level.Error) downstream.error(message)
}
}
2 changes: 2 additions & 0 deletions docs/src/doc/docs/user_guide/cli/usage.md
Expand Up @@ -41,6 +41,8 @@ Dokka supports the following command line arguments:
* `-jdkVersion` - version of JDK to use for linking to JDK JavaDoc
* `-analysisPlatform` - platform used for analysis, see the [Platforms](#platforms) section
* `-dependentSourceSets` - list of dependent source sets in format `moduleName/sourceSetName`, separated by `;`
* `-loggingLevel` - one of `DEBUG`, `PROGRESS`, `INFO`, `WARN`, `ERROR`. Defaults to `DEBUG`. Please note that this argument can't be passed in JSON.


You can also use a JSON file with Dokka configuration:
```
Expand Down
Expand Up @@ -155,6 +155,7 @@ class CliIntegrationTest : AbstractCliIntegrationTest() {
val process = ProcessBuilder(
"java", "-jar", cliJarFile.path,
"-outputDir", dokkaOutputDir.path,
"-loggingLevel", "DEBUG",
"-pluginsClasspath", basePluginJarFile.path,
"-sourceSet",
buildString {
Expand All @@ -166,6 +167,7 @@ class CliIntegrationTest : AbstractCliIntegrationTest() {

val result = process.awaitProcessResult()
assertEquals(0, result.exitCode, "Expected exitCode 0 (Success)")
assertTrue(result.output.contains("Loaded plugins: "), "Expected output to not contain info logs")

assertTrue(dokkaOutputDir.isDirectory, "Missing dokka output directory")

Expand All @@ -181,4 +183,26 @@ class CliIntegrationTest : AbstractCliIntegrationTest() {
val navigationHtml = File(dokkaOutputDir, "navigation.html")
assertTrue(navigationHtml.isFile, "Missing navigation.html")
}

@Test
fun `logging level should be respected`(){
val dokkaOutputDir = File(projectDir, "output")
assertTrue(dokkaOutputDir.mkdirs())
val process = ProcessBuilder(
"java", "-jar", cliJarFile.path,
"-outputDir", dokkaOutputDir.path,
"-loggingLevel", "WARN",
"-pluginsClasspath", basePluginJarFile.path,
"-sourceSet",
buildString {
append(" -src ${File(projectDir, "src").path}")
}
)
.redirectErrorStream(true)
.start()

val result = process.awaitProcessResult()
assertEquals(0, result.exitCode, "Expected exitCode 0 (Success)")
assertFalse(result.output.contains("Loaded plugins: "), "Expected output to not contain info logs")
}
}
Expand Up @@ -85,7 +85,7 @@ class MultiModuleTestBuilder : TestBuilder<MultiModuleTestMethods>() {
)
}

abstract class MultiModuleAbstractTest(logger: TestLogger = TestLogger(DokkaConsoleLogger)) :
abstract class MultiModuleAbstractTest(logger: TestLogger = TestLogger(DokkaConsoleLogger())) :
AbstractTest<MultiModuleTestMethods, MultiModuleTestBuilder, MultiModuleDokkaTestGenerator>(
::MultiModuleTestBuilder,
::MultiModuleDokkaTestGenerator,
Expand Down
Expand Up @@ -14,8 +14,8 @@ import org.jetbrains.dokka.base.transformers.pages.comments.CommentsToContentCon
fun testPage(callback: PageContentBuilder.DocumentableContentBuilder.() -> Unit): RawTestPage {
val content = PageContentBuilder(
EmptyCommentConverter,
KotlinSignatureProvider(EmptyCommentConverter, DokkaConsoleLogger),
DokkaConsoleLogger
KotlinSignatureProvider(EmptyCommentConverter, DokkaConsoleLogger()),
DokkaConsoleLogger()
).contentFor(
DRI.topLevel,
emptySet(),
Expand Down
Expand Up @@ -12,6 +12,7 @@ import org.jetbrains.dokka.testApi.logger.TestLogger
import org.jetbrains.dokka.testApi.testRunner.*
import org.jetbrains.dokka.utilities.DokkaConsoleLogger
import org.jetbrains.dokka.utilities.DokkaLogger
import org.jetbrains.dokka.utilities.LoggingLevel

class BaseDokkaTestGenerator(
configuration: DokkaConfiguration,
Expand Down Expand Up @@ -101,7 +102,7 @@ class BaseTestBuilder : TestBuilder<BaseTestMethods>() {
)
}

abstract class BaseAbstractTest(logger: TestLogger = TestLogger(DokkaConsoleLogger)) : AbstractTest<BaseTestMethods, BaseTestBuilder, BaseDokkaTestGenerator>(
abstract class BaseAbstractTest(logger: TestLogger = TestLogger(DokkaConsoleLogger(LoggingLevel.DEBUG))) : AbstractTest<BaseTestMethods, BaseTestBuilder, BaseDokkaTestGenerator>(
::BaseTestBuilder,
::BaseDokkaTestGenerator,
logger,
Expand Down
2 changes: 1 addition & 1 deletion plugins/base/src/test/kotlin/basic/FailOnWarningTest.kt
Expand Up @@ -116,7 +116,7 @@ class FailOnWarningTest : BaseAbstractTest() {
}

private class ZeroErrorOrWarningCountDokkaLogger(
logger: DokkaLogger = DokkaConsoleLogger
logger: DokkaLogger = DokkaConsoleLogger()
) : DokkaLogger by logger {
override var warningsCount: Int = 0
override var errorsCount: Int = 0
Expand Down
44 changes: 44 additions & 0 deletions plugins/base/src/test/kotlin/basic/LoggerTest.kt
@@ -0,0 +1,44 @@
package basic

import org.jetbrains.dokka.utilities.DokkaConsoleLogger
import org.jetbrains.dokka.utilities.LoggingLevel
import org.jetbrains.dokka.utilities.MessageEmitter
import org.junit.jupiter.api.Test
import kotlin.test.assertFalse
import kotlin.test.assertTrue

class LoggerTest {
class AccumulatingEmitter : MessageEmitter {
val messages: MutableList<String> = mutableListOf()
override fun invoke(message: String) {
messages.add(message)
}
}

@Test
fun `should display info messages if logging is info`(){
val emitter = AccumulatingEmitter()
val logger = DokkaConsoleLogger(LoggingLevel.INFO, emitter)

logger.debug("Debug!")
logger.info("Info!")

assertTrue(emitter.messages.size > 0)
assertTrue(emitter.messages.any { it == "Info!" })
assertFalse(emitter.messages.any { it == "Debug!" })
}

@Test
fun `should not display info messages if logging is warn`(){
val emitter = AccumulatingEmitter()
val logger = DokkaConsoleLogger(LoggingLevel.WARN, emitter)

logger.warn("Warning!")
logger.info("Info!")


assertTrue(emitter.messages.size > 0)
assertFalse(emitter.messages.any { it.contains("Info!") })
assertTrue(emitter.messages.any { it.contains("Warning!") })
}
}
Expand Up @@ -4,16 +4,16 @@ import matchers.content.assertNode
import matchers.content.hasExactText
import org.jetbrains.dokka.model.firstMemberOfType
import org.jetbrains.dokka.pages.*
import org.jetbrains.dokka.testApi.logger.FilteringLogger
import org.jetbrains.dokka.testApi.logger.TestLogger
import org.jetbrains.dokka.base.testApi.testRunner.BaseAbstractTest
import org.jetbrains.dokka.utilities.DokkaConsoleLogger
import org.jetbrains.dokka.utilities.LoggingLevel
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.MethodSource
import kotlin.reflect.KClass

class ObviousTypeSkippingTest : BaseAbstractTest(
logger = TestLogger(FilteringLogger(minLevel = FilteringLogger.Level.Warn, DokkaConsoleLogger))
logger = TestLogger(DokkaConsoleLogger(LoggingLevel.WARN))
) {

private fun source(signature: String) =
Expand Down
Expand Up @@ -75,7 +75,7 @@ class ContextModuleAndPackageDocumentationReaderTest1 : AbstractContextModuleAnd
private val context by lazy {
DokkaContext.create(
configuration = configurationBuilder.build(),
logger = TestLogger(DokkaConsoleLogger),
logger = TestLogger(DokkaConsoleLogger()),
pluginOverrides = emptyList()
)
}
Expand Down
Expand Up @@ -39,7 +39,7 @@ class ContextModuleAndPackageDocumentationReaderTest3 : AbstractContextModuleAnd
private val context by lazy {
DokkaContext.create(
configuration = configurationBuilder.build(),
logger = DokkaConsoleLogger,
logger = DokkaConsoleLogger(),
pluginOverrides = emptyList()
)
}
Expand Down
Expand Up @@ -52,14 +52,14 @@ class InvalidContentModuleAndPackageDocumentationReaderTest : AbstractContextMod
private val contextA by lazy {
DokkaContext.create(
configuration = configurationBuilderA.build(),
logger = DokkaConsoleLogger,
logger = DokkaConsoleLogger(),
pluginOverrides = emptyList()
)
}
private val contextB by lazy {
DokkaContext.create(
configuration = configurationBuilderB.build(),
logger = DokkaConsoleLogger,
logger = DokkaConsoleLogger(),
pluginOverrides = emptyList()
)
}
Expand Down

0 comments on commit c1f87fa

Please sign in to comment.