Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
.gradle
build
.idea
.idea
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ Dropping a requirement of a major version of a dependency is a new contract.
## [Unreleased]
[Unreleased]: https://github.com/atlassian/infrastructure/compare/release-4.19.3...master

### Added
- Enable Jsonifying log4j2 configurations in `SplunkForwarder`. Resolve [JPERF-838].

## [4.19.3] - 2022-06-23
[4.19.3]: https://github.com/atlassian/infrastructure/compare/release-4.19.2...release-4.19.3

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,28 @@ class Sed {
val escapedOutput = output.replace("/", "\\/")
connection.execute("sed -i -r 's/$escapedExpression/$escapedOutput/g' $file")
}
}

internal fun safeReplace(
connection: SshConnection,
expression: String,
output: String,
file: String
): SshConnection.SshResult {
val escapedExpression = expression.replace("/", "\\/")
val escapedOutput = output.replace("/", "\\/")
return connection.safeExecute("sed -i -r 's/$escapedExpression/$escapedOutput/g' $file")
}

internal fun safeReplaceXmlTag(
connection: SshConnection,
sourceTagName: String,
replacementString: String,
file: String
): SshConnection.SshResult {
val escapedSource= sourceTagName.replace("/", "\\/")
val escapedReplacement= replacementString.replace("/", "\\/")
return connection.safeExecute("sed -i '/\\/$escapedSource/a\\\n" +
" $escapedReplacement\n" +
"/$escapedSource/, /\\/$escapedSource/d' $file")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import com.atlassian.performance.tools.infrastructure.api.jvm.jmx.DisabledRemote
import com.atlassian.performance.tools.infrastructure.api.jvm.jmx.RemoteJmx
import com.atlassian.performance.tools.infrastructure.api.profiler.Profiler
import com.atlassian.performance.tools.infrastructure.api.splunk.DisabledSplunkForwarder
import com.atlassian.performance.tools.infrastructure.api.splunk.Log4j2SplunkForwarder
import com.atlassian.performance.tools.infrastructure.api.splunk.SplunkForwarder
import com.atlassian.performance.tools.infrastructure.profiler.DisabledProfiler
import java.net.URI
Expand Down Expand Up @@ -143,7 +144,7 @@ class JiraNodeConfig private constructor(
debug = debug,
remoteJmx = remoteJmx,
jvmArgs = jvmArgs,
splunkForwarder = splunkForwarder,
splunkForwarder = Log4j2SplunkForwarder("log4j2.xml", splunkForwarder),
collectdConfigs = collectdConfigs,
launchTimeouts = launchTimeouts,
jdk = if (versionedJdk != null) versionedJdk as JavaDevelopmentKit else jdk,
Expand All @@ -157,4 +158,4 @@ class JiraNodeConfig private constructor(
JiraNodeConfig::class.java.getResource("/collectd/conf/jira-default.conf").toURI()
)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.atlassian.performance.tools.infrastructure.api.splunk

import com.atlassian.performance.tools.infrastructure.DockerImage
import com.atlassian.performance.tools.infrastructure.api.Sed
import com.atlassian.performance.tools.infrastructure.splunk.Log4jJsonifier
import com.atlassian.performance.tools.ssh.api.SshConnection
import java.time.Duration

Expand Down Expand Up @@ -34,12 +34,7 @@ class AtlassianSplunkForwarder(
}

override fun jsonifyLog4j(sshConnection: SshConnection, log4jPropertiesPath: String) {
Sed().replace(
connection = sshConnection,
expression = "NewLineIndentingFilteringPatternLayout",
output = "layout.JsonLayout",
file = log4jPropertiesPath
)
Log4jJsonifier().jsonifyLog4j1(sshConnection, log4jPropertiesPath)
}

override fun getRequiredPorts(): List<Int> {
Expand Down Expand Up @@ -92,4 +87,4 @@ internal class LogStashConfigBuilder(private val additionalEventFields: Map<Stri
fun build(): String {
return input() + "\n" + filter(additionalEventFields) + "\n" + output(kinesisRoleArn)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ class DisabledSplunkForwarder : SplunkForwarder {
override fun getRequiredPorts(): List<Int> {
return emptyList()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.atlassian.performance.tools.infrastructure.api.splunk

import com.atlassian.performance.tools.infrastructure.splunk.Log4jJsonifier
import com.atlassian.performance.tools.ssh.api.SshConnection
import java.nio.file.Paths

class Log4j2SplunkForwarder(log4j2ConfigFileName: String, splunkForwarder: SplunkForwarder) :
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is new API and it's a good thing. It's a way to offer the fix to anyone, who's not going through the JiraNodeConfig.Builder. @atlassian/jpt, this will be a minor release.

SplunkForwarder by splunkForwarder {

private val log4j2ConfigFileName = log4j2ConfigFileName

override fun jsonifyLog4j(sshConnection: SshConnection, log4jPropertiesPath: String) {
val log4j2ConfigPath = Paths.get(log4jPropertiesPath).resolveSibling(log4j2ConfigFileName).toString()
Log4jJsonifier().jsonifyLog4j1AndLog4j2(sshConnection, log4jPropertiesPath, log4j2ConfigPath)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ interface SplunkForwarder {
fun run(sshConnection: SshConnection, name: String, logsPath: String)
fun jsonifyLog4j(sshConnection: SshConnection, log4jPropertiesPath: String)
fun getRequiredPorts(): List<Int>
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.atlassian.performance.tools.infrastructure.api.splunk

import com.atlassian.performance.tools.infrastructure.DockerImage
import com.atlassian.performance.tools.infrastructure.api.Sed
import com.atlassian.performance.tools.infrastructure.splunk.Log4jJsonifier
import com.atlassian.performance.tools.ssh.api.SshConnection


Expand Down Expand Up @@ -33,12 +33,7 @@ class UniversalSplunkForwarder(
}

override fun jsonifyLog4j(sshConnection: SshConnection, log4jPropertiesPath: String) {
Sed().replace(
connection = sshConnection,
expression = "NewLineIndentingFilteringPatternLayout",
output = "layout.JsonLayout",
file = log4jPropertiesPath
)
Log4jJsonifier().jsonifyLog4j1(sshConnection, log4jPropertiesPath)
}

override fun getRequiredPorts(): List<Int> {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.atlassian.performance.tools.infrastructure.splunk

import com.atlassian.performance.tools.infrastructure.api.Sed
import com.atlassian.performance.tools.ssh.api.SshConnection
import org.apache.logging.log4j.LogManager
import org.apache.logging.log4j.Logger


class Log4jJsonifier {

private val logger: Logger = LogManager.getLogger(Log4jJsonifier::class.java)

fun jsonifyLog4j1(sshConnection: SshConnection, log4jPropertiesPath: String) {
Sed().replace(
connection = sshConnection,
expression = "NewLineIndentingFilteringPatternLayout",
output = "layout.JsonLayout",
file = log4jPropertiesPath
)
}

fun jsonifyLog4j1AndLog4j2(sshConnection: SshConnection, log4jPropertiesPath: String, log4j2ConfigPath: String) {
val log4j1Result = Sed().safeReplace(
connection = sshConnection,
expression = "NewLineIndentingFilteringPatternLayout",
output = "layout.JsonLayout",
file = log4jPropertiesPath
)
if (!log4j1Result.isSuccessful()) {
logger.debug("Attempt to jsonify $log4jPropertiesPath was unsuccessful.")
}
val log4j2Result = Sed().safeReplaceXmlTag(
connection = sshConnection,
sourceTagName = "PatternLayout",
replacementString = "<AtlassianJsonLayout filteringApplied=\"false\"/>",
file = log4j2ConfigPath
)
if (!log4j1Result.isSuccessful()) {
logger.debug("Attempt to jsonify $log4j2ConfigPath was unsuccessful.")
}
if (!log4j1Result.isSuccessful() && !log4j2Result.isSuccessful()) {
throw Exception("Failed to jsonify any log4j configuration.")
}
if (log4j1Result.isSuccessful() && log4j2Result.isSuccessful()) {
logger.debug("Migrated both log4j1 and log4j2 config files, ensure that's correct.")
}
}
}