From 25d7592300e3e7c8c0614084cf303cf2fefe719d Mon Sep 17 00:00:00 2001 From: Dmitriy Voronin Date: Mon, 12 Apr 2021 17:33:18 +0300 Subject: [PATCH] avito.logging.verbose property (#923) * new avito.logging.verbose property to override local console output log levels for out plugins * use println (quiet level in gradle) * add stacktrace print control, extract VerboseDestination --- Makefile | 7 ++ docs/content/contributing/Logging.md | 37 +++++++++- .../logger/destination/VerboseDestination.kt | 42 +++++++++++ .../com/avito/logger/GradleLoggerFactory.kt | 73 +++++++++++++++---- 4 files changed, 143 insertions(+), 16 deletions(-) create mode 100644 subprojects/common/slf4j-logger/src/main/kotlin/com/avito/logger/destination/VerboseDestination.kt diff --git a/Makefile b/Makefile index b12de04854..e422234bf2 100644 --- a/Makefile +++ b/Makefile @@ -26,6 +26,9 @@ instrumentation=Ui stacktrace?= project=-p subprojects +# see Logging.md#Verbose-mode +verbose?= + docker_command?= ifeq ($(docker),true) @@ -62,6 +65,10 @@ ifdef infra params +=-PinfraVersion=$(infra) endif +ifdef verbose +params +=-Pavito.logging.verbosity=$(verbose) +endif + params +=-PtestBuildType=$(test_build_type) params +=-Pci=$(ci) params +=$(log_level) diff --git a/docs/content/contributing/Logging.md b/docs/content/contributing/Logging.md index 03db3e52e6..c804453f5e 100644 --- a/docs/content/contributing/Logging.md +++ b/docs/content/contributing/Logging.md @@ -7,8 +7,8 @@ To obtain a logger for Gradle use `GradleLoggerFactory` methods: ```kotlin -abstract class MyTask: DefaultTask() { - +abstract class MyTask : DefaultTask() { + @TaskAction fun doWork() { val loggerFactory: LoggerFactory = GradleLoggerFactory.fromTask(this) @@ -16,7 +16,7 @@ abstract class MyTask: DefaultTask() { } ``` -## Logging in Android +## Logging in Android To obtain logger for android create `AndroidLoggerFactory` @@ -46,3 +46,34 @@ val logger = loggerFactory.create("MyCustomTag") `StubLoggerFactory` and `StubLogger` can be used in tests `StubLogger` will write to stdout only during test runs from IDE + +## Verbose mode + +Use gradle property `avito.logging.verbosity` to override gradle logging level and send avito logs to stdout (e.g. with +gradle's `quiet` level.) + +Value defines which levels to override. + +For example: `-Pavito.logging.verbosity=INFO` makes `INFO` and higher(`WARNING`) levels act like level quiet + +`CRITICAL`, which is mapped to gradle's `error` level is visible already on quiet level + +Possible values are in `DEBUG`, `INFO`, `WARNING`, `CRITICAL` (see `com.avito.logger.LogLevel`) + +Default is not defined + +### Stacktrace + +Add gradle's `--stacktrace` to also print stacktraces in verbose mode if available + +### Why is it needed? + +Gradle use lifecycle level by default, but to see info or debug level you have to set it for whole gradle run +via `--info` or `--debug`, which made console output unreadable and build slow. + +There is an issue for +that: [gradle/#1010 Ability to set log level for specific task](https://github.com/gradle/gradle/issues/1010) + +With verbose flag you are able to tune log level for avito plugins separately. + +It only affects console output, and not affecting custom loggers like elastic. diff --git a/subprojects/common/slf4j-logger/src/main/kotlin/com/avito/logger/destination/VerboseDestination.kt b/subprojects/common/slf4j-logger/src/main/kotlin/com/avito/logger/destination/VerboseDestination.kt new file mode 100644 index 0000000000..3453b4ae0d --- /dev/null +++ b/subprojects/common/slf4j-logger/src/main/kotlin/com/avito/logger/destination/VerboseDestination.kt @@ -0,0 +1,42 @@ +package com.avito.logger.destination + +import com.avito.logger.LogLevel +import com.avito.logger.LoggingDestination + +data class VerboseMode( + val verbosity: LogLevel, + val printStackTrace: Boolean +) + +/** + * See Logging.md#Verbose-mode + */ +class VerboseDestination(private val verboseMode: VerboseMode) : LoggingDestination { + + private val verbosity = verboseMode.verbosity + + override fun write(level: LogLevel, message: String, throwable: Throwable?) { + when (level) { + LogLevel.DEBUG -> if (verbosity == LogLevel.DEBUG) { + print(message, throwable) + } + LogLevel.INFO -> if (verbosity == LogLevel.DEBUG || verbosity == LogLevel.INFO) { + print(message, throwable) + } + LogLevel.WARNING -> if (verbosity == LogLevel.DEBUG + || verbosity == LogLevel.INFO + || verbosity == LogLevel.WARNING + ) { + print(message, throwable) + } + LogLevel.CRITICAL -> print(message, throwable) + } + } + + private fun print(message: String, throwable: Throwable?) { + println(message) + if (verboseMode.printStackTrace) { + throwable?.printStackTrace() + } + } +} diff --git a/subprojects/gradle/gradle-logger/src/main/kotlin/com/avito/logger/GradleLoggerFactory.kt b/subprojects/gradle/gradle-logger/src/main/kotlin/com/avito/logger/GradleLoggerFactory.kt index 6290475d9d..385d5a4e2b 100644 --- a/subprojects/gradle/gradle-logger/src/main/kotlin/com/avito/logger/GradleLoggerFactory.kt +++ b/subprojects/gradle/gradle-logger/src/main/kotlin/com/avito/logger/GradleLoggerFactory.kt @@ -4,6 +4,8 @@ import com.avito.android.elastic.ElasticConfig import com.avito.android.sentry.SentryConfig import com.avito.android.sentry.sentryConfig import com.avito.logger.destination.Slf4jDestination +import com.avito.logger.destination.VerboseDestination +import com.avito.logger.destination.VerboseMode import com.avito.logger.formatter.AppendMetadataFormatter import com.avito.logger.handler.CombinedHandler import com.avito.logger.handler.DefaultLoggingHandler @@ -12,7 +14,9 @@ import com.avito.utils.gradle.buildEnvironment import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.Task +import org.gradle.api.logging.configuration.ShowStacktrace import java.io.Serializable +import java.util.Locale class GradleLoggerFactory( private val isCiRun: Boolean, @@ -20,7 +24,8 @@ class GradleLoggerFactory( private val elasticConfig: ElasticConfig, private val projectPath: String, private val pluginName: String? = null, - private val taskName: String? = null + private val taskName: String? = null, + private val verboseMode: VerboseMode?, ) : LoggerFactory, Serializable { override fun create(tag: String): Logger = provideLogger( @@ -32,31 +37,40 @@ class GradleLoggerFactory( pluginName = pluginName, projectPath = projectPath, taskName = taskName - ) + ), + verboseMode = verboseMode ) private fun provideLogger( isCiRun: Boolean, sentryConfig: SentryConfig, elasticConfig: ElasticConfig, - metadata: LoggerMetadata + metadata: LoggerMetadata, + verboseMode: VerboseMode? ): Logger = if (isCiRun) { - createCiLogger(sentryConfig, elasticConfig, metadata) + createCiLogger(sentryConfig, elasticConfig, metadata, verboseMode) } else { - createLocalBuildLogger(metadata) + createLocalBuildLogger(metadata, verboseMode) } private fun createCiLogger( sentryConfig: SentryConfig, elasticConfig: ElasticConfig, - metadata: LoggerMetadata + metadata: LoggerMetadata, + verboseMode: VerboseMode? ): Logger { val defaultHandler = when (elasticConfig) { - is ElasticConfig.Disabled -> - DefaultLoggingHandler( - destination = Slf4jDestination(metadata.tag) - ) + is ElasticConfig.Disabled -> { + + val destination: LoggingDestination = if (verboseMode != null) { + VerboseDestination(verboseMode) + } else { + Slf4jDestination(metadata.tag) + } + + DefaultLoggingHandler(destination = destination) + } is ElasticConfig.Enabled -> DefaultLoggingHandler( destination = ElasticDestinationFactory.create(elasticConfig, metadata) @@ -82,11 +96,20 @@ class GradleLoggerFactory( ) } - private fun createLocalBuildLogger(metadata: LoggerMetadata): Logger { + private fun createLocalBuildLogger( + metadata: LoggerMetadata, + verboseMode: VerboseMode? + ): Logger { + + val destination: LoggingDestination = if (verboseMode != null) { + VerboseDestination(verboseMode) + } else { + Slf4jDestination(metadata.tag) + } val gradleLoggerHandler = DefaultLoggingHandler( formatter = AppendMetadataFormatter(metadata), - destination = Slf4jDestination(metadata.tag) + destination = destination ) return DefaultLogger( @@ -127,9 +150,33 @@ class GradleLoggerFactory( elasticConfig = ElasticConfigFactory.config(project), projectPath = project.path, pluginName = pluginName, - taskName = taskName + taskName = taskName, + verboseMode = getVerbosity(project)?.let { VerboseMode(it, doPrintStackTrace(project)) } ) + @Suppress("UnstableApiUsage") + private fun getVerbosity(project: Project): LogLevel? { + return project.providers + .gradleProperty("avito.logging.verbosity") + .forUseAtConfigurationTime() + .map { value -> + try { + LogLevel.valueOf(value.toUpperCase(Locale.getDefault())) + } catch (e: Throwable) { + throw IllegalArgumentException( + "`avito.logging.verbosity` should be one of: " + + "${LogLevel.values().map { it.name }} but was $value" + ) + } + } + .orNull + } + + private fun doPrintStackTrace(project: Project): Boolean { + val showStacktrace = project.gradle.startParameter.showStacktrace + return showStacktrace == ShowStacktrace.ALWAYS || showStacktrace == ShowStacktrace.ALWAYS_FULL + } + private fun Project.isCiRun(): Boolean = project.buildEnvironment is BuildEnvironment.CI && !project.buildEnvironment.inGradleTestKit }