-
Notifications
You must be signed in to change notification settings - Fork 123
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add support for log4j2 as a backend.
Closes #24 Importing a log4j2 backend into Google. RELNOTES=Add support for log4j2 as a backend. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=255567989
- Loading branch information
1 parent
c5c74a5
commit 356778a
Showing
7 changed files
with
396 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
# Copyright (C) 2019 The Flogger Authors. | ||
# | ||
# Description: | ||
# Flogger log4j2 backend (google.github.io/flogger). | ||
|
||
package(default_visibility = ["//:internal"]) | ||
|
||
LOG4J2_BACKEND_SRCS = glob(["src/main/java/**/*.java"]) | ||
|
||
java_library( | ||
name = "log4j2_backend", | ||
srcs = LOG4J2_BACKEND_SRCS, | ||
javacopts = ["-source 1.6 -target 1.6"], | ||
tags = ["maven_coordinates=com.google.flogger:flogger-log4j2-backend:${project.version}"], | ||
deps = [ | ||
"//api", | ||
"//api:system_backend", | ||
"@google_bazel_common//third_party/java/log4j2", | ||
], | ||
) | ||
|
||
load("//tools:maven.bzl", "pom_file") | ||
|
||
pom_file( | ||
name = "pom", | ||
artifact_id = "flogger-log4j2-backend", | ||
artifact_name = "Flogger Log4j2 Backend", | ||
targets = [":log4j2_backend"], | ||
) | ||
|
||
load("@google_bazel_common//tools/javadoc:javadoc.bzl", "javadoc_library") | ||
|
||
javadoc_library( | ||
name = "javadoc", | ||
srcs = LOG4J2_BACKEND_SRCS, | ||
root_packages = ["com.google.common.flogger.backend.log4j2"], | ||
deps = [":log4j2_backend"], | ||
) |
61 changes: 61 additions & 0 deletions
61
log4j2/src/main/java/com/google/common/flogger/backend/log4j2/Log4j2BackendFactory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
/* | ||
* Copyright (C) 2019 The Flogger Authors. | ||
* | ||
* 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. | ||
*/ | ||
|
||
package com.google.common.flogger.backend.log4j2; | ||
|
||
import com.google.common.flogger.backend.LoggerBackend; | ||
import com.google.common.flogger.backend.system.BackendFactory; | ||
import org.apache.logging.log4j.LogManager; | ||
import org.apache.logging.log4j.core.Logger; | ||
|
||
/** | ||
* BackendFactory for log4j2. | ||
* | ||
* <p>To configure this backend for Flogger set the following system property (also see {@link | ||
* com.google.common.flogger.backend.system.DefaultPlatform}): | ||
* | ||
* <ul> | ||
* <li>{@code flogger.backend_factory= | ||
* com.google.common.flogger.backend.log4j2.Log4j2BackendFactory#getInstance} | ||
* </ul> | ||
*/ | ||
public final class Log4j2BackendFactory extends BackendFactory { | ||
private static final Log4j2BackendFactory INSTANCE = new Log4j2BackendFactory(); | ||
|
||
private Log4j2BackendFactory() {} | ||
|
||
/** This method is expected to be called via reflection (and might otherwise be unused). */ | ||
public static BackendFactory getInstance() { | ||
return INSTANCE; | ||
} | ||
|
||
@Override | ||
public LoggerBackend create(String loggingClassName) { | ||
// Compute the logger name exactly the same way as in SimpleBackendFactory. | ||
// The logger name must match the name of the logging class so that we can return it from | ||
// Log4j2LoggerBackend#getLoggerName(). | ||
// We cast org.apache.logging.log4j.core.Logger here so that | ||
// we can access the methods only avilable under org.apache.logging.log4j.core.Logger. | ||
// TODO(b/27920233): Strip inner/nested classes when deriving logger name. | ||
Logger logger = (Logger) LogManager.getLogger(loggingClassName.replace('$', '.')); | ||
return new Log4j2LoggerBackend(logger); | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return "Log4j2 backend"; | ||
} | ||
} |
91 changes: 91 additions & 0 deletions
91
log4j2/src/main/java/com/google/common/flogger/backend/log4j2/Log4j2LogDataFormatter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
/* | ||
* Copyright (C) 2019 The Flogger Authors. | ||
* | ||
* 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. | ||
*/ | ||
|
||
package com.google.common.flogger.backend.log4j2; | ||
|
||
import static java.util.logging.Level.WARNING; | ||
|
||
import com.google.common.flogger.backend.LogData; | ||
import com.google.common.flogger.backend.Metadata; | ||
import com.google.common.flogger.backend.SimpleMessageFormatter; | ||
import com.google.common.flogger.backend.SimpleMessageFormatter.SimpleLogHandler; | ||
import java.util.logging.Level; | ||
|
||
/** Helper to format LogData */ | ||
final class Log4j2LogDataFormatter { | ||
private Log4j2LogDataFormatter() {} | ||
|
||
/** | ||
* Formats the log message and any metadata for the given {@link LogData}, calling the supplied | ||
* receiver object with the results. | ||
*/ | ||
static void format(LogData logData, SimpleLogHandler receiver) { | ||
SimpleMessageFormatter.format(logData, receiver); | ||
} | ||
|
||
/** | ||
* Formats the log message in response to an exception during a previous logging attempt. A | ||
* synthetic error message is generated from the original log data and the given exception is set | ||
* as the cause. The level of this record is the maximum of WARNING or the original level. | ||
*/ | ||
static void formatBadLogData( | ||
RuntimeException error, LogData badLogData, SimpleLogHandler receiver) { | ||
StringBuilder errorMsg = | ||
new StringBuilder("LOGGING ERROR: ").append(error.getMessage()).append('\n'); | ||
int length = errorMsg.length(); | ||
try { | ||
appendLogData(badLogData, errorMsg); | ||
} catch (RuntimeException e) { | ||
// Reset partially written buffer when an error occurs. | ||
errorMsg.setLength(length); | ||
errorMsg.append("Cannot append LogData: ").append(e); | ||
} | ||
|
||
// Re-target this log message as a warning (or above) since it indicates a real bug. | ||
Level level = | ||
badLogData.getLevel().intValue() < WARNING.intValue() ? WARNING : badLogData.getLevel(); | ||
|
||
receiver.handleFormattedLogMessage(level, errorMsg.toString(), error); | ||
} | ||
|
||
/** Appends the given {@link LogData} to the given {@link StringBuilder}. */ | ||
static void appendLogData(LogData data, StringBuilder out) { | ||
out.append(" original message: "); | ||
if (data.getTemplateContext() == null) { | ||
out.append(data.getLiteralArgument()); | ||
} else { | ||
// We know that there's at least one argument to display here. | ||
out.append(data.getTemplateContext().getMessage()); | ||
out.append("\n original arguments:"); | ||
for (Object arg : data.getArguments()) { | ||
out.append("\n ").append(SimpleMessageFormatter.safeToString(arg)); | ||
} | ||
} | ||
Metadata metadata = data.getMetadata(); | ||
if (metadata.size() > 0) { | ||
out.append("\n metadata:"); | ||
for (int n = 0; n < metadata.size(); n++) { | ||
out.append("\n "); | ||
out.append(metadata.getKey(n).getLabel()).append(": ").append(metadata.getValue(n)); | ||
} | ||
} | ||
out.append("\n level: ").append(data.getLevel()); | ||
out.append("\n timestamp (nanos): ").append(data.getTimestampNanos()); | ||
out.append("\n class: ").append(data.getLogSite().getClassName()); | ||
out.append("\n method: ").append(data.getLogSite().getMethodName()); | ||
out.append("\n line number: ").append(data.getLogSite().getLineNumber()); | ||
} | ||
} |
74 changes: 74 additions & 0 deletions
74
log4j2/src/main/java/com/google/common/flogger/backend/log4j2/Log4j2LoggerBackend.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
/* | ||
* Copyright (C) 2019 The Flogger Authors. | ||
* | ||
* 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. | ||
*/ | ||
|
||
package com.google.common.flogger.backend.log4j2; | ||
|
||
import com.google.common.flogger.backend.LogData; | ||
import com.google.common.flogger.backend.LoggerBackend; | ||
import org.apache.logging.log4j.core.Logger; | ||
|
||
/** A logging backend that uses log4j2 to output log statements. */ | ||
final class Log4j2LoggerBackend extends LoggerBackend { | ||
/** Converts java.util.logging.Level to org.apache.log4j.Level. */ | ||
static org.apache.logging.log4j.Level toLog4jLevel(java.util.logging.Level level) { | ||
int logLevel = level.intValue(); | ||
if (logLevel >= java.util.logging.Level.SEVERE.intValue()) { | ||
return org.apache.logging.log4j.Level.ERROR; | ||
} else if (logLevel >= java.util.logging.Level.WARNING.intValue()) { | ||
return org.apache.logging.log4j.Level.WARN; | ||
} else if (logLevel >= java.util.logging.Level.INFO.intValue()) { | ||
return org.apache.logging.log4j.Level.INFO; | ||
} else if (logLevel >= java.util.logging.Level.FINE.intValue()) { | ||
return org.apache.logging.log4j.Level.DEBUG; | ||
} | ||
return org.apache.logging.log4j.Level.TRACE; | ||
} | ||
|
||
private final Logger logger; | ||
|
||
// VisibleForTesting | ||
Log4j2LoggerBackend(Logger logger) { | ||
this.logger = logger; | ||
} | ||
|
||
@Override | ||
public String getLoggerName() { | ||
// Logger#getName() returns exactly the name that we used to create the Logger in | ||
// Log4jBackendFactory. It matches the name of the logging class. | ||
return logger.getName(); | ||
} | ||
|
||
@Override | ||
public boolean isLoggable(java.util.logging.Level level) { | ||
return logger.isEnabled(toLog4jLevel(level)); | ||
} | ||
|
||
private void log(Log4j2SimpleLogEvent logEntry, boolean wasForced) { | ||
if (wasForced || logger.isEnabled(logEntry.getLevel())) { | ||
logger.get().log(logEntry.asLoggingEvent()); | ||
} | ||
} | ||
|
||
@Override | ||
public void log(LogData logData) { | ||
log(Log4j2SimpleLogEvent.create(logger, logData), logData.wasForced()); | ||
} | ||
|
||
@Override | ||
public void handleError(RuntimeException error, LogData badData) { | ||
log(Log4j2SimpleLogEvent.error(logger, error, badData), badData.wasForced()); | ||
} | ||
} |
Oops, something went wrong.