Skip to content

Commit

Permalink
Issue GoogleCloudPlatform#231 - Overhauling logging handlers for java…
Browse files Browse the repository at this point in the history
….util.logging

+ Slf4j is now present, capturing logging events from:
  * commons-logging
  * log4j
  * java.util.logging
  * slf4j-api
+ Slf4j is configured to use java.util.logging as its source
  for output, appending, handlers, and configuration
+ Introducing appengine-java-logging CoreLogging with ability
  to configure user/app logging then system logging in a
  consisten way.
  • Loading branch information
joakime committed Jun 23, 2016
1 parent 6fde3d1 commit 5398963
Show file tree
Hide file tree
Showing 18 changed files with 610 additions and 408 deletions.
34 changes: 34 additions & 0 deletions appengine-java-logging/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,46 @@
<packaging>jar</packaging>
<description>Support code for writing log files compatible with Google App Engine</description>

<properties>
<slf4j.version>1.7.16</slf4j.version>
</properties>

<dependencies>
<!-- Logging: API -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- Logging: Capturing Layers -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
<version>${slf4j.version}</version>
</dependency>
<!-- Logging: Output / Appender Layer -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>${slf4j.version}</version>
</dependency>

<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>

<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/*
* Copyright 2016 Google Inc. All Rights Reserved.
*
* 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.apphosting.logging;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ServiceLoader;
import java.util.logging.LogManager;

/**
* Logging Core behavior.
*/
public class CoreLogging {
public static final String JAVA_UTIL_LOGGING_CONFIG_PROPERTY = "java.util.logging.config.file";

/**
* Initialize the java.util.logging Environment.
* <p>
* Order is:
* <ol>
* <li>Apply App (User) Configuration</li>
* <li>Apply System Mandated Configuration</li>
* </ol>
* </p>
*
* @param appConfigFile the filename for the (optional) app specific java.util.logging
* properties file configuration.
*/
public static void init(File appConfigFile) throws IOException {
// Use App (User) Configuration specified as a file parameter
if (appConfigFile != null && appConfigFile.exists()) {
appConfig(appConfigFile);
} else {
// Use App (User) Configuration specified as a System property
String julConfigFile = System.getProperty(JAVA_UTIL_LOGGING_CONFIG_PROPERTY);
if (julConfigFile != null) {
File configFile = new File(julConfigFile);
if (configFile.exists()) {
appConfig(configFile);
}
}
}

// Manually Adjust Configuration to support System Logging Requirements
systemConfig();
}

/**
* Convenience method for {@link #init(File)}
*
* @param appConfigFilename the filename of the config file (or null)
* @throws IOException if unable to configure the logging
*/
public static void init(String appConfigFilename) throws IOException {
File appConfigFile = null;
if (appConfigFilename == null) {
appConfigFile = new File(appConfigFilename);
}
init(appConfigFile);
}

private static void appConfig(File configFile) {
try (FileInputStream is = new FileInputStream(configFile)) {
LogManager logManager = LogManager.getLogManager();
logManager.reset();
logManager.readConfiguration(is);
} catch (SecurityException | IOException e) {
System.err.println("Warning: caught exception when reading logging properties: " + configFile
.getAbsolutePath());
e.printStackTrace(System.err);
}
}

/**
* Manually Configure the System Level requirements for java.util.logging
*/
private static void systemConfig() throws IOException {
// Since System Loggers can arrive from deep within the various compat layers, it
// makes sense to use the ServiceLoader to obtain references to specific System loggers
// that need to be initialized during this step in the logging initialization.

ServiceLoader<SystemLogger> serviceLoader = ServiceLoader.load(SystemLogger.class);
for (SystemLogger systemLogger : serviceLoader) {
systemLogger.configure();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* Copyright 2016 Google Inc. All Rights Reserved.
*
* 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.apphosting.logging;

import java.io.IOException;

/**
* Interface for any component wanting to participate in the System Logging level
* configuration.
*/
public interface SystemLogger {
/**
* Configure your System Level Logger on this event.
*
* @throws IOException if unable to configure the System Level Logger
*/
void configure() throws IOException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/*
* Copyright 2016 Google Inc. All Rights Reserved.
*
* 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.apphosting.logging;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.concurrent.ThreadLocalRandom;

public class CommonsLoggingExample implements Runnable {
private static final Log LOG = LogFactory.getLog(CommonsLoggingExample.class);

@Override
public void run() {
ThreadLocalRandom rand = ThreadLocalRandom.current();
LOG.trace(String.format("A CommonsLogging Trace Event: %d", rand.nextInt()));
LOG.debug(String.format("A CommonsLogging Debug Event: %d", rand.nextInt()));
LOG.info(String.format("A CommonsLogging Info Event: %d", rand.nextInt()));
LOG.warn(String.format("A CommonsLogging Warn Event: %d", rand.nextInt()));
LOG.error(String.format("A CommonsLogging Error Event: %d", rand.nextInt()),
new RuntimeException("Generic Error"));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright 2016 Google Inc. All Rights Reserved.
*
* 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.apphosting.logging;

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Handler;
import java.util.logging.LogRecord;

public class JsonCaptureHandler extends Handler {

private JsonFormatter formatter;
private List<String> events;

public JsonCaptureHandler() {
super();
formatter = new JsonFormatter();
events = new ArrayList<>();
}

@Override
public void publish(LogRecord record) {
events.add(formatter.format(record));
}

@Override
public void flush() {
}

@Override
public void close() throws SecurityException {
}

public List<String> getEvents() {
return events;
}
}
Loading

0 comments on commit 5398963

Please sign in to comment.