| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You 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.apache.log4j.db; |
| |
| import junit.framework.Test; |
| import junit.framework.TestCase; |
| import junit.framework.TestSuite; |
| import org.apache.log4j.Hierarchy; |
| import org.apache.log4j.Level; |
| import org.apache.log4j.Logger; |
| import org.apache.log4j.MDC; |
| import org.apache.log4j.VectorAppender; |
| import org.apache.log4j.LoggerRepositoryExImpl; |
| import org.apache.log4j.helpers.Constants; |
| import org.apache.log4j.xml.DOMConfigurator; |
| import org.apache.log4j.spi.LocationInfo; |
| import org.apache.log4j.spi.LoggingEvent; |
| import org.apache.log4j.spi.RootLogger; |
| import org.apache.log4j.spi.LoggerRepository; |
| |
| import java.sql.Connection; |
| import java.sql.DriverManager; |
| import java.sql.SQLException; |
| import java.sql.Statement; |
| import java.util.Iterator; |
| import java.util.Map; |
| import java.util.Vector; |
| import java.util.HashMap; |
| import java.io.InputStream; |
| import java.io.IOException; |
| |
| |
| /** |
| * This test case writes a few events into a databases and reads them |
| * back comparing the event written and read back. |
| * |
| * <p>It relies heavily on the proper configuration of its environment |
| * in joran config files as well system properties. |
| * </p> |
| * |
| * <p>See also the Ant build file in the tests/ directory.</p> |
| * |
| * @author Ceki Gülcü |
| */ |
| public class FullCycleDBTest |
| extends TestCase { |
| |
| Vector witnessEvents; |
| Hierarchy lrWrite; |
| LoggerRepository lrRead; |
| String appendConfigFile = null; |
| String readConfigFile = null; |
| |
| |
| /* |
| * @see TestCase#setUp() |
| */ |
| protected void setUp() |
| throws Exception { |
| super.setUp(); |
| appendConfigFile = "append-with-drivermanager1.xml"; |
| readConfigFile = "read-with-drivermanager1.xml"; |
| |
| witnessEvents = new Vector(); |
| lrWrite = new Hierarchy(new RootLogger(Level.DEBUG)); |
| lrRead = new LoggerRepositoryExImpl(new Hierarchy(new RootLogger(Level.DEBUG))); |
| |
| |
| // |
| // attempt to define tables in in-memory database |
| // will throw exception if already defined. |
| // |
| Class.forName("org.hsqldb.jdbcDriver"); |
| Connection connection = DriverManager.getConnection("jdbc:hsqldb:mem:testdb"); |
| try { |
| Statement s = connection.createStatement(); |
| s.executeUpdate("CREATE TABLE logging_event " + |
| "( sequence_number BIGINT NOT NULL, " + |
| " timestamp BIGINT NOT NULL, " + |
| " rendered_message LONGVARCHAR NOT NULL, " + |
| " logger_name VARCHAR NOT NULL, " + |
| " level_string VARCHAR NOT NULL, " + |
| " ndc LONGVARCHAR, " + |
| " thread_name VARCHAR, " + |
| " reference_flag SMALLINT, " + |
| " caller_filename VARCHAR, " + |
| " caller_class VARCHAR, " + |
| " caller_method VARCHAR, " + |
| " caller_line CHAR(4), " + |
| " event_id INT NOT NULL IDENTITY)"); |
| s.executeUpdate("CREATE TABLE logging_event_property " + |
| "( event_id INT NOT NULL, " + |
| " mapped_key VARCHAR(254) NOT NULL, " + |
| " mapped_value LONGVARCHAR, " + |
| " PRIMARY KEY(event_id, mapped_key), " + |
| " FOREIGN KEY (event_id) REFERENCES logging_event(event_id))"); |
| s.executeUpdate("CREATE TABLE logging_event_exception" + |
| " ( event_id INT NOT NULL, " + |
| " i SMALLINT NOT NULL," + |
| " trace_line VARCHAR NOT NULL," + |
| " PRIMARY KEY(event_id, i)," + |
| " FOREIGN KEY (event_id) REFERENCES logging_event(event_id))"); |
| } catch(SQLException ex) { |
| String s = ex.toString(); |
| } finally { |
| connection.close(); |
| } |
| |
| } |
| |
| |
| /* |
| * @see TestCase#tearDown() |
| */ |
| protected void tearDown() |
| throws Exception { |
| super.tearDown(); |
| lrRead.shutdown(); |
| witnessEvents = null; |
| } |
| |
| /** |
| * Constructor for DBReeceiverTest. |
| * @param arg0 |
| */ |
| public FullCycleDBTest(String arg0) { |
| super(arg0); |
| } |
| |
| |
| /** |
| * This test starts by writing a single event to a DB using DBAppender |
| * and then reads it back using DBReceiver. |
| * |
| * DB related information is specified within the configuration files. |
| * @throws Exception |
| */ |
| public void testSingleOutput() |
| throws Exception { |
| DOMConfigurator jc1 = new DOMConfigurator(); |
| InputStream is = FullCycleDBTest.class.getResourceAsStream(appendConfigFile); |
| jc1.doConfigure(is, lrWrite); |
| is.close(); |
| |
| long startTime = System.currentTimeMillis(); |
| System.out.println("***startTime is "+startTime); |
| |
| // Write out just one log message |
| Logger out = lrWrite.getLogger("testSingleOutput.out"); |
| out.debug("some message"+startTime); |
| |
| VectorAppender witnessAppender = (VectorAppender) lrWrite.getRootLogger().getAppender("VECTOR"); |
| witnessEvents = witnessAppender.getVector(); |
| assertEquals(1, witnessEvents.size()); |
| |
| // We have to close all appenders before starting to read |
| lrWrite.shutdown(); |
| |
| // now read it back |
| readBack(readConfigFile, startTime); |
| |
| } |
| |
| /** |
| * This test starts by writing a single event to a DB using DBAppender |
| * and then reads it back using DBReceiver. |
| * |
| * The written event includes MDC and repository properties as well as |
| * exception info. |
| * |
| * DB related information is specified within the configuration files. |
| * @throws Exception |
| */ |
| public void testAllFields() throws IOException { |
| DOMConfigurator jc1 = new DOMConfigurator(); |
| InputStream is = FullCycleDBTest.class.getResourceAsStream(appendConfigFile); |
| jc1.doConfigure(is, lrWrite); |
| is.close(); |
| |
| long startTime = System.currentTimeMillis(); |
| |
| // Write out just one log message |
| MDC.put("key1", "value1-"+startTime); |
| MDC.put("key2", "value2-"+startTime); |
| Map mdcMap = MDC.getContext(); |
| // LogLog.info("**********"+mdcMap.size()); |
| |
| // Write out just one log message |
| Logger out = lrWrite.getLogger("out"+startTime); |
| |
| out.debug("some message"+startTime); |
| MDC.put("key3", "value2-"+startTime); |
| out.error("some error message"+startTime, new Exception("testing")); |
| |
| // we clear the MDC to avoid interference with the events read back from |
| // the db |
| MDC.remove("key1"); |
| MDC.remove("key2"); |
| MDC.remove("key3"); |
| |
| VectorAppender witnessAppender = (VectorAppender) lrWrite.getRootLogger().getAppender("VECTOR"); |
| witnessEvents = witnessAppender.getVector(); |
| assertEquals(2, witnessEvents.size()); |
| |
| // We have to close all appenders just before starting to read |
| lrWrite.shutdown(); |
| |
| readBack(readConfigFile, startTime); |
| } |
| |
| |
| void readBack(String configfile, long startTime) throws IOException { |
| DOMConfigurator jc2 = new DOMConfigurator(); |
| InputStream is = FullCycleDBTest.class.getResourceAsStream(configfile); |
| jc2.doConfigure(is, lrRead); |
| is.close(); |
| |
| // wait a little to allow events to be read |
| try { Thread.sleep(3100); } catch(Exception e) {} |
| VectorAppender va = (VectorAppender) lrRead.getRootLogger().getAppender("VECTOR"); |
| Vector returnedEvents = getRelevantEventsFromVA(va, startTime); |
| |
| compareEvents(witnessEvents, returnedEvents); |
| |
| } |
| |
| void compareEvents(Vector l, Vector r) { |
| assertNotNull("left vector of events should not be null"); |
| assertEquals(l.size(), r.size()); |
| |
| for(int i = 0; i < r.size(); i++) { |
| LoggingEvent le = (LoggingEvent) l.get(i); |
| LoggingEvent re = (LoggingEvent) r.get(i); |
| assertEquals(le.getMessage(), re.getMessage()); |
| assertEquals(le.getLoggerName(), re.getLoggerName()); |
| assertEquals(le.getLevel(), re.getLevel()); |
| assertEquals(le.getThreadName(), re.getThreadName()); |
| if(re.getTimeStamp() < le.getTimeStamp()) { |
| fail("Returned event cannot preceed witness timestamp"); |
| } |
| |
| Map sourceMap = re.getProperties(); |
| Map remap; |
| if (sourceMap == null) { |
| remap = new HashMap(); |
| } else { |
| remap = new HashMap(sourceMap); |
| if (remap.containsKey(Constants.LOG4J_ID_KEY)) { |
| remap.remove(Constants.LOG4J_ID_KEY); |
| } |
| } |
| if(le.getProperties() == null || le.getProperties().size() == 0) { |
| if(remap.size() != 0) { |
| System.out.println("properties are "+remap); |
| fail("Returned event should have been empty"); |
| } |
| } else { |
| assertEquals(le.getProperties(), remap); |
| } |
| comprareStringArrays( le.getThrowableStrRep(), re.getThrowableStrRep()); |
| compareLocationInfo(le, re); |
| } |
| } |
| |
| void comprareStringArrays(String[] la, String[] ra) { |
| if((la == null) && (ra == null)) { |
| return; |
| } |
| assertEquals(la.length, ra.length); |
| for(int i = 0; i < la.length; i++) { |
| assertEquals(la[i], ra[i]); |
| } |
| } |
| |
| void compareLocationInfo(LoggingEvent l, LoggingEvent r) { |
| if(l.locationInformationExists()) { |
| assertEquals(l.getLocationInformation().fullInfo, r.getLocationInformation().fullInfo); |
| } else { |
| assertEquals(LocationInfo.NA_LOCATION_INFO, r.getLocationInformation()); |
| } |
| } |
| |
| Vector getRelevantEventsFromVA(VectorAppender va, long startTime) { |
| assertNotNull(va); |
| Vector v = va.getVector(); |
| Vector r = new Vector(); |
| // remove all elements older than startTime |
| for(Iterator i = v.iterator(); i.hasNext(); ) { |
| LoggingEvent event = (LoggingEvent) i.next(); |
| if(startTime > event.getTimeStamp()) { |
| System.out.println("***Removing event with timestamp "+event.getTimeStamp()); |
| } else { |
| System.out.println("***Keeping event with timestamo"+event.getTimeStamp()); |
| r.add(event); |
| } |
| } |
| return r; |
| } |
| |
| void dump(Vector v) { |
| for(int i = 0; i < v.size(); i++) { |
| LoggingEvent le = (LoggingEvent) v.get(i); |
| System.out.println("---"+le.getLevel()+" "+le.getLoggerName()+" "+le.getMessage()); |
| } |
| } |
| |
| public static Test XXsuite() { |
| TestSuite suite = new TestSuite(); |
| suite.addTest(new FullCycleDBTest("testSingleOutput")); |
| suite.addTest(new FullCycleDBTest("testAllFields")); |
| return suite; |
| } |
| } |