001/** 002 * Logback: the reliable, generic, fast and flexible logging framework. 003 * Copyright (C) 1999-2015, QOS.ch. All rights reserved. 004 * 005 * This program and the accompanying materials are dual-licensed under 006 * either the terms of the Eclipse Public License v1.0 as published by 007 * the Eclipse Foundation 008 * 009 * or (per the licensee's choosing) 010 * 011 * under the terms of the GNU Lesser General Public License version 2.1 012 * as published by the Free Software Foundation. 013 */ 014package ch.qos.logback.classic.net; 015 016import ch.qos.logback.classic.ClassicConstants; 017import ch.qos.logback.classic.PatternLayout; 018import ch.qos.logback.classic.boolex.OnErrorEvaluator; 019import ch.qos.logback.classic.spi.ILoggingEvent; 020import ch.qos.logback.core.Layout; 021import ch.qos.logback.core.boolex.EventEvaluator; 022import ch.qos.logback.core.helpers.CyclicBuffer; 023import ch.qos.logback.core.net.SMTPAppenderBase; 024 025import java.util.List; 026import java.util.concurrent.Future; 027 028import org.slf4j.Marker; 029 030/** 031 * Send an e-mail when a specific logging event occurs, typically on errors or 032 * fatal errors. 033 * 034 * For more information about this appender, please refer to the online manual 035 * at http://logback.qos.ch/manual/appenders.html#SMTPAppender 036 * 037 * @author Ceki Gülcü 038 * @author Sébastien Pennec 039 * 040 */ 041public class SMTPAppender extends SMTPAppenderBase<ILoggingEvent> { 042 043 // value "%logger{20} - %m" is referenced in the docs! 044 static final String DEFAULT_SUBJECT_PATTERN = "%logger{20} - %m"; 045 046 private boolean includeCallerData = false; 047 048 /** 049 * The default constructor will instantiate the appender with a 050 * {@link EventEvaluator} that will trigger on events with level ERROR or 051 * higher. 052 */ 053 public SMTPAppender() { 054 055 } 056 057 public void start() { 058 if (eventEvaluator == null) { 059 OnErrorEvaluator onError = new OnErrorEvaluator(); 060 onError.setContext(getContext()); 061 onError.setName("onError"); 062 onError.start(); 063 this.eventEvaluator = onError; 064 } 065 super.start(); 066 } 067 068 /** 069 * Use the parameter as the {@link EventEvaluator} for this SMTPAppender. 070 */ 071 public SMTPAppender(EventEvaluator<ILoggingEvent> eventEvaluator) { 072 this.eventEvaluator = eventEvaluator; 073 } 074 075 /** 076 * Perform SMTPAppender specific appending actions, mainly adding the event to a 077 * cyclic buffer. 078 */ 079 protected void subAppend(CyclicBuffer<ILoggingEvent> cb, ILoggingEvent event) { 080 if (includeCallerData) { 081 event.getCallerData(); 082 } 083 event.prepareForDeferredProcessing(); 084 cb.add(event); 085 } 086 087 @Override 088 protected void fillBuffer(CyclicBuffer<ILoggingEvent> cb, StringBuffer sbuf) { 089 int len = cb.length(); 090 for (int i = 0; i < len; i++) { 091 ILoggingEvent event = cb.get(); 092 sbuf.append(layout.doLayout(event)); 093 } 094 } 095 096 protected boolean eventMarksEndOfLife(ILoggingEvent eventObject) { 097 List<Marker> markers = eventObject.getMarkerList(); 098 if (markers == null || markers.isEmpty()) 099 return false; 100 101 for (Marker marker : markers) { 102 if (marker.contains(ClassicConstants.FINALIZE_SESSION_MARKER)) { 103 return true; 104 } 105 } 106 return false; 107 } 108 109 @Override 110 protected Layout<ILoggingEvent> makeSubjectLayout(String subjectStr) { 111 if (subjectStr == null) { 112 subjectStr = DEFAULT_SUBJECT_PATTERN; 113 } 114 PatternLayout pl = new PatternLayout(); 115 pl.setContext(getContext()); 116 pl.setPattern(subjectStr); 117 // we don't want a ThrowableInformationConverter appended 118 // to the end of the converter chain 119 // This fixes issue LBCLASSIC-67 120 pl.setPostCompileProcessor(null); 121 pl.start(); 122 return pl; 123 } 124 125 protected PatternLayout makeNewToPatternLayout(String toPattern) { 126 PatternLayout pl = new PatternLayout(); 127 pl.setPattern(toPattern + "%nopex"); 128 return pl; 129 } 130 131 public boolean isIncludeCallerData() { 132 return includeCallerData; 133 } 134 135 public void setIncludeCallerData(boolean includeCallerData) { 136 this.includeCallerData = includeCallerData; 137 } 138 139 Future<?> getAsynchronousSendingFuture() { 140 return asynchronousSendingFuture; 141 } 142}