/*
* Lilith - a log event viewer.
* Copyright (C) 2007-2011 Joern Huxhorn
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package de.huxhorn.lilith.tools.formatters;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.spi.ClassPackagingData;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.classic.spi.IThrowableProxy;
import ch.qos.logback.classic.spi.LoggerContextVO;
import ch.qos.logback.classic.spi.StackTraceElementProxy;
import ch.qos.logback.core.Context;
import ch.qos.logback.core.status.Status;
import ch.qos.logback.core.status.StatusManager;
import de.huxhorn.lilith.data.eventsource.EventWrapper;
import de.huxhorn.lilith.data.logging.ExtendedStackTraceElement;
import de.huxhorn.lilith.data.logging.LoggingEvent;
import de.huxhorn.lilith.data.logging.Message;
import de.huxhorn.lilith.data.logging.ThreadInfo;
import de.huxhorn.lilith.data.logging.ThrowableInfo;
import de.huxhorn.lilith.logback.tools.ContextHelper;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.Marker;
import org.slf4j.MarkerFactory;
public class LoggingFormatter
implements Formatter<EventWrapper<LoggingEvent>>
{
private final Logger logger = LoggerFactory.getLogger(LoggingFormatter.class);
private static final String DEFAULT_PATTERN="%-5level [%thread]: %message%n";
private ch.qos.logback.classic.PatternLayout layout;
private String pattern;
public String getPattern()
{
return pattern;
}
public void setPattern(String pattern)
{
this.pattern = pattern;
}
public String format(EventWrapper<LoggingEvent> wrapper)
{
initLayout();
if(wrapper!=null)
{
LoggingEvent event = wrapper.getEvent();
if(event != null)
{
LoggingFoo foo=new LoggingFoo(event);
return layout.doLayout(foo);
}
}
return null;
}
private void initLayout()
{
if(layout == null)
{
layout=new ch.qos.logback.classic.PatternLayout();
Context context=new LoggerContext();
layout.setContext(context);
if(pattern != null)
{
layout.setPattern(pattern);
}
else
{
layout.setPattern(DEFAULT_PATTERN);
}
layout.start();
StatusManager statusManager = context.getStatusManager();
int statusLevel = ContextHelper.getHighestLevel(context);
if(statusLevel > Status.INFO)
{
List<Status> stati = statusManager.getCopyOfStatusList();
String msg="Error while initializing layout! " + stati;
if(logger.isErrorEnabled()) logger.error(msg);
throw new IllegalStateException(msg);
}
}
}
// suppress warning caused by implementing deprecated method
@SuppressWarnings("deprecation")
private static class LoggingFoo
implements ILoggingEvent
{
private LoggingEvent event;
LoggingFoo(LoggingEvent event)
{
this.event=event;
}
public String getThreadName()
{
if(event != null)
{
ThreadInfo ti = event.getThreadInfo();
if(ti != null)
{
return ti.getName();
}
}
return null;
}
public Level getLevel()
{
if(event != null)
{
LoggingEvent.Level level = event.getLevel();
if(level != null)
{
switch(level)
{
case TRACE:
return ch.qos.logback.classic.Level.TRACE;
case DEBUG:
return ch.qos.logback.classic.Level.DEBUG;
case INFO:
return ch.qos.logback.classic.Level.INFO;
case WARN:
return ch.qos.logback.classic.Level.WARN;
case ERROR:
return ch.qos.logback.classic.Level.ERROR;
}
}
}
return null;
}
public String getMessage()
{
if(event != null)
{
Message message = event.getMessage();
if(message != null)
{
return message.getMessagePattern();
}
}
return null;
}
public Object[] getArgumentArray()
{
Message message = event.getMessage();
if(message != null)
{
return message.getArguments();
}
return new Object[0];
}
public String getFormattedMessage()
{
if(event != null)
{
Message message = event.getMessage();
if(message != null)
{
return message.getMessage();
}
}
return null;
}
public String getLoggerName()
{
if(event != null)
{
return event.getLogger();
}
return null;
}
public LoggerContextVO getLoggerContextVO()
{
LoggerContextVO result=null;
if(event != null)
{
de.huxhorn.lilith.data.eventsource.LoggerContext loggerContext = event.getLoggerContext();
if(loggerContext != null)
{
result=new LoggerContextVO(loggerContext.getName(), loggerContext.getProperties(), loggerContext.getBirthTime());
}
}
return result;
}
public IThrowableProxy getThrowableProxy()
{
if(event != null)
{
return ThrowableProxyFoo.convert(event.getThrowable());
}
return null;
}
public StackTraceElement[] getCallerData()
{
if(event != null)
{
ExtendedStackTraceElement[] callStack = event.getCallStack();
if(callStack != null)
{
StackTraceElement[] result=new StackTraceElement[callStack.length];
for(int i=0;i<callStack.length;i++)
{
ExtendedStackTraceElement current = callStack[i];
if(current == null)
{
continue;
}
result[i] = current.getStackTraceElement();
}
return result;
}
}
return new StackTraceElement[0];
}
public boolean hasCallerData()
{
if(event != null)
{
ExtendedStackTraceElement[] callStack = event.getCallStack();
return callStack!=null && callStack.length>0;
}
return false;
}
public Marker getMarker()
{
if(event != null)
{
Map<String, Marker> markerMap = new HashMap<>();
return convert(event.getMarker(), markerMap);
}
return null;
}
public Map<String, String> getMDCPropertyMap()
{
if(event != null)
{
return event.getMdc();
}
return null;
}
public Map<String, String> getMdc()
{
if(event != null)
{
return event.getMdc();
}
return null;
}
public long getTimeStamp()
{
if(event != null)
{
Long timeStamp=event.getTimeStamp();
if(timeStamp != null)
{
return timeStamp;
}
}
return 0;
}
public void prepareForDeferredProcessing()
{
}
private static Marker convert(de.huxhorn.lilith.data.logging.Marker originalMarker, Map<String, Marker> markerMap)
{
Marker result = null;
if(originalMarker != null)
{
String originalName = originalMarker.getName();
if(originalName != null)
{
result = markerMap.get(originalName);
if(result == null)
{
result = MarkerFactory.getDetachedMarker(originalName);
markerMap.put(originalName, result);
Map<String,de.huxhorn.lilith.data.logging.Marker> references = originalMarker.getReferences();
if(references != null)
{
for(Map.Entry<String, de.huxhorn.lilith.data.logging.Marker> current : references.entrySet())
{
String name = current.getKey();
de.huxhorn.lilith.data.logging.Marker value = current.getValue();
Marker marker = markerMap.get(name);
if(marker == null)
{
marker = convert(value, markerMap);
}
result.add(marker);
}
}
}
}
}
return result;
}
}
private static class ThrowableProxyFoo
implements IThrowableProxy
{
private String message;
private String className;
private StackTraceElementProxy[] stackTraceElementProxyArray;
private IThrowableProxy cause;
private int commonFrames;
private IThrowableProxy[] suppressed;
public String getMessage()
{
return message;
}
public void setMessage(String message)
{
this.message = message;
}
public String getClassName()
{
return className;
}
public void setClassName(String className)
{
this.className = className;
}
public StackTraceElementProxy[] getStackTraceElementProxyArray()
{
return stackTraceElementProxyArray;
}
public void setStackTraceElementProxyArray(StackTraceElementProxy[] stackTraceElementProxyArray)
{
this.stackTraceElementProxyArray = stackTraceElementProxyArray;
}
public IThrowableProxy[] getSuppressed()
{
return suppressed;
}
public void setSuppressed(IThrowableProxy[] suppressed)
{
this.suppressed = suppressed;
}
public IThrowableProxy getCause()
{
return cause;
}
public void setCause(IThrowableProxy cause)
{
this.cause = cause;
}
public int getCommonFrames()
{
return commonFrames;
}
public void setCommonFrames(int commonFrames)
{
this.commonFrames = commonFrames;
}
private static ThrowableProxyFoo convert(ThrowableInfo throwableInfo)
{
ThrowableProxyFoo result=null;
if(throwableInfo != null)
{
result = new ThrowableProxyFoo();
result.setMessage(throwableInfo.getMessage());
result.setClassName(throwableInfo.getName());
result.setCommonFrames(throwableInfo.getOmittedElements());
result.setStackTraceElementProxyArray(convert(throwableInfo.getStackTrace()));
ThrowableInfo[] throwableInfoSuppressed = throwableInfo.getSuppressed();
if(throwableInfoSuppressed != null)
{
IThrowableProxy[] throwableProxySuppressed=new IThrowableProxy[throwableInfoSuppressed.length];
for(int i=0;i<throwableInfoSuppressed.length;i++)
{
throwableProxySuppressed[i] = convert(throwableInfoSuppressed[i]);
}
result.setSuppressed(throwableProxySuppressed);
}
result.setCause(convert(throwableInfo.getCause()));
}
return result;
}
private static StackTraceElementProxy[] convert(ExtendedStackTraceElement[] stackTrace)
{
StackTraceElementProxy[] result = null;
if(stackTrace != null)
{
result = new StackTraceElementProxy[stackTrace.length];
for(int i=0;i<stackTrace.length;i++)
{
ExtendedStackTraceElement current = stackTrace[i];
if(current == null)
{
continue;
}
StackTraceElement ste = current.getStackTraceElement();
if(ste == null)
{
continue;
}
result[i] = new StackTraceElementProxy(ste);
String codeLocation=current.getCodeLocation();
String version=current.getVersion();
if(codeLocation != null || version != null)
{
boolean exact = current.isExact();
ClassPackagingData cpd=new ClassPackagingData(codeLocation, version, exact);
result[i].setClassPackagingData(cpd);
}
}
}
return result;
}
}
}