diff options
author | Piotr Jaszczyk <piotr.jaszczyk@nokia.com> | 2018-11-28 15:46:50 +0100 |
---|---|---|
committer | Piotr Jaszczyk <piotr.jaszczyk@nokia.com> | 2018-11-29 14:41:42 +0100 |
commit | dde383a2aa75f94c26d7949665b79cc95486a223 (patch) | |
tree | 75f3e8f564067afd0e67dbe6254183e45ca26944 /build/hv-collector-analysis/src/main/kotlin | |
parent | 77f896523f2065b1da1be21545155a29edea5122 (diff) |
Custom detekt rule for logger usage check
Check if logger invocations don't use unoptimal invocations, eg.
concatenation `debug("a=" + a)` instead of lambda use `debug {"a=" + a}`
Unfortunately to avoid defining dependencies in many places and having
circural dependencies it was necessarry to reorganize the maven module
structure. The goal was to have `sources` module with production code and
`build` module with build-time tooling (detekt rules among them).
Issue-ID: DCAEGEN2-1002
Change-Id: I36e677b98972aaae6905d722597cbce5e863d201
Signed-off-by: Piotr Jaszczyk <piotr.jaszczyk@nokia.com>
Diffstat (limited to 'build/hv-collector-analysis/src/main/kotlin')
2 files changed, 128 insertions, 0 deletions
diff --git a/build/hv-collector-analysis/src/main/kotlin/org/onap/dcae/collectors/veshv/analysis/SuboptimalLoggerUsage.kt b/build/hv-collector-analysis/src/main/kotlin/org/onap/dcae/collectors/veshv/analysis/SuboptimalLoggerUsage.kt new file mode 100644 index 00000000..a070584c --- /dev/null +++ b/build/hv-collector-analysis/src/main/kotlin/org/onap/dcae/collectors/veshv/analysis/SuboptimalLoggerUsage.kt @@ -0,0 +1,92 @@ +/* + * ============LICENSE_START======================================================= + * dcaegen2-collectors-veshv + * ================================================================================ + * Copyright (C) 2018 NOKIA + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.dcae.collectors.veshv.analysis + +import io.gitlab.arturbosch.detekt.api.CodeSmell +import io.gitlab.arturbosch.detekt.api.Config +import io.gitlab.arturbosch.detekt.api.Debt +import io.gitlab.arturbosch.detekt.api.Entity +import io.gitlab.arturbosch.detekt.api.Issue +import io.gitlab.arturbosch.detekt.api.Rule +import io.gitlab.arturbosch.detekt.api.Severity +import org.jetbrains.kotlin.com.intellij.psi.PsiElement +import org.jetbrains.kotlin.psi.KtCallExpression +import org.jetbrains.kotlin.psi.KtOperationExpression +import org.jetbrains.kotlin.psi.KtStringTemplateExpression +import org.jetbrains.kotlin.psi.KtValueArgumentList +import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType + +/** + * @author Piotr Jaszczyk <piotr.jaszczyk@nokia.com> + * @since November 2018 + */ +class SuboptimalLoggerUsage(config: Config) : Rule(config) { + + override val issue = Issue(javaClass.simpleName, + Severity.Performance, + """ + Reports usage of unoptimized logger calls. + In Kotlin every method call (including logger calls) is eagerly evaluated by default. That means that + each argument will be evaluated even if loglevel is higher than in current call. The most common way of + mitigating this issue is to use lazy loading by means of lambda expressions, so instead of + log.debug("a=${'$'}a") we can write log.debug{ "a=${'$'}a" }. Logging string literals is fine - no + additional computation will be performed.""".trimIndent(), + Debt(mins = 10)) + + private val loggerNames = config.valueOrDefault("loggerNames", DEFAULT_LOGGER_NAMES).split(",") + + private val loggingMethods = config.valueOrDefault("loggingMethodNames", DEFAULT_LOGGING_METHOD_NAMES).split(",") + + override fun visitCallExpression(expression: KtCallExpression) { + val targetObject = expression.parent.firstChild + val methodName = expression.firstChild + + logExpressionArguments(targetObject, methodName) + ?.let(this::checkGettingWarningMessage) + ?.let { reportCodeSmell(expression, it) } + } + + private fun logExpressionArguments(targetObject: PsiElement, methodName: PsiElement) = + if (isLogExpression(targetObject, methodName)) + methodName.nextSibling as? KtValueArgumentList + else null + + private fun isLogExpression(targetObject: PsiElement, methodName: PsiElement) = + loggerNames.any(targetObject::textMatches) && loggingMethods.any(methodName::textMatches) + + private fun checkGettingWarningMessage(args: KtValueArgumentList) = when { + args.anyDescendantOfType<KtOperationExpression> { true } -> + "should not use any operators in logging expression" + args.anyDescendantOfType<KtCallExpression> { true } -> + "should not call anything in logging expression" + args.anyDescendantOfType<KtStringTemplateExpression> { it.hasInterpolation() } -> + "should not use string interpolation in logging expression" + else -> null + } + + private fun reportCodeSmell(expression: KtCallExpression, message: String) { + report(CodeSmell(issue, Entity.from(expression), message)) + } + + companion object { + const val DEFAULT_LOGGER_NAMES = "logger,LOGGER,log,LOG" + const val DEFAULT_LOGGING_METHOD_NAMES = "trace,debug,info,warn,error,severe" + } +} diff --git a/build/hv-collector-analysis/src/main/kotlin/org/onap/dcae/collectors/veshv/analysis/VesHvRuleSetProvider.kt b/build/hv-collector-analysis/src/main/kotlin/org/onap/dcae/collectors/veshv/analysis/VesHvRuleSetProvider.kt new file mode 100644 index 00000000..eec933dc --- /dev/null +++ b/build/hv-collector-analysis/src/main/kotlin/org/onap/dcae/collectors/veshv/analysis/VesHvRuleSetProvider.kt @@ -0,0 +1,36 @@ +/* + * ============LICENSE_START======================================================= + * dcaegen2-collectors-veshv + * ================================================================================ + * Copyright (C) 2018 NOKIA + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.dcae.collectors.veshv.analysis + +import io.gitlab.arturbosch.detekt.api.Config +import io.gitlab.arturbosch.detekt.api.RuleSet +import io.gitlab.arturbosch.detekt.api.RuleSetProvider + +/** + * @author Piotr Jaszczyk <piotr.jaszczyk@nokia.com> + * @since November 2018 + */ +class VesHvRuleSetProvider : RuleSetProvider { + override val ruleSetId: String + get() = "HvVesCustomRules" + + override fun instance(config: Config) = RuleSet(ruleSetId, listOf(SuboptimalLoggerUsage(config))) + +} |