[logback-dev] svn commit: r2086 - logback/trunk/logback-core/src/main/java/ch/qos/logback/core/sift
noreply.ceki at qos.ch
noreply.ceki at qos.ch
Thu Dec 18 21:48:23 CET 2008
Author: ceki
Date: Thu Dec 18 21:48:23 2008
New Revision: 2086
Added:
logback/trunk/logback-core/src/main/java/ch/qos/logback/core/sift/
logback/trunk/logback-core/src/main/java/ch/qos/logback/core/sift/AppenderFactory.java
logback/trunk/logback-core/src/main/java/ch/qos/logback/core/sift/AppenderTracker.java
logback/trunk/logback-core/src/main/java/ch/qos/logback/core/sift/AppenderTrackerImpl.java
logback/trunk/logback-core/src/main/java/ch/qos/logback/core/sift/SiftingAppenderBase.java
logback/trunk/logback-core/src/main/java/ch/qos/logback/core/sift/SiftingJoranConfigurator.java
Log:
- migrating SiftingAppender to logback-core from logback-classic
Added: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/sift/AppenderFactory.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/sift/AppenderFactory.java Thu Dec 18 21:48:23 2008
@@ -0,0 +1,43 @@
+package ch.qos.logback.core.sift;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import ch.qos.logback.core.Appender;
+import ch.qos.logback.core.Context;
+import ch.qos.logback.core.joran.event.SaxEvent;
+import ch.qos.logback.core.joran.spi.JoranException;
+
+public abstract class AppenderFactory<E, K> {
+
+ final List<SaxEvent> eventList;
+ Context context;
+
+ AppenderFactory(Context context, List<SaxEvent> eventList) {
+ this.context = context;
+ this.eventList = new ArrayList<SaxEvent>(eventList);
+ removeHoardElement();
+
+ }
+
+ void removeHoardElement() {
+ eventList.remove(0);
+ eventList.remove(eventList.size() - 1);
+ System.out.println(eventList);
+ }
+
+
+ abstract SiftingJoranConfigurator<E> getSiftingJoranConfigurator(K k);
+
+ Appender<E> buildAppender(Context context, K k) throws JoranException {
+ SiftingJoranConfigurator<E> sjc = getSiftingJoranConfigurator(k);
+ sjc.setContext(context);
+ sjc.doConfigure(eventList);
+ return sjc.getAppender();
+ }
+
+ public List<SaxEvent> getEventList() {
+ return eventList;
+ }
+
+}
Added: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/sift/AppenderTracker.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/sift/AppenderTracker.java Thu Dec 18 21:48:23 2008
@@ -0,0 +1,28 @@
+/**
+ * Logback: the generic, reliable, fast and flexible logging framework.
+ *
+ * Copyright (C) 2000-2008, QOS.ch
+ *
+ * This library is free software, you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation.
+ */
+package ch.qos.logback.core.sift;
+
+import java.util.List;
+
+import ch.qos.logback.core.Appender;
+
+public interface AppenderTracker<E, K> {
+
+ static int MILLIS_IN_ONE_SECOND = 1000;
+ static int THRESHOLD = 30 * 60 * MILLIS_IN_ONE_SECOND; // 30 minutes
+
+ void put(K key, Appender<E> value, long timestamp);
+ Appender<E> get(String key, long timestamp);
+ void stopStaleAppenders(long timestamp);
+ List<K> keyList();
+ List<Appender<E>> valueList();
+
+
+}
\ No newline at end of file
Added: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/sift/AppenderTrackerImpl.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/sift/AppenderTrackerImpl.java Thu Dec 18 21:48:23 2008
@@ -0,0 +1,207 @@
+/**
+ * Logback: the generic, reliable, fast and flexible logging framework.
+ *
+ * Copyright (C) 2000-2008, QOS.ch
+ *
+ * This library is free software, you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation.
+ */
+package ch.qos.logback.core.sift;
+
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import ch.qos.logback.core.Appender;
+
+/**
+ * Track appenders by a key. When an appender is not used for
+ * longer than THRESHOLD, stop it.
+ * @author Ceki Gulcu
+ */
+public class AppenderTrackerImpl<E, K> implements AppenderTracker<E, K> {
+
+ Map<K, Entry> map = new HashMap<K, Entry>();
+
+ Entry head; // least recently used entries are towards the head
+ Entry tail; // most recently used entries are towards the tail
+
+ long lastCheck = 0;
+
+ AppenderTrackerImpl() {
+ head = new Entry(null, null, 0);
+ tail = head;
+ }
+
+
+ public synchronized void put(K key, Appender<E> value, long timestamp) {
+ Entry entry = map.get(key);
+ if (entry == null) {
+ entry = new Entry(key, value, timestamp);
+ map.put(key, entry);
+ }
+ moveToTail(entry);
+ }
+
+ public synchronized Appender<E> get(String key, long timestamp) {
+ Entry existing = map.get(key);
+ if (existing == null) {
+ return null;
+ } else {
+ existing.setTimestamp(timestamp);
+ moveToTail(existing);
+ return existing.value;
+ }
+ }
+
+
+ public synchronized void stopStaleAppenders(long now) {
+ if (lastCheck + MILLIS_IN_ONE_SECOND > now) {
+ return;
+ }
+ lastCheck = now;
+ while (head.value != null && isEntryStale(head,now)) {
+ Appender appender = head.value;
+ //System.out.println(" stopping "+appender);
+ appender.stop();
+ removeHead();
+ }
+ }
+
+ public List<K> keyList() {
+ List<K> result = new LinkedList<K>();
+ Entry e = head;
+ while (e != tail) {
+ result.add(e.key);
+ e = e.next;
+ }
+ return result;
+ }
+
+
+ final private boolean isEntryStale(Entry entry, long now) {
+ return ((entry.timestamp + THRESHOLD) < now);
+ }
+
+
+ private void removeHead() {
+ // System.out.println("RemoveHead called");
+ map.remove(head.key);
+ head = head.next;
+ head.prev = null;
+ }
+
+ private void moveToTail(Entry e) {
+ rearrangePreexistingLinks(e);
+ rearrangeTailLinks(e);
+ }
+
+ private void rearrangePreexistingLinks(Entry e) {
+ if (e.prev != null) {
+ e.prev.next = e.next;
+ }
+ if (e.next != null) {
+ e.next.prev = e.prev;
+ }
+ if (head == e) {
+ head = e.next;
+ }
+ }
+
+ private void rearrangeTailLinks(Entry e) {
+ if (head == tail) {
+ head = e;
+ }
+ Entry preTail = tail.prev;
+ if (preTail != null) {
+ preTail.next = e;
+ }
+ e.prev = preTail;
+ e.next = tail;
+ tail.prev = e;
+ }
+
+ public void dump() {
+ Entry e = head;
+ System.out.print("N:");
+ while (e != null) {
+ // System.out.print(e+"->");
+ System.out.print(e.key + ", ");
+ e = e.next;
+ }
+ System.out.println();
+ }
+
+
+
+ public List<Appender<E>> valueList() {
+ List<Appender<E>> result = new LinkedList<Appender<E>>();
+ Entry e = head;
+ while (e != tail) {
+ result.add(e.value);
+ e = e.next;
+ }
+ return result;
+ }
+
+ // ================================================================
+ private class Entry {
+ Entry next;
+ Entry prev;
+
+ K key;
+ Appender<E> value;
+ long timestamp;
+
+ Entry(K k, Appender<E> v, long timestamp) {
+ this.key = k;
+ this.value = v;
+ this.timestamp = timestamp;
+ }
+
+ public long getTimestamp() {
+ return timestamp;
+ }
+
+ public void setTimestamp(long timestamp) {
+ this.timestamp = timestamp;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((key == null) ? 0 : key.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ final Entry other = (Entry) obj;
+ if (key == null) {
+ if (other.key != null)
+ return false;
+ } else if (!key.equals(other.key))
+ return false;
+ if (value == null) {
+ if (other.value != null)
+ return false;
+ } else if (!value.equals(other.value))
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "(" + key + ", " + value + ")";
+ }
+ }
+}
Added: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/sift/SiftingAppenderBase.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/sift/SiftingAppenderBase.java Thu Dec 18 21:48:23 2008
@@ -0,0 +1,112 @@
+/**
+ * Logback: the generic, reliable, fast and flexible logging framework.
+ *
+ * Copyright (C) 2000-2008, QOS.ch
+ *
+ * This library is free software, you can redistribute it and/or modify it under
+ * the terms of the GNU Lesser General Public License as published by the Free
+ * Software Foundation.
+ */
+package ch.qos.logback.core.sift;
+
+
+import ch.qos.logback.core.Appender;
+import ch.qos.logback.core.UnsynchronizedAppenderBase;
+import ch.qos.logback.core.joran.spi.JoranException;
+import ch.qos.logback.core.util.OptionHelper;
+
+/**
+ * This appender can contains other appenders which it can build dynamically
+ * depending on MDC values. The built appender is specified as part of a
+ * configuration file.
+ *
+ * <p>See the logback manual for further details.
+ *
+ *
+ * @author Ceki Gulcu
+ */
+public abstract class SiftingAppenderBase<E, K> extends UnsynchronizedAppenderBase<E> {
+
+ AppenderTracker<E, K> appenderTracker = new AppenderTrackerImpl<E, K>();
+ //Map<String, Appender<LoggingEvent>> appenderMap = new Hashtable<String, Appender<LoggingEvent>>();
+
+ String mdcKey;
+ String defaultValue;
+
+ AppenderFactory<E, K> appenderFactory;
+
+ void setAppenderFactory(AppenderFactory<E, K> appenderFactory) {
+ this.appenderFactory = appenderFactory;
+ }
+
+ @Override
+ public void start() {
+ int errors = 0;
+ if (OptionHelper.isEmpty(mdcKey)) {
+ errors++;
+ addError("The \"mdcKey\" property must be set");
+ }
+ if (OptionHelper.isEmpty(defaultValue)) {
+ errors++;
+ addError("The \"defaultValue\" property must be set");
+ }
+ if (errors == 0) {
+ super.start();
+ }
+ }
+
+ @Override
+ public void stop() {
+ for (Appender<E> appender : appenderTracker.valueList()) {
+ appender.stop();
+ }
+ }
+
+ abstract protected K getDiscriminatingValue(E event);
+ abstract protected long getTimestamp(E event);
+
+ @Override
+ protected void append(E event) {
+ if (!isStarted()) {
+ return;
+ }
+
+
+ K value = getDiscriminatingValue(event);
+ long timestamp = getTimestamp(event);
+
+ Appender<E> appender = appenderTracker.get(value, timestamp);
+
+ if (appender == null) {
+ try {
+ appender = appenderFactory.buildAppender(context, value);
+ if (appender != null) {
+ appenderTracker.put(value, appender, timestamp);
+ }
+ } catch (JoranException e) {
+ addError("Failed to build appender for [" + value + "]", e);
+ return;
+ }
+ }
+ appenderTracker.stopStaleAppenders(timestamp);
+ appender.doAppend(event);
+ }
+
+ public String getMdcKey() {
+ return mdcKey;
+ }
+
+ public void setMdcKey(String mdcKey) {
+ this.mdcKey = mdcKey;
+ }
+
+ /**
+ * @see #setDefaultValue(String)
+ * @return
+ */
+ public String getDefaultValue() {
+ return defaultValue;
+ }
+
+
+}
Added: logback/trunk/logback-core/src/main/java/ch/qos/logback/core/sift/SiftingJoranConfigurator.java
==============================================================================
--- (empty file)
+++ logback/trunk/logback-core/src/main/java/ch/qos/logback/core/sift/SiftingJoranConfigurator.java Thu Dec 18 21:48:23 2008
@@ -0,0 +1,23 @@
+package ch.qos.logback.core.sift;
+
+import ch.qos.logback.core.Appender;
+import ch.qos.logback.core.joran.GenericConfigurator;
+import ch.qos.logback.core.joran.spi.Interpreter;
+import ch.qos.logback.core.joran.spi.RuleStore;
+
+public abstract class SiftingJoranConfigurator<E> extends GenericConfigurator {
+
+ @Override
+ protected void addImplicitRules(Interpreter interpreter) {
+ // TODO Auto-generated method stub
+
+ }
+
+ @Override
+ protected void addInstanceRules(RuleStore rs) {
+ // TODO Auto-generated method stub
+
+ }
+
+ abstract Appender<E> getAppender();
+}
More information about the logback-dev
mailing list