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;
024import org.slf4j.Marker;
025
026/**
027 * Send an e-mail when a specific logging event occurs, typically on errors or
028 * fatal errors.
029 * 
030 * For more information about this appender, please refer to the online manual at
031 * http://logback.qos.ch/manual/appenders.html#SMTPAppender
032 * 
033 * @author Ceki Gülcü
034 * @author Sébastien Pennec
035 * 
036 */
037public class SMTPAppender extends SMTPAppenderBase<ILoggingEvent> {
038
039    // value "%logger{20} - %m" is referenced in the docs!
040    static final String DEFAULT_SUBJECT_PATTERN = "%logger{20} - %m";
041
042    private boolean includeCallerData = false;
043
044    /**
045     * The default constructor will instantiate the appender with a
046     * {@link EventEvaluator} that will trigger on events with level
047     * ERROR or higher.
048     */
049    public SMTPAppender() {
050
051    }
052
053    public void start() {
054        if (eventEvaluator == null) {
055            OnErrorEvaluator onError = new OnErrorEvaluator();
056            onError.setContext(getContext());
057            onError.setName("onError");
058            onError.start();
059            this.eventEvaluator = onError;
060        }
061        super.start();
062    }
063
064    /**
065     * Use the parameter as the {@link
066     * EventEvaluator} for this SMTPAppender.
067     */
068    public SMTPAppender(EventEvaluator<ILoggingEvent> eventEvaluator) {
069        this.eventEvaluator = eventEvaluator;
070    }
071
072    /**
073     * Perform SMTPAppender specific appending actions, mainly adding the event to
074     * a cyclic buffer.
075     */
076    protected void subAppend(CyclicBuffer<ILoggingEvent> cb, ILoggingEvent event) {
077        if (includeCallerData) {
078            event.getCallerData();
079        }
080        event.prepareForDeferredProcessing();
081        cb.add(event);
082    }
083
084    @Override
085    protected void fillBuffer(CyclicBuffer<ILoggingEvent> cb, StringBuffer sbuf) {
086        int len = cb.length();
087        for (int i = 0; i < len; i++) {
088            ILoggingEvent event = cb.get();
089            sbuf.append(layout.doLayout(event));
090        }
091    }
092
093    protected boolean eventMarksEndOfLife(ILoggingEvent eventObject) {
094        Marker marker = eventObject.getMarker();
095        if (marker == null)
096            return false;
097
098        return marker.contains(ClassicConstants.FINALIZE_SESSION_MARKER);
099    }
100
101    @Override
102    protected Layout<ILoggingEvent> makeSubjectLayout(String subjectStr) {
103        if (subjectStr == null) {
104            subjectStr = DEFAULT_SUBJECT_PATTERN;
105        }
106        PatternLayout pl = new PatternLayout();
107        pl.setContext(getContext());
108        pl.setPattern(subjectStr);
109        // we don't want a ThrowableInformationConverter appended
110        // to the end of the converter chain
111        // This fixes issue LBCLASSIC-67
112        pl.setPostCompileProcessor(null);
113        pl.start();
114        return pl;
115    }
116
117    protected PatternLayout makeNewToPatternLayout(String toPattern) {
118        PatternLayout pl = new PatternLayout();
119        pl.setPattern(toPattern + "%nopex");
120        return pl;
121    }
122
123    public boolean isIncludeCallerData() {
124        return includeCallerData;
125    }
126
127    public void setIncludeCallerData(boolean includeCallerData) {
128        this.includeCallerData = includeCallerData;
129    }
130}