001/**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.camel.model;
018
019import java.util.Map;
020
021import javax.xml.bind.annotation.XmlAccessType;
022import javax.xml.bind.annotation.XmlAccessorType;
023import javax.xml.bind.annotation.XmlAttribute;
024import javax.xml.bind.annotation.XmlRootElement;
025import javax.xml.bind.annotation.XmlTransient;
026
027import org.apache.camel.Exchange;
028import org.apache.camel.Expression;
029import org.apache.camel.LoggingLevel;
030import org.apache.camel.Processor;
031import org.apache.camel.processor.DefaultMaskingFormatter;
032import org.apache.camel.processor.LogProcessor;
033import org.apache.camel.spi.MaskingFormatter;
034import org.apache.camel.spi.Metadata;
035import org.apache.camel.spi.RouteContext;
036import org.apache.camel.util.CamelContextHelper;
037import org.apache.camel.util.CamelLogger;
038import org.apache.camel.util.ObjectHelper;
039import org.apache.camel.util.StringHelper;
040import org.slf4j.Logger;
041import org.slf4j.LoggerFactory;
042
043/**
044 * Logs the defined message to the logger
045 *
046 * @version 
047 */
048@Metadata(label = "eip,configuration")
049@XmlRootElement(name = "log")
050@XmlAccessorType(XmlAccessType.FIELD)
051public class LogDefinition extends NoOutputDefinition<LogDefinition> {
052    @XmlTransient
053    private static final Logger LOG = LoggerFactory.getLogger(LogDefinition.class);
054    @XmlAttribute(required = true)
055    private String message;
056    @XmlAttribute @Metadata(defaultValue = "INFO")
057    private LoggingLevel loggingLevel;
058    @XmlAttribute
059    private String logName;
060    @XmlAttribute
061    private String marker;
062    @XmlAttribute
063    private String loggerRef;
064    @XmlTransient
065    private Logger logger;
066
067    public LogDefinition() {
068    }
069
070    public LogDefinition(String message) {
071        this.message = message;
072    }
073
074    @Override
075    public String toString() {
076        return "Log[" + message + "]";
077    }
078    
079    @Override
080    public String getShortName() {
081        return "log";
082    }
083
084    @Override
085    public String getLabel() {
086        return "log";
087    }
088
089    @Override
090    public Processor createProcessor(RouteContext routeContext) throws Exception {
091        StringHelper.notEmpty(message, "message", this);
092
093        // use simple language for the message string to give it more power
094        Expression exp = routeContext.getCamelContext().resolveLanguage("simple").createExpression(message);
095
096        // get logger explicitely set in the definition
097        Logger logger = this.getLogger();
098
099        // get logger which may be set in XML definition
100        if (logger == null && ObjectHelper.isNotEmpty(loggerRef)) {
101            logger = CamelContextHelper.mandatoryLookup(routeContext.getCamelContext(), loggerRef, Logger.class);
102        }
103
104        if (logger == null) {
105            // first - try to lookup single instance in the registry, just like LogComponent
106            Map<String, Logger> availableLoggers = routeContext.lookupByType(Logger.class);
107            if (availableLoggers.size() == 1) {
108                logger = availableLoggers.values().iterator().next();
109                LOG.debug("Using custom Logger: {}", logger);
110            } else if (availableLoggers.size() > 1) {
111                // we should log about this somewhere...
112                LOG.debug("More than one {} instance found in the registry. Falling back to create logger by name.", Logger.class.getName());
113            }
114        }
115
116        if (logger == null) {
117            String name = getLogName();
118            if (name == null) {
119                name = routeContext.getCamelContext().getGlobalOption(Exchange.LOG_EIP_NAME);
120                if (name != null) {
121                    LOG.debug("Using logName from CamelContext properties: {}", name);
122                }
123            }
124            if (name == null) {
125                name = routeContext.getRoute().getId();
126                LOG.debug("LogName is not configured, using route id as logName: {}", name);
127            }
128            logger = LoggerFactory.getLogger(name);
129        }
130
131        // should be INFO by default
132        LoggingLevel level = getLoggingLevel() != null ? getLoggingLevel() : LoggingLevel.INFO;
133        CamelLogger camelLogger = new CamelLogger(logger, level, getMarker());
134
135        return new LogProcessor(exp, camelLogger, getMaskingFormatter(routeContext), routeContext.getCamelContext().getLogListeners());
136    }
137
138    private MaskingFormatter getMaskingFormatter(RouteContext routeContext) {
139        if (routeContext.isLogMask()) {
140            MaskingFormatter formatter = routeContext.getCamelContext().getRegistry().lookupByNameAndType(Constants.CUSTOM_LOG_MASK_REF, MaskingFormatter.class);
141            if (formatter == null) {
142                formatter = new DefaultMaskingFormatter();
143            }
144            return formatter;
145        }
146        return null;
147    }
148
149    @Override
150    public void addOutput(ProcessorDefinition<?> output) {
151        // add outputs on parent as this log does not support outputs
152        getParent().addOutput(output);
153    }
154
155    public LoggingLevel getLoggingLevel() {
156        return loggingLevel;
157    }
158
159    /**
160     * Sets the logging level.
161     * <p/>
162     * The default value is INFO
163     */
164    public void setLoggingLevel(LoggingLevel loggingLevel) {
165        this.loggingLevel = loggingLevel;
166    }
167
168    public String getMessage() {
169        return message;
170    }
171
172    /**
173     * Sets the log message (uses simple language)
174     */
175    public void setMessage(String message) {
176        this.message = message;
177    }
178
179    public String getLogName() {
180        return logName;
181    }
182
183    /**
184     * Sets the name of the logger
185     */
186    public void setLogName(String logName) {
187        this.logName = logName;
188    }
189
190    public String getMarker() {
191        return marker;
192    }
193
194    /**
195     * To use slf4j marker
196     */
197    public void setMarker(String marker) {
198        this.marker = marker;
199    }
200
201    public String getLoggerRef() {
202        return loggerRef;
203    }
204
205    /**
206     * To refer to a custom logger instance to lookup from the registry.
207     */
208    public void setLoggerRef(String loggerRef) {
209        this.loggerRef = loggerRef;
210    }
211
212    public Logger getLogger() {
213        return logger;
214    }
215
216    /**
217     * To use a custom logger instance
218     */
219    public void setLogger(Logger logger) {
220        this.logger = logger;
221    }
222}