Skip to content

Commit

Permalink
Add support for log4j2 as a backend.
Browse files Browse the repository at this point in the history
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
paladox authored and ronshapiro committed Jul 11, 2019
1 parent c5c74a5 commit 356778a
Show file tree
Hide file tree
Showing 7 changed files with 396 additions and 0 deletions.
1 change: 1 addition & 0 deletions BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ package_group(
"//api/...",
"//google/...",
"//log4j/...",
"//log4j2/...",
"//slf4j/...",
"//tools/...",
],
Expand Down
38 changes: 38 additions & 0 deletions log4j2/BUILD
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"],
)
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";
}
}
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());
}
}
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());
}
}
Loading

0 comments on commit 356778a

Please sign in to comment.