logback-dev
Threads by month
- ----- 2026 -----
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- 9940 discussions
[GIT] Logback: the generic, reliable, fast and flexible logging framework. branch, master, updated. v_0.9.27-1-g4a792d8
by git-noreply@pixie.qos.ch 27 Dec '10
by git-noreply@pixie.qos.ch 27 Dec '10
27 Dec '10
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Logback: the generic, reliable, fast and flexible logging framework.".
The branch, master has been updated
via 4a792d8efd47548dedbf838ef5d32531e9a928c8 (commit)
from c6c098ff63d8af47d10da2bb5a90f6aaea011c59 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://git.qos.ch/gitweb/?p=logback.git;a=commit;h=4a792d8efd47548dedbf838e…
http://github.com/ceki/logback/commit/4a792d8efd47548dedbf838ef5d32531e9a92…
commit 4a792d8efd47548dedbf838ef5d32531e9a928c8
Author: Ceki Gulcu <ceki(a)qos.ch>
Date: Mon Dec 27 17:17:35 2010 +0100
moving various tests to scala
diff --git a/logback-access/pom.xml b/logback-access/pom.xml
index 11bb3db..dcfeb31 100644
--- a/logback-access/pom.xml
+++ b/logback-access/pom.xml
@@ -7,7 +7,7 @@
<parent>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
- <version>0.9.27</version>
+ <version>0.9.28-SNAPSHOT</version>
</parent>
<artifactId>logback-access</artifactId>
diff --git a/logback-classic/pom.xml b/logback-classic/pom.xml
index 7eea5e8..ed392a5 100644
--- a/logback-classic/pom.xml
+++ b/logback-classic/pom.xml
@@ -7,7 +7,7 @@
<parent>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
- <version>0.9.27</version>
+ <version>0.9.28-SNAPSHOT</version>
</parent>
<artifactId>logback-classic</artifactId>
diff --git a/logback-classic/src/test/java/ch/qos/logback/classic/turbo/ReconfigureOnChangeTest.java b/logback-classic/src/test/java/ch/qos/logback/classic/turbo/ReconfigureOnChangeTest.java
index 546a653..f080e50 100644
--- a/logback-classic/src/test/java/ch/qos/logback/classic/turbo/ReconfigureOnChangeTest.java
+++ b/logback-classic/src/test/java/ch/qos/logback/classic/turbo/ReconfigureOnChangeTest.java
@@ -179,7 +179,7 @@ public class ReconfigureOnChangeTest {
// we can't have the test succeed under JDK 1.5, punt and require 1.6+
if (Env.isJDK6OrHigher()) {
assertTrue(failMsg,
- (effectiveResets * 1.4) >= (expectedReconfigurations * 1.0));
+ (effectiveResets * 1.5) >= (expectedReconfigurations * 1.0));
}
}
diff --git a/logback-core/pom.xml b/logback-core/pom.xml
index ec015b0..4c2f517 100644
--- a/logback-core/pom.xml
+++ b/logback-core/pom.xml
@@ -1,167 +1,193 @@
<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>ch.qos.logback</groupId>
- <artifactId>logback-parent</artifactId>
- <version>0.9.27</version>
- </parent>
-
- <artifactId>logback-core</artifactId>
- <packaging>jar</packaging>
- <name>Logback Core Module</name>
-
- <url>http://logback.qos.ch</url>
- <description>
- <!--
- Never _never_ let Eclipse's auto format function add
- a line return in the description.
- The generated jar will contain a corrupt MANIFEST file.
- -->
- Logback: the generic, reliable, fast and flexible logging library for Java.
- </description>
-
- <licenses>
- <license>
- <name>Eclipse Public License - v 1.0</name>
- <url>http://www.eclipse.org/legal/epl-v10.html</url>
- </license>
-
- <license>
- <name>GNU Lesser General Public License</name>
- <url>http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html</url>
- </license>
- </licenses>
-
- <dependencies>
- <dependency>
- <groupId>janino</groupId>
- <artifactId>janino</artifactId>
- <scope>compile</scope>
- <optional>true</optional>
- </dependency>
-
- <dependency>
- <groupId>org.codehaus.groovy</groupId>
- <artifactId>groovy-all</artifactId>
- <scope>compile</scope>
- <optional>true</optional>
- </dependency>
-
-
- <dependency>
- <groupId>javax.mail</groupId>
- <artifactId>mail</artifactId>
- <scope>compile</scope>
- <optional>true</optional>
- </dependency>
- <dependency>
- <groupId>org.apache.geronimo.specs</groupId>
- <artifactId>geronimo-jms_1.1_spec</artifactId>
- <scope>compile</scope>
- <optional>true</optional>
- </dependency>
-
- <dependency>
- <groupId>org.easymock</groupId>
- <artifactId>easymock</artifactId>
- <version>2.4</version>
- <scope>test</scope>
- </dependency>
-
- <dependency>
- <groupId>javax.servlet</groupId>
- <artifactId>servlet-api</artifactId>
- <scope>compile</scope>
- <optional>true</optional>
- </dependency>
- </dependencies>
-
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <configuration>
- <source>1.5</source>
- <target>1.5</target>
- </configuration>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-compiler-plugin</artifactId>
- <configuration>
- <source>1.5</source>
- <target>1.5</target>
- </configuration>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-surefire-plugin</artifactId>
- <configuration>
- <forkMode>once</forkMode>
- <reportFormat>plain</reportFormat>
- <trimStackTrace>false</trimStackTrace>
- <excludes>
- <exclude>**/All*Test.java</exclude>
- <exclude>**/PackageTest.java</exclude>
- </excludes>
- </configuration>
- </plugin>
-
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-jar-plugin</artifactId>
- <configuration>
- <archive>
- <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
- </archive>
- </configuration>
- <executions>
- <execution>
- <id>bundle-test-jar</id>
- <phase>package</phase>
- <goals>
- <goal>jar</goal>
- <goal>test-jar</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
-
- <plugin>
- <groupId>org.apache.felix</groupId>
- <artifactId>maven-bundle-plugin</artifactId>
- <extensions>true</extensions>
- <executions>
- <execution>
- <id>bundle-manifest</id>
- <phase>process-classes</phase>
- <goals>
- <goal>manifest</goal>
- </goals>
- </execution>
- </executions>
- <configuration>
- <instructions>
- <Export-Package>ch.qos.logback.core.*</Export-Package>
- <Import-Package>
- javax.*;resolution:=optional,
- org.xml.*;resolution:=optional,
- org.codehaus.janino;resolution:=optional,
- *
- </Import-Package>
- <Bundle-RequiredExecutionEnvironment>J2SE-1.5</Bundle-RequiredExecutionEnvironment>
- </instructions>
- </configuration>
- </plugin>
- </plugins>
- </build>
+ 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>ch.qos.logback</groupId>
+ <artifactId>logback-parent</artifactId>
+ <version>0.9.28-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>logback-core</artifactId>
+ <packaging>jar</packaging>
+ <name>Logback Core Module</name>
+
+ <url>http://logback.qos.ch</url>
+ <description>
+ <!--
+ Never _never_ let Eclipse's auto format function add
+ a line return in the description.
+ The generated jar will contain a corrupt MANIFEST file.
+ -->
+ Logback: the generic, reliable, fast and flexible logging library for Java.
+ </description>
+
+ <licenses>
+ <license>
+ <name>Eclipse Public License - v 1.0</name>
+ <url>http://www.eclipse.org/legal/epl-v10.html</url>
+ </license>
+
+ <license>
+ <name>GNU Lesser General Public License</name>
+ <url>http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html</url>
+ </license>
+ </licenses>
+
+ <dependencies>
+ <dependency>
+ <groupId>janino</groupId>
+ <artifactId>janino</artifactId>
+ <scope>compile</scope>
+ <optional>true</optional>
+ </dependency>
+
+ <dependency>
+ <groupId>org.codehaus.groovy</groupId>
+ <artifactId>groovy-all</artifactId>
+ <scope>compile</scope>
+ <optional>true</optional>
+ </dependency>
+
+
+ <dependency>
+ <groupId>javax.mail</groupId>
+ <artifactId>mail</artifactId>
+ <scope>compile</scope>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.geronimo.specs</groupId>
+ <artifactId>geronimo-jms_1.1_spec</artifactId>
+ <scope>compile</scope>
+ <optional>true</optional>
+ </dependency>
+
+ <dependency>
+ <groupId>org.easymock</groupId>
+ <artifactId>easymock</artifactId>
+ <version>2.4</version>
+ <scope>test</scope>
+ </dependency>
+
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <scope>compile</scope>
+ <optional>true</optional>
+ </dependency>
+
+ <dependency>
+ <groupId>org.scala-lang</groupId>
+ <artifactId>scala-library</artifactId>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.5</source>
+ <target>1.5</target>
+ </configuration>
+ </plugin>
+
+
+ <plugin>
+ <groupId>org.scala-tools</groupId>
+ <artifactId>maven-scala-plugin</artifactId>
+ <version>2.14.3</version>
+ <configuration>
+ <testSourceDir>src/test/scala</testSourceDir>
+ </configuration>
+ <executions>
+ <execution>
+ <id>scala-test-compile</id>
+ <phase>process-test-resources</phase>
+ <goals>
+ <goal>testCompile</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <configuration>
+ <forkMode>once</forkMode>
+ <reportFormat>plain</reportFormat>
+ <trimStackTrace>false</trimStackTrace>
+ <excludes>
+ <exclude>**/All*Test.java</exclude>
+ <exclude>**/PackageTest.java</exclude>
+ </excludes>
+ </configuration>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-jar-plugin</artifactId>
+ <configuration>
+ <archive>
+ <manifestFile>${project.build.outputDirectory}/META-INF/MANIFEST.MF</manifestFile>
+ </archive>
+ </configuration>
+ <executions>
+ <execution>
+ <id>bundle-test-jar</id>
+ <phase>package</phase>
+ <goals>
+ <goal>jar</goal>
+ <goal>test-jar</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <executions>
+ <execution>
+ <id>bundle-manifest</id>
+ <phase>process-classes</phase>
+ <goals>
+ <goal>manifest</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <instructions>
+ <Export-Package>ch.qos.logback.core.*</Export-Package>
+ <Import-Package>
+ javax.*;resolution:=optional,
+ org.xml.*;resolution:=optional,
+ org.codehaus.janino;resolution:=optional,
+ *
+ </Import-Package>
+ <Bundle-RequiredExecutionEnvironment>J2SE-1.5</Bundle-RequiredExecutionEnvironment>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
</project>
\ No newline at end of file
diff --git a/logback-core/src/test/scala/ch/qos/logback/core/rolling/A.scala b/logback-core/src/test/scala/ch/qos/logback/core/rolling/A.scala
new file mode 100644
index 0000000..b446737
--- /dev/null
+++ b/logback-core/src/test/scala/ch/qos/logback/core/rolling/A.scala
@@ -0,0 +1,41 @@
+package ch.qos.logback.core.rolling
+
+import collection.mutable.ListBuffer
+import org.junit.Test
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: ceki
+ * Date: 27.12.10
+ * Time: 14:19
+ * To change this template use File | Settings | File Templates.
+ */
+
+class A {
+
+
+ val initial = List(1,2, 3, 5)
+ def mon[B](f: Int => B): List[B] = {
+ val b = new ListBuffer[B]
+ var these = initial
+ while (!these.isEmpty) {
+ var that = f(these.head)
+ b += that
+ these = these.tail
+ }
+ b.toList
+ }
+
+ def asString(in: Any):String = {
+ "-"+ in.toString;
+ }
+
+ @Test
+ def doTest() {
+ val res: List[String] = mon(asString);
+ println(res)
+
+
+ }
+
+}
\ No newline at end of file
diff --git a/logback-core/src/test/scala/ch/qos/logback/core/rolling/RollingScaffolding.scala b/logback-core/src/test/scala/ch/qos/logback/core/rolling/RollingScaffolding.scala
new file mode 100644
index 0000000..ed78e3e
--- /dev/null
+++ b/logback-core/src/test/scala/ch/qos/logback/core/rolling/RollingScaffolding.scala
@@ -0,0 +1,85 @@
+/**
+ * Logback: the reliable, generic, fast and flexible logging framework.
+ * Copyright (C) 1999-2010, QOS.ch. All rights reserved.
+ *
+ * This program and the accompanying materials are dual-licensed under
+ * either the terms of the Eclipse Public License v1.0 as published by
+ * the Eclipse Foundation
+ *
+ * or (per the licensee's choosing)
+ *
+ * under the terms of the GNU Lesser General Public License version 2.1
+ * as published by the Free Software Foundation.
+ */
+package ch.qos.logback.core.rolling
+
+import ch.qos.logback.core.{ContextBase, Context}
+import ch.qos.logback.core.util.CoreTestConstants
+import ch.qos.logback.core.testUtil.RandomUtil
+import java.util.{Date, Calendar}
+import java.util.concurrent.TimeUnit
+import java.text.SimpleDateFormat
+
+trait RollingScaffolding {
+ final val DATE_PATTERN_WITH_SECONDS = "yyyy-MM-dd_HH_mm_ss"
+ final val SDF = new SimpleDateFormat(DATE_PATTERN_WITH_SECONDS)
+ private[rolling] var context: Context = new ContextBase
+ private[rolling] var diff: Int = RandomUtil.getPositiveInt
+ protected var currentTime: Long = 0L
+ protected var randomOutputDir: String = CoreTestConstants.OUTPUT_DIR_PREFIX + diff + "/"
+ private[rolling] var cal: Calendar = Calendar.getInstance
+ protected var nextRolloverThreshold: Long = 0;
+ protected var expectedFilenameList: List[String] = Nil
+
+ def setUpScaffolding: Unit = {
+ context.setName("test")
+ cal.set(Calendar.MILLISECOND, 333)
+ currentTime = cal.getTimeInMillis
+ nextRolloverThreshold = recomputeRolloverThreshold(currentTime)
+ }
+
+ protected def incCurrentTime(increment: Long): Unit = {
+ currentTime += increment
+ }
+
+ protected def getDateOfCurrentPeriodsStart: Date = {
+ var delta: Long = currentTime % 1000
+ return new Date(currentTime - delta)
+ }
+
+ protected def addExpectedFileName_ByDate(outputDir: String, testId: String, date: Date, gzExtension: Boolean): Unit = {
+ var fn: String = outputDir + testId + "-" + SDF.format(date)
+ if (gzExtension) {
+ fn += ".gz"
+ }
+ expectedFilenameList += fn
+
+ }
+
+ protected def addExpectedFileNamedIfItsTime_ByDate(outputDir: String, testId: String, gzExtension: Boolean): Unit = {
+ if (passThresholdTime(nextRolloverThreshold)) {
+ addExpectedFileName_ByDate(outputDir, testId, getDateOfCurrentPeriodsStart, gzExtension)
+ nextRolloverThreshold = recomputeRolloverThreshold(currentTime)
+ }
+ }
+
+ protected def passThresholdTime(nextRolloverThreshold: Long): Boolean = {
+ return currentTime >= nextRolloverThreshold
+ }
+
+ protected def recomputeRolloverThreshold(ct: Long): Long = {
+ var delta: Long = ct % 1000
+ (ct - delta) + 1000
+ }
+
+ private[rolling] def addGZIfNotLast(i: Int, suff: String): String = {
+ var lastIndex: Int = expectedFilenameList.size - 1
+ if (i != lastIndex) suff else ""
+ }
+
+ private[rolling] def waitForCompression(tbrp: TimeBasedRollingPolicy[AnyRef]): Unit = {
+ if (tbrp.future != null && !tbrp.future.isDone) {
+ tbrp.future.get(200, TimeUnit.MILLISECONDS)
+ }
+ }
+ }
\ No newline at end of file
diff --git a/logback-core/src/test/scala/ch/qos/logback/core/rolling/TimeBasedRolling2Test.scala b/logback-core/src/test/scala/ch/qos/logback/core/rolling/TimeBasedRolling2Test.scala
new file mode 100644
index 0000000..06bd4af
--- /dev/null
+++ b/logback-core/src/test/scala/ch/qos/logback/core/rolling/TimeBasedRolling2Test.scala
@@ -0,0 +1,104 @@
+/**
+ * Logback: the reliable, generic, fast and flexible logging framework.
+ * Copyright (C) 1999-2010, QOS.ch. All rights reserved.
+ *
+ * This program and the accompanying materials are dual-licensed under
+ * either the terms of the Eclipse Public License v1.0 as published by
+ * the Eclipse Foundation
+ *
+ * or (per the licensee's choosing)
+ *
+ * under the terms of the GNU Lesser General Public License version 2.1
+ * as published by the Free Software Foundation.
+ */
+package ch.qos.logback.core.rolling
+
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import ch.qos.logback.core.util.Compare
+import ch.qos.logback.core.util.CoreTestConstants
+import ch.qos.logback.core.encoder.EchoEncoder
+
+class TimeBasedRolling2Test extends RollingScaffolding {
+
+ private[rolling] var rfa1: RollingFileAppender[AnyRef] = new RollingFileAppender[AnyRef]
+ private[rolling] var tbrp1: TimeBasedRollingPolicy[AnyRef] = new TimeBasedRollingPolicy[AnyRef]
+ private[rolling] var encoder: EchoEncoder[AnyRef] = new EchoEncoder[AnyRef]
+
+ @Before
+ def setUp: Unit = {
+ setUpScaffolding
+ }
+
+ private[rolling] def initRFA(rfa: RollingFileAppender[AnyRef], filename: String): Unit = {
+ rfa.setContext(context)
+ rfa.setEncoder(encoder)
+ if (filename != null) {
+ rfa.setFile(filename)
+ }
+ }
+
+ private[rolling] def initTRBP(rfa: RollingFileAppender[AnyRef], tbrp: TimeBasedRollingPolicy[AnyRef], filenamePattern: String, givenTime: Long): Unit = {
+ tbrp.setContext(context)
+ tbrp.setFileNamePattern(filenamePattern)
+ tbrp.setParent(rfa)
+ tbrp.timeBasedFileNamingAndTriggeringPolicy = new DefaultTimeBasedFileNamingAndTriggeringPolicy[AnyRef]
+ tbrp.timeBasedFileNamingAndTriggeringPolicy.setCurrentTime(givenTime)
+ rfa.setRollingPolicy(tbrp)
+ tbrp.start
+ rfa.start
+ }
+
+ def genericTest(testId: String, compressionSuffix: String): Unit = {
+ val withCompression = compressionSuffix.length > 0
+ initRFA(rfa1, null);
+ println(randomOutputDir + testId + "-%d{"
+ + DATE_PATTERN_WITH_SECONDS + "}" + compressionSuffix )
+
+ initTRBP(rfa1, tbrp1, randomOutputDir + testId + "-%d{"
+ + DATE_PATTERN_WITH_SECONDS + "}" + compressionSuffix, currentTime);
+
+ // compute the current filename
+ addExpectedFileName_ByDate(randomOutputDir, testId, getDateOfCurrentPeriodsStart, withCompression);
+
+ incCurrentTime(1100);
+ tbrp1.timeBasedFileNamingAndTriggeringPolicy.setCurrentTime(currentTime);
+
+ for (i <- 0 until 3) {
+ rfa1.doAppend("Hello---" + i);
+ addExpectedFileNamedIfItsTime_ByDate(randomOutputDir, testId, withCompression && (i !=2))
+ incCurrentTime(500);
+ tbrp1.timeBasedFileNamingAndTriggeringPolicy.setCurrentTime(currentTime)
+ if(withCompression)
+ waitForCompression(tbrp1)
+ }
+
+ var i = 0;
+ for (fn <- expectedFilenameList) {
+ val suffix: String = if(withCompression) addGZIfNotLast(i, compressionSuffix) else ""
+ val witnessFileName: String = CoreTestConstants.TEST_DIR_PREFIX + "witness/rolling/tbr-" + testId + "." + i.toString + suffix
+ assertTrue(Compare.compare(fn, witnessFileName));
+ i += 1
+ }
+
+ }
+
+ /**
+ * Test rolling without compression, file option left blank, no stop/start
+ */
+ @Test
+ def noCompression_FileBlank_NoRestart_1 = {
+ genericTest("test1", "")
+ }
+
+ /**
+ * With compression, file option left blank, no stop/restart
+ */
+ @Test
+ def withCompression_FileBlank_NoRestart_2 = {
+ genericTest("test2", ".gz");
+ }
+
+
+}
\ No newline at end of file
diff --git a/logback-examples/pom.xml b/logback-examples/pom.xml
index 2428f24..48b65ba 100644
--- a/logback-examples/pom.xml
+++ b/logback-examples/pom.xml
@@ -5,7 +5,7 @@
<parent>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
- <version>0.9.27</version>
+ <version>0.9.28-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
diff --git a/logback-site/pom.xml b/logback-site/pom.xml
index 2c2b192..a1707da 100644
--- a/logback-site/pom.xml
+++ b/logback-site/pom.xml
@@ -3,7 +3,7 @@
<parent>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
- <version>0.9.27</version>
+ <version>0.9.28-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
diff --git a/logback-site/src/site/pages/documentation.html b/logback-site/src/site/pages/documentation.html
index bdfcf72..5c07e09 100644
--- a/logback-site/src/site/pages/documentation.html
+++ b/logback-site/src/site/pages/documentation.html
@@ -90,12 +90,8 @@
</li>
<li><a
- href="http://www.devoxx.com:5080/player/main.html#state=state_player&id=357&slide…">SLF4J
- and Logback projects</a>, by C. Gülcü and S. Pennec
- (Jazoon presentation with audio). If the previous link does not
- work, please try the <a
- href="http://beta.parleys.com/share/parleysshare2.swf?pageId=357">back
- up</a>.
+ href="http://beta.parleys.com/#id=1701&st=5&sl=1"><b>Devoxx-2009
+ video presentation</b></a>, by C. Gülcü
</li>
<li><a
diff --git a/logback-site/src/site/pages/news.html b/logback-site/src/site/pages/news.html
index 4144b5d..178c2d8 100644
--- a/logback-site/src/site/pages/news.html
+++ b/logback-site/src/site/pages/news.html
@@ -28,6 +28,10 @@
<hr width="80%" align="center" />
+ <h3>January xx, 2011 - Release of version 0.9.28</h3>
+
+ <hr width="80%" align="center" />
+
<h3>December 22nd, 2010 - Release of version 0.9.27</h3>
<p>Added a new section in the documentation about <a
diff --git a/pom.xml b/pom.xml
index b91736b..992972d 100755
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
- <version>0.9.27</version>
+ <version>0.9.28-SNAPSHOT</version>
<packaging>pom</packaging>
<name>Logback-Parent</name>
@@ -34,7 +34,7 @@
<slf4j.version>1.6.1</slf4j.version>
<junit.version>4.7</junit.version>
<janino.version>2.5.10</janino.version>
-
+ <scala.version>2.7.7</scala.version>
<consolePlugin.version>1.1.0</consolePlugin.version>
</properties>
@@ -154,10 +154,17 @@
<version>1.0</version>
</dependency>
<dependency>
- <groupId>javax.servlet</groupId>
- <artifactId>servlet-api</artifactId>
- <version>2.5</version>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ <version>2.5</version>
</dependency>
+
+ <dependency>
+ <groupId>org.scala-lang</groupId>
+ <artifactId>scala-library</artifactId>
+ <version>${scala.version}</version>
+ </dependency>
+
</dependencies>
</dependencyManagement>
@@ -225,6 +232,7 @@
<outputDirectory>target/site/dist/</outputDirectory>
</configuration>
</plugin>
+
</plugins>
</build>
diff --git a/src/main/header.txt b/src/main/header.txt
index 56d0e7b..cf0e315 100644
--- a/src/main/header.txt
+++ b/src/main/header.txt
@@ -1,6 +1,6 @@
Logback: the generic, reliable, fast and flexible logging framework.
-Copyright (C) 1999-2009, QOS.ch. All rights reserved.
+Copyright (C) 1999-2010, QOS.ch. All rights reserved.
This program and the accompanying materials are dual-licensed under
either the terms of the Eclipse Public License v1.0 as published by
-----------------------------------------------------------------------
Summary of changes:
logback-access/pom.xml | 2 +-
logback-classic/pom.xml | 2 +-
.../classic/turbo/ReconfigureOnChangeTest.java | 2 +-
logback-core/pom.xml | 354 +++++++++++---------
.../test/scala/ch/qos/logback/core/rolling/A.scala | 41 +++
.../logback/core/rolling/RollingScaffolding.scala | 85 +++++
.../core/rolling/TimeBasedRolling2Test.scala | 104 ++++++
logback-examples/pom.xml | 2 +-
logback-site/pom.xml | 2 +-
logback-site/src/site/pages/documentation.html | 8 +-
logback-site/src/site/pages/news.html | 4 +
pom.xml | 18 +-
src/main/header.txt | 2 +-
13 files changed, 445 insertions(+), 181 deletions(-)
create mode 100644 logback-core/src/test/scala/ch/qos/logback/core/rolling/A.scala
create mode 100644 logback-core/src/test/scala/ch/qos/logback/core/rolling/RollingScaffolding.scala
create mode 100644 logback-core/src/test/scala/ch/qos/logback/core/rolling/TimeBasedRolling2Test.scala
hooks/post-receive
--
Logback: the generic, reliable, fast and flexible logging framework.
1
0
Hello all,
In light of the large code base in logback dealing with tests, I started
moving some of the test to Scala. As you are probably aware, Scala has a
number serious advantages over java. It has some serious disadvantages
as well. It's all still very experimental. I'll let you know how it goes.
Cheers,
--
Ceki
1
0
Nullpointer
-----------
Key: LBCLASSIC-113
URL: http://jira.qos.ch/browse/LBCLASSIC-113
Project: logback-classic
Issue Type: Bug
Components: Other
Reporter: Mathias Bogaert
Assignee: Logback dev list
Priority: Critical
java.lang.NullPointerException
at ch.qos.logback.classic.Logger.callTurboFilters(Logger.java:769) [logback-classic-0.9.15.jar:na]
at ch.qos.logback.classic.Logger.isTraceEnabled(Logger.java:641) [logback-classic-0.9.15.jar:na]
at ch.qos.logback.classic.Logger.isTraceEnabled(Logger.java:637) [logback-classic-0.9.15.jar:na]
at org.hibernate.event.def.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:198) [hibernate-core-3.3.0.SP1.jar:3.3.0.SP1]
at org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:126) [hibernate-core-3.3.0.SP1.jar:3.3.0.SP1]
at org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:905) [hibernate-core-3.3.0.SP1.jar:3.3.0.SP1]
Hibernate calls if ( log.isTraceEnabled() ).
--
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://jira.qos.ch/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira
3
3
[GIT] Logback: the generic, reliable, fast and flexible logging framework. annotated tag, v_0.9.27, created. v_0.9.27
by git-noreply@pixie.qos.ch 22 Dec '10
by git-noreply@pixie.qos.ch 22 Dec '10
22 Dec '10
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Logback: the generic, reliable, fast and flexible logging framework.".
The annotated tag, v_0.9.27 has been created
at ee40f0381308f61d040c28ccb534af9abf829871 (tag)
tagging c6c098ff63d8af47d10da2bb5a90f6aaea011c59 (commit)
replaces v_0.9.25
tagged by Ceki Gulcu
on Wed Dec 22 23:11:30 2010 +0100
- Log -----------------------------------------------------------------
tagging release 0.9.27
Ceki Gulcu (54):
start work on next version
typo fixes
fix LBCORE-114
trying to hunt down LBCLASSIC-223
logback-classic should be based on the latest SLF4J...
InetAdress.canonicalHostName is not necessarily the same as InetHost.hostname
patial fix for LBCLASSIC-183. It helps if the ThreadLoacal class is
Solve LBCLASSIC-183. Use InheritableThreadLocal instead of
editing
ongoing work
OnConsoleStatusListener now retrospectively prints status messages
minor refactoring
Fix LBCLASSIC-226
- fix LBCORE-170
start work on 0.9.27
added link to XtremeMP project
adding recipes
on going work on th emailPerTransaction recipe
working on the documentation
avoid output on folders outside target/test-output
avoid polluting the output for default additity, added a test case
Fix LBCLASSIC-231
blurb in the news
ongoing work on the docs
fix LBCORE-174
documenation in relation with LBCLASSIC-212
minor editing
- Ongoing work on LBCORE-180 and LBCLASSIC-232
minor editing
TeeFilter now takes include and exclude parameters so that it can be
minor edit
- pom.xml clean up
- minor edits
news about LBACCESS-15
ongoing work on the documentation
ongoing edits
ow
minor edits
logback-access documentaiton improvements
logback-access documentation improvements
add support for dynamic destination address computation in SMTPAppender
adding support for composite keywords
ongoing work on compound conversion words
working version of compound keywords
doc improvements
applied Inigo Surguy's proof reading patch
- merged OptionTokenizer into TokenStream in order to lift the
ongoing docs edits
add missing file
ongoing edits
more edits
- Improved testing of CyclicBufferTracker. Added support for immediate
- doc improvements
- minor edits to news.html
-----------------------------------------------------------------------
hooks/post-receive
--
Logback: the generic, reliable, fast and flexible logging framework.
1
0
[GIT] Logback: the generic, reliable, fast and flexible logging framework. branch, master, updated. v_0.9.25-54-gc6c098f
by git-noreply@pixie.qos.ch 22 Dec '10
by git-noreply@pixie.qos.ch 22 Dec '10
22 Dec '10
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Logback: the generic, reliable, fast and flexible logging framework.".
The branch, master has been updated
via c6c098ff63d8af47d10da2bb5a90f6aaea011c59 (commit)
from 668e4464586c07ebe59c578406c3e7799508d46f (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://git.qos.ch/gitweb/?p=logback.git;a=commit;h=c6c098ff63d8af47d10da2bb…
http://github.com/ceki/logback/commit/c6c098ff63d8af47d10da2bb5a90f6aaea011…
commit c6c098ff63d8af47d10da2bb5a90f6aaea011c59
Author: Ceki Gulcu <ceki(a)qos.ch>
Date: Wed Dec 22 22:54:38 2010 +0100
- minor edits to news.html
- preparing release 0.9.27
diff --git a/logback-access/pom.xml b/logback-access/pom.xml
index b0e7ab3..11bb3db 100644
--- a/logback-access/pom.xml
+++ b/logback-access/pom.xml
@@ -7,7 +7,7 @@
<parent>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
- <version>0.9.27-SNAPSHOT</version>
+ <version>0.9.27</version>
</parent>
<artifactId>logback-access</artifactId>
diff --git a/logback-classic/pom.xml b/logback-classic/pom.xml
index f5dbbcb..7eea5e8 100644
--- a/logback-classic/pom.xml
+++ b/logback-classic/pom.xml
@@ -7,7 +7,7 @@
<parent>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
- <version>0.9.27-SNAPSHOT</version>
+ <version>0.9.27</version>
</parent>
<artifactId>logback-classic</artifactId>
diff --git a/logback-core/pom.xml b/logback-core/pom.xml
index d8b6207..ec015b0 100644
--- a/logback-core/pom.xml
+++ b/logback-core/pom.xml
@@ -7,7 +7,7 @@
<parent>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
- <version>0.9.27-SNAPSHOT</version>
+ <version>0.9.27</version>
</parent>
<artifactId>logback-core</artifactId>
diff --git a/logback-examples/pom.xml b/logback-examples/pom.xml
index 50fd2a0..2428f24 100644
--- a/logback-examples/pom.xml
+++ b/logback-examples/pom.xml
@@ -5,7 +5,7 @@
<parent>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
- <version>0.9.27-SNAPSHOT</version>
+ <version>0.9.27</version>
</parent>
<modelVersion>4.0.0</modelVersion>
diff --git a/logback-site/pom.xml b/logback-site/pom.xml
index d4a317c..2c2b192 100644
--- a/logback-site/pom.xml
+++ b/logback-site/pom.xml
@@ -3,7 +3,7 @@
<parent>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
- <version>0.9.27-SNAPSHOT</version>
+ <version>0.9.27</version>
</parent>
<modelVersion>4.0.0</modelVersion>
diff --git a/logback-site/src/site/pages/news.html b/logback-site/src/site/pages/news.html
index 99f8e53..4144b5d 100644
--- a/logback-site/src/site/pages/news.html
+++ b/logback-site/src/site/pages/news.html
@@ -33,9 +33,13 @@
<p>Added a new section in the documentation about <a
href="recipes/index.html">real-world inspired recipes</a>.</p>
- <p><code>PatternLayout</code> now supports
- compound conversion words of which <a
- href="manual/layouts.html#replace">"%replace"</a> is one example.
+ <p><code>PatternLayout</code> now supports compound conversion
+ words of which <a
+ href="manual/layouts.html#replace">"%replace"</a> is one
+ example. This change involved a significant re-write of the
+ pattern tokenizer, the pattern parser and the pattern
+ compiler. However, the changes should be backward compatible as far
+ as users are concerned.
</p>
<p>The <a href="manual/appenders.html#smtpTo"><span
diff --git a/pom.xml b/pom.xml
index 3d6af6d..b91736b 100755
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
<groupId>ch.qos.logback</groupId>
<artifactId>logback-parent</artifactId>
- <version>0.9.27-SNAPSHOT</version>
+ <version>0.9.27</version>
<packaging>pom</packaging>
<name>Logback-Parent</name>
-----------------------------------------------------------------------
Summary of changes:
logback-access/pom.xml | 2 +-
logback-classic/pom.xml | 2 +-
logback-core/pom.xml | 2 +-
logback-examples/pom.xml | 2 +-
logback-site/pom.xml | 2 +-
logback-site/src/site/pages/news.html | 10 +++++++---
pom.xml | 2 +-
7 files changed, 13 insertions(+), 9 deletions(-)
hooks/post-receive
--
Logback: the generic, reliable, fast and flexible logging framework.
1
0
Hello all,
I am happy to announce the release of logback version 0.9.27. Please
refer to the news page for precise details.
http://logback.qos.ch/news.html
You can download logback, including full source code, class files and
documentation on our download page, shown below.
http://logback.qos.ch/download.html
You can receive logback related announcements by subscribing to the
QOS.ch announce mailing list. To subscribe to QOS.ch announce list,
please visit the following URL.
http://www.qos.ch/mailman/listinfo/announce
Enjoy,
--
Ceki
1
0
[GIT] Logback: the generic, reliable, fast and flexible logging framework. branch, master, updated. v_0.9.25-53-g668e446
by git-noreply@pixie.qos.ch 22 Dec '10
by git-noreply@pixie.qos.ch 22 Dec '10
22 Dec '10
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Logback: the generic, reliable, fast and flexible logging framework.".
The branch, master has been updated
via 668e4464586c07ebe59c578406c3e7799508d46f (commit)
from 8f3f52105b1f95909cb48be721fe3046473b2a4b (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://git.qos.ch/gitweb/?p=logback.git;a=commit;h=668e4464586c07ebe59c5784…
http://github.com/ceki/logback/commit/668e4464586c07ebe59c578406c3e7799508d…
commit 668e4464586c07ebe59c578406c3e7799508d46f
Author: Ceki Gulcu <ceki(a)qos.ch>
Date: Wed Dec 22 22:50:31 2010 +0100
- doc improvements
- minor indentation changes
diff --git a/logback-core/src/main/java/ch/qos/logback/core/net/SMTPAppenderBase.java b/logback-core/src/main/java/ch/qos/logback/core/net/SMTPAppenderBase.java
index a835638..f3bb08c 100644
--- a/logback-core/src/main/java/ch/qos/logback/core/net/SMTPAppenderBase.java
+++ b/logback-core/src/main/java/ch/qos/logback/core/net/SMTPAppenderBase.java
@@ -59,18 +59,14 @@ import ch.qos.logback.core.util.OptionHelper;
*/
public abstract class SMTPAppenderBase<E> extends AppenderBase<E> {
- static InternetAddress[] EMPTY_IA_ARRAY = new InternetAddress[0];
+ static InternetAddress[] EMPTY_IA_ARRAY = new InternetAddress[0];
// ~ 14 days
static final int MAX_DELAY_BETWEEN_STATUS_MESSAGES = 1228800 * CoreConstants.MILLIS_IN_ONE_SECOND;
long lastTrackerStatusPrint = 0;
int delayBetweenStatusMessages = 300 * CoreConstants.MILLIS_IN_ONE_SECOND;
-
-
-
protected Layout<E> subjectLayout;
-
protected Layout<E> layout;
private List<PatternLayoutBase<E>> toPatternLayoutList = new ArrayList<PatternLayoutBase<E>>();
@@ -110,7 +106,7 @@ public abstract class SMTPAppenderBase<E> extends AppenderBase<E> {
*/
public void start() {
- if(cbTracker == null) {
+ if (cbTracker == null) {
cbTracker = new CyclicBufferTrackerImpl<E>();
}
@@ -189,15 +185,13 @@ public abstract class SMTPAppenderBase<E> extends AppenderBase<E> {
}
}
-
- if(isEventMarkedForBufferRemoval(eventObject)) {
+ // immediately remove the buffer if asked by the user
+ if (isEventMarkedForBufferRemoval(eventObject)) {
cbTracker.removeBuffer(key);
}
cbTracker.clearStaleBuffers(now);
-
-
if (lastTrackerStatusPrint + delayBetweenStatusMessages < now) {
addInfo("SMTPAppender [" + name + "] is tracking [" + cbTracker.size() + "] buffers");
lastTrackerStatusPrint = now;
@@ -268,14 +262,14 @@ public abstract class SMTPAppenderBase<E> extends AppenderBase<E> {
try {
PatternLayoutBase<E> emailPL = toPatternLayoutList.get(i);
String email = emailPL.doLayout(event);
- if(email == null || email.length() == 0) {
+ if (email == null || email.length() == 0) {
continue;
}
InternetAddress[] tmp = InternetAddress.parse(email, true);
// one <To> element should contain one email address
iaList.add(tmp[0]);
} catch (AddressException e) {
- addError("Could not parse email address for [" + toPatternLayoutList.get(i) + "] for event ["+event+"]", e);
+ addError("Could not parse email address for [" + toPatternLayoutList.get(i) + "] for event [" + event + "]", e);
return iaList;
}
}
@@ -325,12 +319,12 @@ public abstract class SMTPAppenderBase<E> extends AppenderBase<E> {
charsetEncoding);
}
- List<InternetAddress> destinationAddresses = parseAddress(lastEventObject);
- if(destinationAddresses.isEmpty()) {
- addInfo("Empty destination address. Aborting email transmission");
- return;
- }
- mimeMsg.setRecipients(Message.RecipientType.TO, destinationAddresses.toArray(EMPTY_IA_ARRAY));
+ List<InternetAddress> destinationAddresses = parseAddress(lastEventObject);
+ if (destinationAddresses.isEmpty()) {
+ addInfo("Empty destination address. Aborting email transmission");
+ return;
+ }
+ mimeMsg.setRecipients(Message.RecipientType.TO, destinationAddresses.toArray(EMPTY_IA_ARRAY));
String contentType = layout.getContentType();
@@ -352,8 +346,6 @@ public abstract class SMTPAppenderBase<E> extends AppenderBase<E> {
}
}
-
-
abstract protected void fillBuffer(CyclicBuffer<E> cb, StringBuffer sbuf);
/**
@@ -388,6 +380,7 @@ public abstract class SMTPAppenderBase<E> extends AppenderBase<E> {
/**
* Alias for smtpHost
+ *
* @param smtpHost
*/
public void setSMTPHost(String smtpHost) {
@@ -422,7 +415,7 @@ public abstract class SMTPAppenderBase<E> extends AppenderBase<E> {
* @param port
*/
public void setSMTPPort(int port) {
- setSmtpPort(port);
+ setSmtpPort(port);
}
/**
@@ -436,13 +429,16 @@ public abstract class SMTPAppenderBase<E> extends AppenderBase<E> {
/**
* Alias for {@link #getSmtpPort}
+ *
* @return
- */
+ */
public int getSMTPPort() {
return getSmtpPort();
}
+
/**
* See {@link #setSmtpPort}
+ *
* @return
*/
public int getSmtpPort() {
@@ -466,27 +462,27 @@ public abstract class SMTPAppenderBase<E> extends AppenderBase<E> {
}
public void addTo(String to) {
- if(to == null || to.length() == 0) {
- throw new IllegalArgumentException("Null or empty <to> property");
- }
- PatternLayoutBase plb = makeNewToPatternLayout(to.trim());
- plb.setContext(context);
- plb.start();
- this.toPatternLayoutList.add(plb);
+ if (to == null || to.length() == 0) {
+ throw new IllegalArgumentException("Null or empty <to> property");
+ }
+ PatternLayoutBase plb = makeNewToPatternLayout(to.trim());
+ plb.setContext(context);
+ plb.start();
+ this.toPatternLayoutList.add(plb);
}
abstract protected PatternLayoutBase<E> makeNewToPatternLayout(String toPattern);
- public List<String> getToAsListOfString() {
- List<String> toList = new ArrayList<String>();
- for(PatternLayoutBase plb: toPatternLayoutList) {
- toList.add(plb.getPattern());
- }
- return toList;
- }
+ public List<String> getToAsListOfString() {
+ List<String> toList = new ArrayList<String>();
+ for (PatternLayoutBase plb : toPatternLayoutList) {
+ toList.add(plb.getPattern());
+ }
+ return toList;
+ }
// for testing purpose only
- public Message getMessage() {
+ public Message getMessage() {
return mimeMsg;
}
diff --git a/logback-core/src/main/java/ch/qos/logback/core/pattern/ReplacingCompositeConverter.java b/logback-core/src/main/java/ch/qos/logback/core/pattern/ReplacingCompositeConverter.java
index 6542a44..40d1eae 100644
--- a/logback-core/src/main/java/ch/qos/logback/core/pattern/ReplacingCompositeConverter.java
+++ b/logback-core/src/main/java/ch/qos/logback/core/pattern/ReplacingCompositeConverter.java
@@ -40,9 +40,6 @@ public class ReplacingCompositeConverter<E> extends CompositeConverter<E> {
}
regex = optionList.get(0);
pattern = Pattern.compile(regex);
-
- //.matcher(this).replaceAll(replacement);
-
replacement = optionList.get(1);
super.start();
}
diff --git a/logback-core/src/main/java/ch/qos/logback/core/spi/CyclicBufferTracker.java b/logback-core/src/main/java/ch/qos/logback/core/spi/CyclicBufferTracker.java
index 0c9fe80..83cc39f 100644
--- a/logback-core/src/main/java/ch/qos/logback/core/spi/CyclicBufferTracker.java
+++ b/logback-core/src/main/java/ch/qos/logback/core/spi/CyclicBufferTracker.java
@@ -31,8 +31,6 @@ public interface CyclicBufferTracker<E> {
public int getBufferSize();
public void setBufferSize(int size);
-
-
public int getMaxNumberOfBuffers();
/**
diff --git a/logback-site/src/site/pages/manual/appenders.html b/logback-site/src/site/pages/manual/appenders.html
index c527c4f..a37f67c 100644
--- a/logback-site/src/site/pages/manual/appenders.html
+++ b/logback-site/src/site/pages/manual/appenders.html
@@ -1695,10 +1695,11 @@ public interface TriggeringPolicy<E> extends LifeCycle {
<tr>
<td><a name="smtpTo" href="#smtpTo"><b><span class="option">to</span></b></a></td>
<td><code>String</code></td>
- <td>The email address of the recipient as a pattern. The
- pattern is evaluated anew with the triggering event as input
- for each outgoing email. Multiple recipients can be specified
- by using several <code><to></code> elements.</td>
+ <td>The email address of the recipient as a
+ <em>pattern</em>. The pattern is evaluated anew with the
+ triggering event as input for each outgoing email. Multiple
+ recipients can be specified by using several
+ <code><to></code> elements.</td>
</tr>
<tr class="alt">
<td><b><span class="option">from</span></b></td>
@@ -1818,8 +1819,8 @@ public interface TriggeringPolicy<E> extends LifeCycle {
href="../xref/ch/qos/logback/core/spi/CyclicBufferTrackerImpl.html">CyclicBufferTrackerImpl</a>
will be automatically created. By default, this instance
will keep events in a cyclic buffer of size 256. You may
- change the size with the help of the <code>BufferSize</code>
- option.</p>
+ change the size with the help of the <span
+ class="option">bufferSize</span> option (see below).</p>
</td>
</tr>
@@ -2369,6 +2370,45 @@ logger.error(<b>notifyAdmin</b>,
host, greatly facilitating problem diagnosis.
</p>
+ <h4><a name= "bufferManagement" href="#bufferManagement">On buffer
+ management in very busy systems</a></h4>
+
+ <p>Internally, each distinct value returned by the disciminator
+ will cause the creation of a new cyclic buffer. However, at most
+ <span class="option">maxNumberOfBuffers</span> (by default 64)
+ will be maintained. Whenever the number of buffers rises above
+ <span class="option">maxNumberOfBuffers</span>, the least recently
+ updated buffer is automatically discarded. As a second safety
+ measure, any buffer which has not been updated in the last 30
+ minutes will be automatically discarded as well.</p>
+
+ <p>On systems serving a large number of transactions per minute,
+ allowing only a small number for <span
+ class="option">maxNumberOfBuffers</span> (by default 64) will
+ often cause the number of events in the outgoing email to be
+ unnecessarily small. Indeed, in the presence of a large number of
+ transactions, there will be more than one buffer associated with
+ the same transaction as buffers will be killed and re-born in
+ succession for the same discriminator value (or transaction). Note
+ that in even such very busy systems, the maximum number of cyclic
+ buffers is capped by <span
+ class="option">maxNumberOfBuffers</span>.
+ </p>
+
+ <p>To avoid such yo-yo effects, <code>SMTPAppender</code> will
+ release the buffer associated with a given discriminator key as
+ soon as it sees an event marked as "FINALIZE_SESSION". This will
+ cause the appropriate buffer to be discarded at the end of each
+ transaction. You can then safely increase the value of <span
+ class="option">maxNumberOfBuffers</span> to a larger value such as
+ 512 or 1024 without risking running out of memory.
+ </p>
+
+ <p>Thuse reare three distinct but complementary mechanisms working
+ together to manage cyclic buffers. They ensure that only relevant
+ buffers are kept alive at any given moment, even in very busy
+ systems.</p>
+
<!-- =========================================================== -->
<!-- =========================================================== -->
diff --git a/logback-site/src/site/pages/news.html b/logback-site/src/site/pages/news.html
index 55138ef..99f8e53 100644
--- a/logback-site/src/site/pages/news.html
+++ b/logback-site/src/site/pages/news.html
@@ -28,10 +28,14 @@
<hr width="80%" align="center" />
- <h3>xxx, 2010 - Release of version 0.9.27</h3>
+ <h3>December 22nd, 2010 - Release of version 0.9.27</h3>
- <p><code>PatternLayout</code> now supports compound conversion
- words of which <a href="manual/layouts.html#replace">"%replace"</a> is one example.
+ <p>Added a new section in the documentation about <a
+ href="recipes/index.html">real-world inspired recipes</a>.</p>
+
+ <p><code>PatternLayout</code> now supports
+ compound conversion words of which <a
+ href="manual/layouts.html#replace">"%replace"</a> is one example.
</p>
<p>The <a href="manual/appenders.html#smtpTo"><span
diff --git a/logback-site/src/site/pages/recipes/emailPerTransaction.html b/logback-site/src/site/pages/recipes/emailPerTransaction.html
index 5eb054b..a7ca756 100644
--- a/logback-site/src/site/pages/recipes/emailPerTransaction.html
+++ b/logback-site/src/site/pages/recipes/emailPerTransaction.html
@@ -21,7 +21,7 @@
</div>
<div id="content">
- <h2>Triggering an email containing the isoloated logs of selected
+ <h2>Triggering an email containing the isolated logs of selected
transactions</h2>
<p>Let Dave and Carol be software QA engineers working at a
@@ -86,7 +86,7 @@ import javax.servlet.http.HttpServletResponse;
public class PrimeAction extends Action {
Logger logger = LoggerFactory.getLogger(PrimeAction.class);
- Marker SMTP_TRIGGER = MarkerFactory.getMarker("SMTP_TRIGGER");
+ static Marker SMTP_TRIGGER = MarkerFactory.getMarker("SMTP_TRIGGER");
public ActionForward execute(ActionMapping actionMapping,
ActionForm actionForm, HttpServletRequest request,
@@ -302,7 +302,7 @@ MDC.put("txId", transactionId); </pre>
</layout>
<discriminator class="ch.qos.logback.classic.sift.MDCBasedDiscriminator">
- <key>uuid</key>
+ <key>txId</key>
<defaultValue>default</defaultValue>
</discriminator>
@@ -314,18 +314,131 @@ MDC.put("txId", transactionId); </pre>
(marker != null && marker.contains("SMTP_TRIGGER") )
</expression>
</evaluator>
+ </appender>
+
+ <root level="DEBUG">
+ <appender-ref ref="SMTP" />
+ </root>
+</configuration> </pre>
+
+ <p>If your particular SMTP server does not handle address tags,
+ you can still use them within the evaluator but remove them in
+ the recipient address with the help of the <a
+ href="../manual/layouts.html#replace">%replace</a> conversion
+ word. Here is the relevant configuraton snippet:</p>
+
+ <pre class="prettyprint source"><appender name="SMTP" class="ch.qos.logback.classic.net.SMTPAppender">
+ <to>%replace(%mdc{txEmail}){'\+log', ''}</to>
+ ...
+</appender></pre>
+
+ <p>This replaces any occurrence of the string "+log" within the
+ string returned by %mdc{txEmail} with the empty string,
+ effectively erasing +log from the recipient address.</p>
+
+ <h3>Buffer management in very busy systems</h3>
+
+ <p>The solution described so far provides an amazingly flexible
+ solution to the initial problem. Indeed, any QA-engineer at
+ Fooware.com, say Carol, can have the logs generated by requests
+ she makes to Buscrit sent to her automatically by email. All she
+ has to do is to suffix the user part in her email address with
+ "+log" when she registers with Buscrit.
+ </p>
+
+ <p>By default <code>SMTPAppender</code> will cap the number of
+ buffers it maintains to the value of the <span
+ class="option">maxNumberOfBuffers</span> option (64 by default)
+ and automatically discards buffers untouched for at least 30
+ minutes. While this approach will work nicely in a test
+ environment with few transactions, in a very busy production
+ system, these buffer management mechanims will cause Carol to
+ receive <a
+ href="../manual/appenders.html#bufferManagement">truncated log
+ buffers</a>. </p>
+
+ <p>To deal with this problem, we instruct SMTPAppender to discard
+ apprioate buffer at the end of each transaction. This is done by
+ logging an event marked as "FINALIZE_SESSION". Here is a modified
+ version of <code>PrimeAction</code> which marks the end of a
+ transaction with "FINALIZE_SESSION".
+ </p>
+
+ <pre class="prettyprint source">package ch.qos.logback.demo.prime;
+
+<b>import static ch.qos.logback.classic.ClassicConstants.FINALIZE_SESSION_MARKER;</b>
+
+public class PrimeAction extends Action {
+
+ Logger logger = LoggerFactory.getLogger(PrimeAction.class);
+ static Marker SMTP_TRIGGER = MarkerFactory.getMarker("SMTP_TRIGGER");
+ static {
+ // markers can hold references to other markers
+ <b>SMTP_TRIGGER.add(FINALIZE_SESSION_MARKER);</b>
+ }
+
+ public ActionForward execute(ActionMapping actionMapping, ... ) throws Exception {
+
+ Long number = form.getNumber();
+ try {
+ ...
+ } finally {
+ <b>logger.info(SMTP_TRIGGER, "Prime computation ended");</b>
+ MDC.put("txId", null); // clear txId asap to avoid accidental rebirth
+ }
+ }
+} </pre>
+
+
+ <p>Not that at the end of each transaction the appropriate buffer
+ is discarded, we can incrase the value of <span
+ class="option">maxNumberOfBuffers</span> as shown in the next
+ configuration file..
+ </p>
+
+ <pre class="prettyprint source"><configuration scan="true" scanPeriod="3 seconds">
+
+ <statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" />
+
+ <appender name="SMTP" class="ch.qos.logback.classic.net.SMTPAppender">
+ <SMTPHost>NAME_OF_SMTP_HOST</SMTPHost>
+ <to>%mdc{txEmail}</to>
+ <from></from>
+ <subject>Prime - %mdc{number}</subject>
+
+ <layout class="ch.qos.logback.classic.html.HTMLLayout">
+ <pattern>%date%level%logger{24}%msg</pattern>
+ </layout>
<discriminator class="ch.qos.logback.classic.sift.MDCBasedDiscriminator">
- <key>uuid</key>
+ <key>txId</key>
<defaultValue>default</defaultValue>
</discriminator>
- </appender>
+
+ <b><cyclicBufferTracker class="ch.qos.logback.core.spi.CyclicBufferTrackerImpl"></b>
+ <b><maxNumberOfBuffers>512</maxNumberOfBuffers></b>
+ <b></cyclicBufferTracker></b>
+
+ <evaluator class="ch.qos.logback.classic.boolex.JaninoEventEvaluator">
+ <expression>
+ (mdc != null &amp;&amp; mdc.get("txEmail") != null &amp;&amp;
+ ((String) mdc.get("txEmail")).contains("+log") )
+ &amp;&amp;
+ (marker != null && marker.contains("SMTP_TRIGGER") )
+ </expression>
+ </evaluator>
<root level="DEBUG">
<appender-ref ref="SMTP" />
</root>
</configuration> </pre>
- <script src="../templates/footer.js" type="text/javascript"></script>
+
+ <p>With these latest changes, we can selectively send isolated
+ logs for selected transactions to the concerned recipient, even in
+ very busy production systems without excessive memory consumption.
+ </p>
+
+ <script src="../templates/footer.js" type="text/javascript"></script>
</div>
</body>
</html>
-----------------------------------------------------------------------
Summary of changes:
.../ch/qos/logback/core/net/SMTPAppenderBase.java | 70 +++++------
.../core/pattern/ReplacingCompositeConverter.java | 3 -
.../qos/logback/core/spi/CyclicBufferTracker.java | 2 -
logback-site/src/site/pages/manual/appenders.html | 52 +++++++-
logback-site/src/site/pages/news.html | 10 +-
.../site/pages/recipes/emailPerTransaction.html | 125 +++++++++++++++++++-
6 files changed, 205 insertions(+), 57 deletions(-)
hooks/post-receive
--
Logback: the generic, reliable, fast and flexible logging framework.
1
0
[GIT] Logback: the generic, reliable, fast and flexible logging framework. branch, master, updated. v_0.9.25-52-g8f3f521
by git-noreply@pixie.qos.ch 22 Dec '10
by git-noreply@pixie.qos.ch 22 Dec '10
22 Dec '10
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Logback: the generic, reliable, fast and flexible logging framework.".
The branch, master has been updated
via 8f3f52105b1f95909cb48be721fe3046473b2a4b (commit)
from 20c3ef5ec9336719396f67866630e3a5807afa34 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://git.qos.ch/gitweb/?p=logback.git;a=commit;h=8f3f52105b1f95909cb48be7…
http://github.com/ceki/logback/commit/8f3f52105b1f95909cb48be721fe3046473b2…
commit 8f3f52105b1f95909cb48be721fe3046473b2a4b
Author: Ceki Gulcu <ceki(a)qos.ch>
Date: Wed Dec 22 18:12:51 2010 +0100
- Improved testing of CyclicBufferTracker. Added support for immediate
removal of buffer if requested by the user.
diff --git a/logback-access/src/main/java/ch/qos/logback/access/net/SMTPAppender.java b/logback-access/src/main/java/ch/qos/logback/access/net/SMTPAppender.java
index 4584e4f..7b1d60c 100644
--- a/logback-access/src/main/java/ch/qos/logback/access/net/SMTPAppender.java
+++ b/logback-access/src/main/java/ch/qos/logback/access/net/SMTPAppender.java
@@ -63,7 +63,7 @@ public class SMTPAppender extends SMTPAppenderBase<AccessEvent> {
protected void fillBuffer(CyclicBuffer<AccessEvent> cb, StringBuffer sbuf) {
int len = cb.length();
for (int i = 0; i < len; i++) {
- // sbuf.append(MimeUtility.encodeText(layout.format(cb.get())));
+ // sbuf.append(MimeUtility.encodeText(layout.format(cb.getOrCreate())));
AccessEvent event = (AccessEvent) cb.get();
sbuf.append(layout.doLayout(event));
}
@@ -86,5 +86,8 @@ public class SMTPAppender extends SMTPAppenderBase<AccessEvent> {
return pl;
}
+ protected boolean isEventMarkedForBufferRemoval(AccessEvent eventObject) {
+ return false;
+ }
}
diff --git a/logback-classic/src/main/java/ch/qos/logback/classic/ClassicConstants.java b/logback-classic/src/main/java/ch/qos/logback/classic/ClassicConstants.java
index 193a31d..2972d2d 100644
--- a/logback-classic/src/main/java/ch/qos/logback/classic/ClassicConstants.java
+++ b/logback-classic/src/main/java/ch/qos/logback/classic/ClassicConstants.java
@@ -13,6 +13,9 @@
*/
package ch.qos.logback.classic;
+import org.slf4j.Marker;
+import org.slf4j.MarkerFactory;
+
public class ClassicConstants {
static public final String USER_MDC_KEY = "user";
@@ -41,4 +44,6 @@ public class ClassicConstants {
public final static String REQUEST_X_FORWARDED_FOR = "req.xForwardedFor";
public final static String GAFFER_CONFIGURATOR_FQCN = "ch.qos.logback.classic.gaffer.GafferConfigurator";
+
+ public final static Marker FINALIZE_SESSION_MARKER = MarkerFactory.getMarker("FINALIZE_SESSION");
}
diff --git a/logback-classic/src/main/java/ch/qos/logback/classic/net/SMTPAppender.java b/logback-classic/src/main/java/ch/qos/logback/classic/net/SMTPAppender.java
index 262bd91..faa1580 100644
--- a/logback-classic/src/main/java/ch/qos/logback/classic/net/SMTPAppender.java
+++ b/logback-classic/src/main/java/ch/qos/logback/classic/net/SMTPAppender.java
@@ -13,6 +13,7 @@
*/
package ch.qos.logback.classic.net;
+import ch.qos.logback.classic.ClassicConstants;
import ch.qos.logback.classic.PatternLayout;
import ch.qos.logback.classic.boolex.OnErrorEvaluator;
import ch.qos.logback.classic.spi.ILoggingEvent;
@@ -20,6 +21,7 @@ import ch.qos.logback.core.Layout;
import ch.qos.logback.core.boolex.EventEvaluator;
import ch.qos.logback.core.helpers.CyclicBuffer;
import ch.qos.logback.core.net.SMTPAppenderBase;
+import org.slf4j.Marker;
/**
* Send an e-mail when a specific logging event occurs, typically on errors or
@@ -86,6 +88,15 @@ public class SMTPAppender extends SMTPAppenderBase<ILoggingEvent> {
}
}
+ protected boolean isEventMarkedForBufferRemoval(ILoggingEvent eventObject) {
+ Marker marker = eventObject.getMarker();
+ if(marker == null)
+ return false;
+
+ return marker.contains(ClassicConstants.FINALIZE_SESSION_MARKER);
+ }
+
+
@Override
protected Layout<ILoggingEvent> makeSubjectLayout(String subjectStr) {
if(subjectStr == null) {
@@ -102,6 +113,7 @@ public class SMTPAppender extends SMTPAppenderBase<ILoggingEvent> {
return pl;
}
+
protected PatternLayout makeNewToPatternLayout(String toPattern) {
PatternLayout pl = new PatternLayout();
pl.setPattern(toPattern+"%nopex");
diff --git a/logback-classic/src/test/java/ch/qos/logback/classic/net/DilutedSMTPAppenderTest.java b/logback-classic/src/test/java/ch/qos/logback/classic/net/DilutedSMTPAppenderTest.java
index 53bbc0c..abb5102 100644
--- a/logback-classic/src/test/java/ch/qos/logback/classic/net/DilutedSMTPAppenderTest.java
+++ b/logback-classic/src/test/java/ch/qos/logback/classic/net/DilutedSMTPAppenderTest.java
@@ -52,7 +52,7 @@ public class DilutedSMTPAppenderTest {
appender.addTo("sebastien.nospam(a)qos.ch");
appender.start();
cbTracker = appender.getCyclicBufferTracker();
- cb = cbTracker.get("", 0);
+ cb = cbTracker.getOrCreate("", 0);
}
diff --git a/logback-core/src/main/java/ch/qos/logback/core/net/SMTPAppenderBase.java b/logback-core/src/main/java/ch/qos/logback/core/net/SMTPAppenderBase.java
index 01f9dbe..a835638 100644
--- a/logback-core/src/main/java/ch/qos/logback/core/net/SMTPAppenderBase.java
+++ b/logback-core/src/main/java/ch/qos/logback/core/net/SMTPAppenderBase.java
@@ -175,7 +175,7 @@ public abstract class SMTPAppenderBase<E> extends AppenderBase<E> {
String key = discriminator.getDiscriminatingValue(eventObject);
long now = System.currentTimeMillis();
- CyclicBuffer<E> cb = cbTracker.get(key, now);
+ CyclicBuffer<E> cb = cbTracker.getOrCreate(key, now);
subAppend(cb, eventObject);
try {
@@ -188,7 +188,16 @@ public abstract class SMTPAppenderBase<E> extends AppenderBase<E> {
addError("SMTPAppender's EventEvaluator threw an Exception-", ex);
}
}
+
+
+ if(isEventMarkedForBufferRemoval(eventObject)) {
+ cbTracker.removeBuffer(key);
+ }
+
cbTracker.clearStaleBuffers(now);
+
+
+
if (lastTrackerStatusPrint + delayBetweenStatusMessages < now) {
addInfo("SMTPAppender [" + name + "] is tracking [" + cbTracker.size() + "] buffers");
lastTrackerStatusPrint = now;
@@ -199,6 +208,8 @@ public abstract class SMTPAppenderBase<E> extends AppenderBase<E> {
}
}
+ abstract protected boolean isEventMarkedForBufferRemoval(E eventObject);
+
abstract protected void subAppend(CyclicBuffer<E> cb, E eventObject);
/**
diff --git a/logback-core/src/main/java/ch/qos/logback/core/rolling/TimeBasedFileNamingAndTriggeringPolicyBase.java b/logback-core/src/main/java/ch/qos/logback/core/rolling/TimeBasedFileNamingAndTriggeringPolicyBase.java
index d5d4129..5328db7 100644
--- a/logback-core/src/main/java/ch/qos/logback/core/rolling/TimeBasedFileNamingAndTriggeringPolicyBase.java
+++ b/logback-core/src/main/java/ch/qos/logback/core/rolling/TimeBasedFileNamingAndTriggeringPolicyBase.java
@@ -30,9 +30,7 @@ abstract public class TimeBasedFileNamingAndTriggeringPolicyBase<E> extends
protected String elapsedPeriodsFileName;
protected RollingCalendar rc;
- protected long currentTime;
- // indicate whether the time has been forced or not
- protected boolean isTimeForced = false;
+ protected long currentTime = -1;
protected Date dateInCurrentPeriod = null;
protected long nextCheck;
@@ -102,12 +100,11 @@ abstract public class TimeBasedFileNamingAndTriggeringPolicyBase<E> extends
public void setCurrentTime(long timeInMillis) {
currentTime = timeInMillis;
- isTimeForced = true;
}
public long getCurrentTime() {
// if time is forced return the time set by user
- if (isTimeForced) {
+ if (currentTime >= 0) {
return currentTime;
} else {
return System.currentTimeMillis();
diff --git a/logback-core/src/main/java/ch/qos/logback/core/spi/CyclicBufferTracker.java b/logback-core/src/main/java/ch/qos/logback/core/spi/CyclicBufferTracker.java
index 4f1ab45..0c9fe80 100644
--- a/logback-core/src/main/java/ch/qos/logback/core/spi/CyclicBufferTracker.java
+++ b/logback-core/src/main/java/ch/qos/logback/core/spi/CyclicBufferTracker.java
@@ -54,7 +54,12 @@ public interface CyclicBufferTracker<E> {
* @param timestamp
* @return
*/
- CyclicBuffer<E> get(String key, long timestamp);
+ CyclicBuffer<E> getOrCreate(String key, long timestamp);
+
+ /**
+ * Remove a cyclic buffer identified by its key.
+ */
+ void removeBuffer(String key);
/**
* Clear (and detach) buffers which are stale.
diff --git a/logback-core/src/main/java/ch/qos/logback/core/spi/CyclicBufferTrackerImpl.java b/logback-core/src/main/java/ch/qos/logback/core/spi/CyclicBufferTrackerImpl.java
index a32a934..be788b1 100644
--- a/logback-core/src/main/java/ch/qos/logback/core/spi/CyclicBufferTrackerImpl.java
+++ b/logback-core/src/main/java/ch/qos/logback/core/spi/CyclicBufferTrackerImpl.java
@@ -13,7 +13,6 @@
*/
package ch.qos.logback.core.spi;
-import ch.qos.logback.core.Appender;
import ch.qos.logback.core.CoreConstants;
import ch.qos.logback.core.helpers.CyclicBuffer;
@@ -65,7 +64,7 @@ public class CyclicBufferTrackerImpl<E> implements CyclicBufferTracker<E> {
this.maxNumBuffers = maxNumBuffers;
}
- public CyclicBuffer<E> get(String key, long timestamp) {
+ public CyclicBuffer<E> getOrCreate(String key, long timestamp) {
Entry existing = map.get(key);
if (existing == null) {
CyclicBuffer<E> cb = processNewEntry(key, timestamp);
@@ -77,12 +76,25 @@ public class CyclicBufferTrackerImpl<E> implements CyclicBufferTracker<E> {
}
}
+ public void removeBuffer(String key) {
+ Entry existing = map.get(key);
+ if (existing != null) {
+ bufferCount--;
+ map.remove(key);
+ unlink(existing);
+ CyclicBuffer<E> cb = existing.value;
+ if(cb != null) {
+ cb.clear();
+ }
+ }
+ }
+
private CyclicBuffer<E> processNewEntry(String key, long timestamp) {
CyclicBuffer<E> cb = new CyclicBuffer<E>(bufferSize);
Entry entry = new Entry(key, cb, timestamp);
map.put(key, entry);
bufferCount++;
- rearrangeTailLinks(entry);
+ linkBeforeTail(entry);
if (bufferCount >= maxNumBuffers) {
removeHead();
}
@@ -101,11 +113,11 @@ public class CyclicBufferTrackerImpl<E> implements CyclicBufferTracker<E> {
}
private void moveToTail(Entry e) {
- rearrangePreexistingLinks(e);
- rearrangeTailLinks(e);
+ unlink(e);
+ linkBeforeTail(e);
}
- private void rearrangePreexistingLinks(Entry e) {
+ private void unlink(Entry e) {
if (e.prev != null) {
e.prev.next = e.next;
}
@@ -125,8 +137,6 @@ public class CyclicBufferTrackerImpl<E> implements CyclicBufferTracker<E> {
lastCheck = now;
while (head.value != null && isEntryStale(head, now)) {
- CyclicBuffer<E> cb = head.value;
- cb.clear();
removeHead();
}
}
@@ -149,7 +159,7 @@ public class CyclicBufferTrackerImpl<E> implements CyclicBufferTracker<E> {
return result;
}
- private void rearrangeTailLinks(Entry e) {
+ private void linkBeforeTail(Entry e) {
if (head == tail) {
head = e;
}
diff --git a/logback-core/src/test/java/ch/qos/logback/core/spi/CyclicBufferTrackerImplTest.java b/logback-core/src/test/java/ch/qos/logback/core/spi/CyclicBufferTrackerImplTest.java
index 6b9ee28..2b64b88 100644
--- a/logback-core/src/test/java/ch/qos/logback/core/spi/CyclicBufferTrackerImplTest.java
+++ b/logback-core/src/test/java/ch/qos/logback/core/spi/CyclicBufferTrackerImplTest.java
@@ -22,25 +22,45 @@ public class CyclicBufferTrackerImplTest {
long now = 3000;
tracker.clearStaleBuffers(now);
assertEquals(0, tracker.keyList().size());
+ assertEquals(0, tracker.bufferCount);
}
- @Test
+ @Test
public void empty1() {
long now = 3000;
- assertNotNull(tracker.get(key, now++));
- now += CyclicBufferTracker.THRESHOLD+1000;
+ assertNotNull(tracker.getOrCreate(key, now++));
+ now += CyclicBufferTracker.THRESHOLD + 1000;
tracker.clearStaleBuffers(now);
assertEquals(0, tracker.keyList().size());
- assertNotNull(tracker.get(key, now++));
+ assertEquals(0, tracker.bufferCount);
+
+ assertNotNull(tracker.getOrCreate(key, now++));
}
@Test
public void smoke() {
long now = 3000;
- CyclicBuffer<Object> cb = tracker.get(key, now);
- assertEquals(cb, tracker.get(key, now++));
- now += AppenderTrackerImpl.THRESHOLD+1000;
+ CyclicBuffer<Object> cb = tracker.getOrCreate(key, now);
+ assertEquals(cb, tracker.getOrCreate(key, now++));
+ now += AppenderTrackerImpl.THRESHOLD + 1000;
tracker.clearStaleBuffers(now);
assertEquals(0, tracker.keyList().size());
+ assertEquals(0, tracker.bufferCount);
}
+
+ @Test
+ public void destroy() {
+ long now = 3000;
+ CyclicBuffer<Object> cb = tracker.getOrCreate(key, now);
+ cb.add(new Object());
+ assertEquals(1, cb.length());
+ tracker.removeBuffer(key);
+ assertEquals(0, tracker.keyList().size());
+ assertEquals(0, tracker.bufferCount);
+ assertEquals(0, cb.length());
+ }
+
+
+
+
}
diff --git a/logback-core/src/test/java/ch/qos/logback/core/spi/CyclicBufferTrackerSimulator.java b/logback-core/src/test/java/ch/qos/logback/core/spi/CyclicBufferTrackerSimulator.java
index 3d3e000..ff9dd98 100644
--- a/logback-core/src/test/java/ch/qos/logback/core/spi/CyclicBufferTrackerSimulator.java
+++ b/logback-core/src/test/java/ch/qos/logback/core/spi/CyclicBufferTrackerSimulator.java
@@ -20,14 +20,16 @@ import java.util.*;
*/
public class CyclicBufferTrackerSimulator {
- CyclicBufferTrackerImpl<Object> realAppenderTracker = new CyclicBufferTrackerImpl<Object>();
- CyclicBufferTrackerImpl t_appenderTracker = new CyclicBufferTrackerImpl();
+ CyclicBufferTrackerImpl<Object> realCBTracker = new CyclicBufferTrackerImpl<Object>();
+ CyclicBufferTracker_TImpl<Object> t_CBTracker = new CyclicBufferTracker_TImpl<Object>();
List<SimulationEvent> scenario = new ArrayList<SimulationEvent>();
List<String> keySpace = new ArrayList<String>();
int maxTimestampInc;
Random randomKeyGen = new Random(100);
- Random random = new Random(11234);
+ Random simulatorRandom = new Random(11234);
+
+ int deleteToInsertRatio = 10;
CyclicBufferTrackerSimulator(int keySpaceLen, int maxTimestampInc) {
this.maxTimestampInc = maxTimestampInc;
@@ -35,7 +37,7 @@ public class CyclicBufferTrackerSimulator {
for (int i = 0; i < keySpaceLen; i++) {
String k = getRandomKeyStr();
if (checkMap.containsKey(k)) {
- System.out.println("random key collision occured");
+ System.out.println("random key collision occurred");
k += "" + i;
}
keySpace.add(k);
@@ -54,10 +56,15 @@ public class CyclicBufferTrackerSimulator {
long timestamp = 30000;
int keySpaceLen = keySpace.size();
for (int i = 0; i < simLen; i++) {
- int index = random.nextInt(keySpaceLen);
- timestamp += random.nextInt(maxTimestampInc);
+ int index = simulatorRandom.nextInt(keySpaceLen);
+ timestamp += simulatorRandom.nextInt(maxTimestampInc);
+ EventType eventType = EventType.INSERT;
+ if (simulatorRandom.nextInt(deleteToInsertRatio) == 0) {
+ eventType = EventType.DELETE;
+ }
+
String key = keySpace.get(index);
- scenario.add(new SimulationEvent(key, timestamp));
+ scenario.add(new SimulationEvent(eventType, key, timestamp));
}
}
@@ -72,23 +79,36 @@ public class CyclicBufferTrackerSimulator {
CyclicBufferTracker<Object> tracker) {
String key = simulationEvent.key;
long timestamp = simulationEvent.timestamp;
- tracker.get(key, timestamp);
+ EventType eventType = simulationEvent.eventType;
+ switch (eventType) {
+ case INSERT:
+ tracker.getOrCreate(key, timestamp);
+ break;
+ case DELETE:
+ tracker.removeBuffer(key);
+ break;
+ }
}
public void simulate() {
for (SimulationEvent simeEvent : scenario) {
- play(simeEvent, realAppenderTracker);
- play(simeEvent, t_appenderTracker);
+ play(simeEvent, realCBTracker);
+ play(simeEvent, t_CBTracker);
}
}
// =========================================================================
+ enum EventType {
+ INSERT, DELETE;
+ }
class SimulationEvent {
final public String key;
final public long timestamp;
+ final EventType eventType;
- public SimulationEvent(String key, long timestamp) {
+ public SimulationEvent(EventType eventType, String key, long timestamp) {
+ this.eventType = eventType;
this.key = key;
this.timestamp = timestamp;
}
diff --git a/logback-core/src/test/java/ch/qos/logback/core/spi/CyclicBufferTracker_TImpl.java b/logback-core/src/test/java/ch/qos/logback/core/spi/CyclicBufferTracker_TImpl.java
index 553104d..1d564a5 100644
--- a/logback-core/src/test/java/ch/qos/logback/core/spi/CyclicBufferTracker_TImpl.java
+++ b/logback-core/src/test/java/ch/qos/logback/core/spi/CyclicBufferTracker_TImpl.java
@@ -16,8 +16,6 @@ public class CyclicBufferTracker_TImpl<E> implements CyclicBufferTracker<E> {
int bufferSize = DEFAULT_BUFFER_SIZE;
int maxNumBuffers = DEFAULT_NUMBER_OF_BUFFERS;
- int bufferCount = 0;
-
List<TEntry> entryList = new LinkedList<TEntry>();
long lastCheck = 0;
@@ -47,12 +45,27 @@ public class CyclicBufferTracker_TImpl<E> implements CyclicBufferTracker<E> {
return null;
}
- public CyclicBuffer<E> get(String key, long timestamp) {
+ List<String> keyList() {
+ Collections.sort(entryList);
+
+ List<String> result = new LinkedList<String>();
+ for (int i = 0; i < entryList.size(); i++) {
+ TEntry te = entryList.get(i);
+ result.add(te.key);
+ }
+ return result;
+ }
+
+
+ public CyclicBuffer<E> getOrCreate(String key, long timestamp) {
TEntry te = getEntry(key);
if (te == null) {
CyclicBuffer<E> cb = new CyclicBuffer<E>(bufferSize);
te = new TEntry<E>(key, cb, timestamp);
entryList.add(te);
+ if (entryList.size() >= maxNumBuffers) {
+ entryList.remove(0);
+ }
return cb;
} else {
te.timestamp = timestamp;
@@ -62,6 +75,16 @@ public class CyclicBufferTracker_TImpl<E> implements CyclicBufferTracker<E> {
}
+ public void removeBuffer(String k) {
+ for (int i = 0; i < entryList.size(); i++) {
+ TEntry te = entryList.get(i);
+ if (te.key.equals(k)) {
+ entryList.remove(i);
+ return;
+ }
+ }
+ }
+
final private boolean isEntryStale(TEntry entry, long now) {
return ((entry.timestamp + THRESHOLD) < now);
}
diff --git a/logback-core/src/test/java/ch/qos/logback/core/spi/ScenarioBasedCyclicBufferTrackerTest.java b/logback-core/src/test/java/ch/qos/logback/core/spi/ScenarioBasedCyclicBufferTrackerTest.java
index e48e4df..3fe7abd 100644
--- a/logback-core/src/test/java/ch/qos/logback/core/spi/ScenarioBasedCyclicBufferTrackerTest.java
+++ b/logback-core/src/test/java/ch/qos/logback/core/spi/ScenarioBasedCyclicBufferTrackerTest.java
@@ -26,9 +26,9 @@ public class ScenarioBasedCyclicBufferTrackerTest {
CyclicBufferTrackerSimulator simulator;
- void verify() {
- CyclicBufferTrackerImpl<Object> at = simulator.realAppenderTracker;
- CyclicBufferTrackerImpl<Object> t_at = simulator.t_appenderTracker;
+ void verify() {
+ CyclicBufferTrackerImpl<Object> at = simulator.realCBTracker;
+ CyclicBufferTracker_TImpl<Object> t_at = simulator.t_CBTracker;
assertEquals(t_at.keyList(), at.keyList());
}
@@ -48,7 +48,7 @@ public class ScenarioBasedCyclicBufferTrackerTest {
verify();
}
- @Test
+ @Test
public void longTest() {
simulator = new CyclicBufferTrackerSimulator(128, CyclicBufferTracker.THRESHOLD / 2);
simulator.buildScenario(200000);
diff --git a/logback-site/src/site/pages/recipes/emailPerTransaction.html b/logback-site/src/site/pages/recipes/emailPerTransaction.html
index 9573605..5eb054b 100644
--- a/logback-site/src/site/pages/recipes/emailPerTransaction.html
+++ b/logback-site/src/site/pages/recipes/emailPerTransaction.html
@@ -170,7 +170,7 @@ public class PrimeAction extends Action {
<p>To isolate a given transaction, there must first be a way to
distinguish it from other transactions. Typically this would be
accomplished by putting the unique identifier of the transaction
- into the the MDC.
+ into the MDC.
</p>
<pre class="prettyprint source">String transactionId = ...; // extract id from transaction
@@ -236,8 +236,12 @@ MDC.put("txId", transactionId); </pre>
<b><key>txId</key></b>
<b><defaultValue>default</defaultValue></b>
<b></discriminator></b>
+ </appender>
- </appender> </pre>
+ <root level="DEBUG">
+ <appender-ref ref="SMTP" />
+ </root>
+</configuration> </pre>
<p>After starting the logback-demo web-application with the above
configuration file (with <span class="option">smtpHost</span> and
@@ -315,8 +319,12 @@ MDC.put("txId", transactionId); </pre>
<key>uuid</key>
<defaultValue>default</defaultValue>
</discriminator>
+ </appender>
- </appender> </pre>
+ <root level="DEBUG">
+ <appender-ref ref="SMTP" />
+ </root>
+</configuration> </pre>
<script src="../templates/footer.js" type="text/javascript"></script>
</div>
</body>
-----------------------------------------------------------------------
Summary of changes:
.../ch/qos/logback/access/net/SMTPAppender.java | 5 ++-
.../ch/qos/logback/classic/ClassicConstants.java | 5 ++
.../ch/qos/logback/classic/net/SMTPAppender.java | 12 ++++++
.../classic/net/DilutedSMTPAppenderTest.java | 2 +-
.../ch/qos/logback/core/net/SMTPAppenderBase.java | 13 ++++++-
...TimeBasedFileNamingAndTriggeringPolicyBase.java | 7 +--
.../qos/logback/core/spi/CyclicBufferTracker.java | 7 +++-
.../logback/core/spi/CyclicBufferTrackerImpl.java | 28 +++++++++----
.../core/spi/CyclicBufferTrackerImplTest.java | 34 +++++++++++++---
.../core/spi/CyclicBufferTrackerSimulator.java | 42 ++++++++++++++-----
.../core/spi/CyclicBufferTracker_TImpl.java | 29 ++++++++++++-
.../spi/ScenarioBasedCyclicBufferTrackerTest.java | 8 ++--
.../site/pages/recipes/emailPerTransaction.html | 14 +++++-
13 files changed, 160 insertions(+), 46 deletions(-)
hooks/post-receive
--
Logback: the generic, reliable, fast and flexible logging framework.
1
0
[GIT] Logback: the generic, reliable, fast and flexible logging framework. branch, master, updated. v_0.9.25-51-g20c3ef5
by git-noreply@pixie.qos.ch 21 Dec '10
by git-noreply@pixie.qos.ch 21 Dec '10
21 Dec '10
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Logback: the generic, reliable, fast and flexible logging framework.".
The branch, master has been updated
via 20c3ef5ec9336719396f67866630e3a5807afa34 (commit)
from 072bbaef8e8d0508e1660cc5d49b3e8c7112e881 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://git.qos.ch/gitweb/?p=logback.git;a=commit;h=20c3ef5ec9336719396f6786…
http://github.com/ceki/logback/commit/20c3ef5ec9336719396f67866630e3a5807af…
commit 20c3ef5ec9336719396f67866630e3a5807afa34
Author: Ceki Gulcu <ceki(a)qos.ch>
Date: Tue Dec 21 22:58:57 2010 +0100
more edits
diff --git a/logback-site/src/site/pages/recipes/emailPerTransaction.html b/logback-site/src/site/pages/recipes/emailPerTransaction.html
index a13a167..9573605 100644
--- a/logback-site/src/site/pages/recipes/emailPerTransaction.html
+++ b/logback-site/src/site/pages/recipes/emailPerTransaction.html
@@ -133,10 +133,10 @@ public class PrimeAction extends Action {
<statusListener class="ch.qos.logback.core.status.OnConsoleStatusListener" />
<appender name="SMTP" class="ch.qos.logback.classic.net.SMTPAppender">
- <SMTPHost>NAME_OF_SMTP_HOST</SMTPHost>
+ <smtpHost>NAME_OF_SMTP_HOST</smtpHost>
<to>...</to>
<from>...</from>
- <subject>Prime - %mdc{number}</subject>
+ <subject>Prime - %mdc{number} by %mdc{userid} </subject>
<layout class="ch.qos.logback.classic.html.HTMLLayout">
<pattern>%date%level%logger{24}%msg</pattern>
</layout>
@@ -164,9 +164,50 @@ public class PrimeAction extends Action {
transactions. With a little effort, we can actually seperate events
belonging to different transactions so that the outgoing email
triggeed at the end of the transaction contains logs from that
- transaction and only that one.
+ transaction and only that transaction.
</p>
+ <p>To isolate a given transaction, there must first be a way to
+ distinguish it from other transactions. Typically this would be
+ accomplished by putting the unique identifier of the transaction
+ into the the MDC.
+ </p>
+
+ <pre class="prettyprint source">String transactionId = ...; // extract id from transaction
+MDC.put("txId", transactionId); </pre>
+
+ <p>In the <a
+ href="http://logback-demo.qos.ch/xref/ch/qos/logback/demo/UserServletFilter.html"><code>UserServletFilter</code></a>
+ class, this is done by retreiving the id of the session and putting
+ it into the MDC under the key "txId".</p>
+
+
+ <pre class="prettyprint source">public class UserServletFilter implements Filter {
+
+ public void doFilter(ServletRequest request, ServletResponse response,
+ FilterChain chain) throws IOException, ServletException {
+
+ HttpServletRequest req = (HttpServletRequest) request;
+ HttpSession session = req.getSession();
+ MDC.put("txId", session.getId());
+ ...
+ try {
+ // invoke subsequent filters
+ chain.doFilter(request, response);
+ } finally {
+ // always clear the MDC at the end of the request
+ MDC.clear();
+ }
+ }
+}</pre>
+
+
+ <p>By setting an appropriate discriminator in SMTPAppender, you can
+ can scatter incoming events into different buffers according to the
+ value returned by the discriminator. Given that each request session
+ is placed under the MDC key "txId", we can use an MDC-based
+ discriminator to isolate the logs generated by each transaction.
+ </p>
<pre class="prettyprint source"><configuration scan="true" scanPeriod="3 seconds">
@@ -174,33 +215,73 @@ public class PrimeAction extends Action {
<appender name="SMTP" class="ch.qos.logback.classic.net.SMTPAppender">
<smtpHost>NAME_OF_SMTP_HOST</smtpHost>
+ <to>...</to>
+ <from>...</from>
+
+ <smtpHost>NAME_OF_SMTP_HOST</smtpHost>
<to>name(a)some.smtp.host</to>
<from>testing@...</from>
- <subject>Prime - %mdc{number}</subject>
+ <subject>Prime - %mdc{number} by %mdc{userid} </subject>
<layout class="ch.qos.logback.classic.html.HTMLLayout">
<pattern>%date%level%logger{24}%msg</pattern>
</layout>
- <discriminator class="ch.qos.logback.classic.sift.MDCBasedDiscriminator">
- <key>uuid</key>
- <defaultValue>default</defaultValue>
- </discriminator>
-
<evaluator class="ch.qos.logback.classic.boolex.JaninoEventEvaluator">
<expression>
marker != null && marker.contains("SMTP_TRIGGER")
</expression>
</evaluator>
- <discriminator class="ch.qos.logback.classic.sift.MDCBasedDiscriminator">
- <key>uuid</key>
- <defaultValue>default</defaultValue>
- </discriminator>
+ <b><discriminator class="ch.qos.logback.classic.sift.MDCBasedDiscriminator"></b>
+ <b><key>txId</key></b>
+ <b><defaultValue>default</defaultValue></b>
+ <b></discriminator></b>
</appender> </pre>
+
+ <p>After starting the logback-demo web-application with the above
+ configuration file (with <span class="option">smtpHost</span> and
+ <span class="option">to</span> options adapted for my environment)
+ on localhost and then visiting the <a
+ href="http://localhost:8070/logback-demo/prime.jsp">Prime
+ number</a> page to factoize the number 123, I received the
+ following email:
+ </p>
+
+ <img src="images/factorEmail0.png" alt="selective email0"/>
+ <p>Note that the above email contains the logs generated by the
+ factorization of the number 123, without log pollution from any
+ other "transaction".
+ </p>
- <h3>Selective triggering & Transaction isolation</h3>
+ <h3>Selective triggering & recipient addressing with transaction isolation</h3>
+
+ <p>In a real world scenario, receiving isolated transactions is not
+ enough. You would need to trigger outgoing emails only for certain
+ users, typically QA engineers such as Dave and Carol. Moreover, you
+ would want the emails generated by transaction made by Carol to
+ Carol's mailbox and those generated by Dave to Dave's mailbox.</p>
+
+ <p>Selective triggering and addressing are two distinct
+ problems. Depending on the exact circumstances, there are many ways
+ of tackling these two issues. However, for the sake of simplicity,
+ let us assume that the SMTP server at Fooware.com accepts <a
+ href="http://en.wikipedia.org/wiki/Email_address#Address_tags">address
+ tags</a>. Such an SMTP server treats an incoming message sent to
+ username+xyz(a)fooware.com as if it were addressed to
+ username(a)fooware.com, effectively stripping the +xyz part.</p>
+
+ <p>Let us further assume that we can somehow extract the email
+ address of the user from the contents of her transaction, via a
+ database lookup or perhaps some other means. The extracted email
+ addressed is placed into the MDC under the key "txEmail".
+ </p>
+
+ <p>Upon a logging event marked as SMTP_TRIGGER, the following
+ confugration file will trigger an email message addressed to the
+ value of "%mdc{txEmail}" but only if it contains the string "+log".
+ </p>
<pre class="prettyprint source"><configuration scan="true" scanPeriod="3 seconds">
@@ -208,7 +289,7 @@ public class PrimeAction extends Action {
<appender name="SMTP" class="ch.qos.logback.classic.net.SMTPAppender">
<SMTPHost>NAME_OF_SMTP_HOST</SMTPHost>
- <to>com</to>
+ <b><to>%mdc{txEmail}</to></b>
<from></from>
<subject>Prime - %mdc{number}</subject>
@@ -223,9 +304,9 @@ public class PrimeAction extends Action {
<evaluator class="ch.qos.logback.classic.boolex.JaninoEventEvaluator">
<expression>
- (mdc != null && mdc.get("txUser") != null &&
- ((String) mdc.get("txUser")).contains("Mickey") )
- &&
+ <b>(mdc != null &amp;&amp; mdc.get("txEmail") != null &amp;&amp; </b>
+ <b>((String) mdc.get("txEmail")).contains("+log") )</b>
+ &amp;&amp;
(marker != null && marker.contains("SMTP_TRIGGER") )
</expression>
</evaluator>
-----------------------------------------------------------------------
Summary of changes:
.../site/pages/recipes/emailPerTransaction.html | 117 +++++++++++++++++---
1 files changed, 99 insertions(+), 18 deletions(-)
hooks/post-receive
--
Logback: the generic, reliable, fast and flexible logging framework.
1
0
[GIT] Logback: the generic, reliable, fast and flexible logging framework. branch, master, updated. v_0.9.25-50-g072bbae
by git-noreply@pixie.qos.ch 21 Dec '10
by git-noreply@pixie.qos.ch 21 Dec '10
21 Dec '10
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "Logback: the generic, reliable, fast and flexible logging framework.".
The branch, master has been updated
via 072bbaef8e8d0508e1660cc5d49b3e8c7112e881 (commit)
from f1db4042a372249765b52d6b430b7f33dcbf410b (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
http://git.qos.ch/gitweb/?p=logback.git;a=commit;h=072bbaef8e8d0508e1660cc5…
http://github.com/ceki/logback/commit/072bbaef8e8d0508e1660cc5d49b3e8c7112e…
commit 072bbaef8e8d0508e1660cc5d49b3e8c7112e881
Author: Ceki Gulcu <ceki(a)qos.ch>
Date: Tue Dec 21 22:56:38 2010 +0100
ongoing edits
diff --git a/logback-site/src/site/resources/recipes/images/factorEmail0.png b/logback-site/src/site/resources/recipes/images/factorEmail0.png
new file mode 100644
index 0000000..0680367
Binary files /dev/null and b/logback-site/src/site/resources/recipes/images/factorEmail0.png differ
-----------------------------------------------------------------------
Summary of changes:
.../site/resources/recipes/images/factorEmail0.png | Bin 0 -> 51648 bytes
1 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 logback-site/src/site/resources/recipes/images/factorEmail0.png
hooks/post-receive
--
Logback: the generic, reliable, fast and flexible logging framework.
1
0