6 changed files with 499 additions and 1 deletions
@ -0,0 +1,52 @@
@@ -0,0 +1,52 @@
|
||||
# MongoDB Log4J Appender |
||||
|
||||
This module sets up a Log4J appender that puts logging events in MongoDB. It is fully configurable |
||||
and connects directly to the MongoDB server using the driver. It has no dependency on any Spring package. |
||||
|
||||
To use it, configure a host, port, (optionally) applicationId, and database property in your Log4J configuration: |
||||
|
||||
log4j.appender.stdout=org.springframework.data.document.mongodb.log4j.MongoLog4jAppender |
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout |
||||
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n |
||||
log4j.appender.stdout.host = localhost |
||||
log4j.appender.stdout.port = 27017 |
||||
log4j.appender.stdout.database = logs |
||||
log4j.appender.stdout.applicationId = my.application |
||||
log4j.appender.stdout.warnOrHigherWriteConcern = FSYNC_SAFE |
||||
|
||||
It will even support properties in your MDC (so long as they're Strings or support .toString()). |
||||
|
||||
The collection name is configurable as well. If you don't specify anything, it will use the Category name. |
||||
If you want to specify a collection name, you can give it a String.format() string which will be passed the |
||||
following parameters: |
||||
|
||||
1. Calendar.YEAR |
||||
2. Calendar.MONTH |
||||
3. Calendar.DAY_OF_MONTH |
||||
4. Calendar.HOUR_OF_DAY |
||||
5. event.getLevel().toString() |
||||
6. event.getLogger().getName() |
||||
|
||||
An example log entry might look like: |
||||
|
||||
{ |
||||
"_id" : ObjectId("4d89341a8ef397e06940d5cd"), |
||||
"applicationId" : "my.application", |
||||
"name" : "org.springframework.data.document.mongodb.log4j.AppenderTest", |
||||
"level" : "DEBUG", |
||||
"timestamp" : "1300837402444", |
||||
"properties" : { |
||||
"property" : "one" |
||||
}, |
||||
"message" : "DEBUG message" |
||||
} |
||||
|
||||
To set WriteConcern levels for WARN or higher messages, set warnOrHigherWriteConcern to one of the following: |
||||
|
||||
* FSYNC_SAFE |
||||
* NONE |
||||
* NORMAL |
||||
* REPLICAS_SAFE |
||||
* SAFE |
||||
|
||||
(http://api.mongodb.org/java/2.5-pre-/com/mongodb/WriteConcern.html#field_detail)[http://api.mongodb.org/java/2.5-pre-/com/mongodb/WriteConcern.html#field_detail] |
||||
@ -0,0 +1,163 @@
@@ -0,0 +1,163 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
<parent> |
||||
<groupId>org.springframework.data</groupId> |
||||
<artifactId>spring-data-document-parent</artifactId> |
||||
<version>1.0.0.BUILD-SNAPSHOT</version> |
||||
<relativePath>../spring-data-document-parent/pom.xml</relativePath> |
||||
</parent> |
||||
<artifactId>spring-data-log4j-appender</artifactId> |
||||
<packaging>jar</packaging> |
||||
<name>Spring Data MongoDB Log4J Appender</name> |
||||
|
||||
<properties> |
||||
<mongo.version>2.3</mongo.version> |
||||
</properties> |
||||
|
||||
<dependencies> |
||||
|
||||
<!-- Spring --> |
||||
<dependency> |
||||
<groupId>org.springframework</groupId> |
||||
<artifactId>spring-beans</artifactId> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.springframework</groupId> |
||||
<artifactId>spring-tx</artifactId> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.springframework</groupId> |
||||
<artifactId>spring-expression</artifactId> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.springframework</groupId> |
||||
<artifactId>spring-test</artifactId> |
||||
<scope>test</scope> |
||||
</dependency> |
||||
|
||||
<!-- Spring Data --> |
||||
<dependency> |
||||
<groupId>org.springframework.data</groupId> |
||||
<artifactId>spring-data-document-core</artifactId> |
||||
<version>${project.version}</version> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.springframework.data</groupId> |
||||
<artifactId>spring-data-commons-core</artifactId> |
||||
<version>${data.commons.version}</version> |
||||
</dependency> |
||||
|
||||
<!-- MongoDB --> |
||||
<dependency> |
||||
<groupId>org.mongodb</groupId> |
||||
<artifactId>mongo-java-driver</artifactId> |
||||
<version>${mongo.version}</version> |
||||
</dependency> |
||||
|
||||
<!-- Logging --> |
||||
<dependency> |
||||
<groupId>org.slf4j</groupId> |
||||
<artifactId>slf4j-api</artifactId> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.slf4j</groupId> |
||||
<artifactId>jcl-over-slf4j</artifactId> |
||||
<scope>compile</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>org.slf4j</groupId> |
||||
<artifactId>slf4j-log4j12</artifactId> |
||||
<scope>runtime</scope> |
||||
</dependency> |
||||
<dependency> |
||||
<groupId>log4j</groupId> |
||||
<artifactId>log4j</artifactId> |
||||
<exclusions> |
||||
<exclusion> |
||||
<groupId>javax.mail</groupId> |
||||
<artifactId>mail</artifactId> |
||||
</exclusion> |
||||
<exclusion> |
||||
<groupId>javax.jms</groupId> |
||||
<artifactId>jms</artifactId> |
||||
</exclusion> |
||||
<exclusion> |
||||
<groupId>com.sun.jdmk</groupId> |
||||
<artifactId>jmxtools</artifactId> |
||||
</exclusion> |
||||
<exclusion> |
||||
<groupId>com.sun.jmx</groupId> |
||||
<artifactId>jmxri</artifactId> |
||||
</exclusion> |
||||
</exclusions> |
||||
<scope>compile</scope> |
||||
</dependency> |
||||
|
||||
<!-- Test dependencies --> |
||||
<dependency> |
||||
<groupId>org.mockito</groupId> |
||||
<artifactId>mockito-all</artifactId> |
||||
<scope>test</scope> |
||||
</dependency> |
||||
|
||||
<dependency> |
||||
<groupId>org.hamcrest</groupId> |
||||
<artifactId>hamcrest-all</artifactId> |
||||
<version>1.1</version> |
||||
<scope>test</scope> |
||||
</dependency> |
||||
|
||||
<dependency> |
||||
<groupId>junit</groupId> |
||||
<artifactId>junit</artifactId> |
||||
<scope>test</scope> |
||||
</dependency> |
||||
|
||||
<dependency> |
||||
<groupId>joda-time</groupId> |
||||
<artifactId>joda-time</artifactId> |
||||
<version>1.6</version> |
||||
<scope>test</scope> |
||||
</dependency> |
||||
|
||||
</dependencies> |
||||
<build> |
||||
<plugins> |
||||
<plugin> |
||||
<groupId>com.springsource.bundlor</groupId> |
||||
<artifactId>com.springsource.bundlor.maven</artifactId> |
||||
</plugin> |
||||
|
||||
<plugin> |
||||
<groupId>com.mysema.maven</groupId> |
||||
<artifactId>maven-apt-plugin</artifactId> |
||||
<version>1.0</version> |
||||
<executions> |
||||
<execution> |
||||
<phase>generate-test-sources</phase> |
||||
<goals> |
||||
<goal>test-process</goal> |
||||
</goals> |
||||
<configuration> |
||||
<outputDirectory>target/generated-sources/test-annotations</outputDirectory> |
||||
<processor>org.springframework.data.document.mongodb.repository.MongoAnnotationProcessor</processor> |
||||
</configuration> |
||||
</execution> |
||||
</executions> |
||||
</plugin> |
||||
</plugins> |
||||
</build> |
||||
|
||||
<repositories> |
||||
<repository> |
||||
<id>querydsl</id> |
||||
<name>Mysema QueryDsl</name> |
||||
<url>http://source.mysema.com/maven2/releases</url> |
||||
<snapshots> |
||||
<enabled>false</enabled> |
||||
</snapshots> |
||||
</repository> |
||||
</repositories> |
||||
</project> |
||||
@ -0,0 +1,193 @@
@@ -0,0 +1,193 @@
|
||||
/* |
||||
* Copyright (c) 2011 by the original author(s). |
||||
* |
||||
* 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 org.springframework.data.document.mongodb.log4j; |
||||
|
||||
import java.net.UnknownHostException; |
||||
import java.util.Arrays; |
||||
import java.util.Calendar; |
||||
import java.util.Map; |
||||
|
||||
import com.mongodb.BasicDBList; |
||||
import com.mongodb.BasicDBObject; |
||||
import com.mongodb.DB; |
||||
import com.mongodb.Mongo; |
||||
import com.mongodb.WriteConcern; |
||||
import org.apache.log4j.AppenderSkeleton; |
||||
import org.apache.log4j.Level; |
||||
import org.apache.log4j.spi.LoggingEvent; |
||||
|
||||
/** |
||||
* @author Jon Brisbin <jbrisbin@vmware.com> |
||||
*/ |
||||
public class MongoLog4jAppender extends AppenderSkeleton { |
||||
|
||||
public static final String LEVEL = "level"; |
||||
public static final String NAME = "name"; |
||||
public static final String APP_ID = "applicationId"; |
||||
public static final String TIMESTAMP = "timestamp"; |
||||
public static final String PROPERTIES = "properties"; |
||||
public static final String TRACEBACK = "traceback"; |
||||
public static final String MESSAGE = "message"; |
||||
|
||||
protected String host = "localhost"; |
||||
protected int port = 27017; |
||||
protected String database = "logs"; |
||||
protected String collection = null; |
||||
protected String applicationId = System.getProperty("APPLICATION_ID", null); |
||||
protected WriteConcern warnOrHigherWriteConcern = WriteConcern.SAFE; |
||||
protected WriteConcern infoOrLowerWriteConcern = WriteConcern.NORMAL; |
||||
protected Mongo mongo; |
||||
protected DB db; |
||||
|
||||
public MongoLog4jAppender() { |
||||
} |
||||
|
||||
public MongoLog4jAppender(boolean isActive) { |
||||
super(isActive); |
||||
} |
||||
|
||||
public String getHost() { |
||||
return host; |
||||
} |
||||
|
||||
public void setHost(String host) { |
||||
this.host = host; |
||||
} |
||||
|
||||
public int getPort() { |
||||
return port; |
||||
} |
||||
|
||||
public void setPort(int port) { |
||||
this.port = port; |
||||
} |
||||
|
||||
public String getDatabase() { |
||||
return database; |
||||
} |
||||
|
||||
public void setDatabase(String database) { |
||||
this.database = database; |
||||
} |
||||
|
||||
public String getCollection() { |
||||
return collection; |
||||
} |
||||
|
||||
public void setCollection(String collection) { |
||||
this.collection = collection; |
||||
} |
||||
|
||||
public String getApplicationId() { |
||||
return applicationId; |
||||
} |
||||
|
||||
public void setApplicationId(String applicationId) { |
||||
this.applicationId = applicationId; |
||||
} |
||||
|
||||
public void setWarnOrHigherWriteConcern(String wc) { |
||||
this.warnOrHigherWriteConcern = WriteConcern.valueOf(wc); |
||||
} |
||||
|
||||
public String getWarnOrHigherWriteConcern() { |
||||
return warnOrHigherWriteConcern.toString(); |
||||
} |
||||
|
||||
public String getInfoOrLowerWriteConcern() { |
||||
return infoOrLowerWriteConcern.toString(); |
||||
} |
||||
|
||||
public void setInfoOrLowerWriteConcern(String wc) { |
||||
this.infoOrLowerWriteConcern = WriteConcern.valueOf(wc); |
||||
} |
||||
|
||||
protected void connectToMongo() throws UnknownHostException { |
||||
this.mongo = new Mongo(host, port); |
||||
this.db = mongo.getDB(database); |
||||
} |
||||
|
||||
@SuppressWarnings({"unchecked"}) |
||||
@Override |
||||
protected void append(final LoggingEvent event) { |
||||
if (null == db) { |
||||
try { |
||||
connectToMongo(); |
||||
} catch (UnknownHostException e) { |
||||
throw new RuntimeException(e.getMessage(), e); |
||||
} |
||||
} |
||||
|
||||
BasicDBObject dbo = new BasicDBObject(); |
||||
dbo.put(APP_ID, applicationId); |
||||
dbo.put(NAME, event.getLogger().getName()); |
||||
dbo.put(LEVEL, event.getLevel().toString()); |
||||
dbo.put(TIMESTAMP, String.format("%s", event.getTimeStamp())); |
||||
|
||||
// Copy properties into document
|
||||
Map<Object, Object> props = event.getProperties(); |
||||
if (null != props && props.size() > 0) { |
||||
BasicDBObject propsDbo = new BasicDBObject(); |
||||
for (Map.Entry<Object, Object> entry : props.entrySet()) { |
||||
propsDbo.put(entry.getKey().toString(), entry.getValue().toString()); |
||||
} |
||||
dbo.put(PROPERTIES, propsDbo); |
||||
} |
||||
|
||||
// Copy traceback info (if there is any) into the document
|
||||
String[] traceback = event.getThrowableStrRep(); |
||||
if (null != traceback && traceback.length > 0) { |
||||
BasicDBList tbDbo = new BasicDBList(); |
||||
tbDbo.addAll(Arrays.asList(traceback)); |
||||
dbo.put(TRACEBACK, tbDbo); |
||||
} |
||||
|
||||
// Put the rendered message into the document
|
||||
dbo.put(MESSAGE, event.getRenderedMessage()); |
||||
|
||||
// Insert the document
|
||||
if (null == collection) { |
||||
// Use the category name
|
||||
collection = event.getLogger().getName(); |
||||
} else { |
||||
Calendar now = Calendar.getInstance(); |
||||
collection = String.format(collection, |
||||
now.get(Calendar.YEAR), |
||||
now.get(Calendar.MONTH), |
||||
now.get(Calendar.DAY_OF_MONTH), |
||||
now.get(Calendar.HOUR_OF_DAY), |
||||
event.getLevel().toString(), |
||||
event.getLogger().getName()); |
||||
} |
||||
|
||||
WriteConcern wc; |
||||
if (event.getLevel().isGreaterOrEqual(Level.WARN)) { |
||||
wc = warnOrHigherWriteConcern; |
||||
} else { |
||||
wc = infoOrLowerWriteConcern; |
||||
} |
||||
db.getCollection(collection).insert(dbo, wc); |
||||
} |
||||
|
||||
public void close() { |
||||
mongo.close(); |
||||
} |
||||
|
||||
public boolean requiresLayout() { |
||||
return true; |
||||
} |
||||
} |
||||
@ -0,0 +1,71 @@
@@ -0,0 +1,71 @@
|
||||
/* |
||||
* Copyright (c) 2011 by the original author(s). |
||||
* |
||||
* 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 org.springframework.data.document.mongodb.log4j; |
||||
|
||||
import static org.hamcrest.Matchers.*; |
||||
import static org.junit.Assert.*; |
||||
|
||||
import java.net.UnknownHostException; |
||||
|
||||
import com.mongodb.DB; |
||||
import com.mongodb.DBCursor; |
||||
import com.mongodb.Mongo; |
||||
import org.apache.log4j.Logger; |
||||
import org.apache.log4j.MDC; |
||||
import org.junit.Before; |
||||
import org.junit.Test; |
||||
|
||||
/** |
||||
* @author Jon Brisbin <jbrisbin@vmware.com> |
||||
*/ |
||||
public class AppenderTest { |
||||
|
||||
private static final String NAME = AppenderTest.class.getName(); |
||||
private Logger log = Logger.getLogger(NAME); |
||||
private Mongo mongo; |
||||
private DB db; |
||||
|
||||
@Before |
||||
public void setup() { |
||||
try { |
||||
mongo = new Mongo("localhost", 27017); |
||||
db = mongo.getDB("logs"); |
||||
db.getCollection(NAME).drop(); |
||||
} catch (UnknownHostException e) { |
||||
throw new RuntimeException(e.getMessage(), e); |
||||
} |
||||
} |
||||
|
||||
@Test |
||||
public void testLogging() { |
||||
log.debug("DEBUG message"); |
||||
log.info("INFO message"); |
||||
log.warn("WARN message"); |
||||
log.error("ERROR message"); |
||||
|
||||
DBCursor msgs = db.getCollection(NAME).find(); |
||||
assertThat(msgs.count(), is(4)); |
||||
|
||||
} |
||||
|
||||
@Test |
||||
public void testProperties() { |
||||
MDC.put("property", "one"); |
||||
log.debug("DEBUG message"); |
||||
} |
||||
|
||||
} |
||||
@ -0,0 +1,19 @@
@@ -0,0 +1,19 @@
|
||||
log4j.rootCategory=INFO, stdout |
||||
|
||||
log4j.appender.stdout=org.springframework.data.document.mongodb.log4j.MongoLog4jAppender |
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout |
||||
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - <%m>%n |
||||
log4j.appender.stdout.host = localhost |
||||
log4j.appender.stdout.port = 27017 |
||||
log4j.appender.stdout.database = logs |
||||
log4j.appender.stdout.applicationId = my.application |
||||
log4j.appender.stdout.warnOrHigherWriteConcern = FSYNC_SAFE |
||||
|
||||
log4j.category.org.apache.activemq=ERROR |
||||
log4j.category.org.springframework.batch=DEBUG |
||||
log4j.category.org.springframework.data.document.mongodb=DEBUG |
||||
log4j.category.org.springframework.transaction=INFO |
||||
|
||||
log4j.category.org.hibernate.SQL=DEBUG |
||||
# for debugging datasource initialization |
||||
# log4j.category.test.jdbc=DEBUG |
||||
Loading…
Reference in new issue