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.component.log;
018
019import org.apache.camel.Component;
020import org.apache.camel.LoggingLevel;
021import org.apache.camel.Processor;
022import org.apache.camel.Producer;
023import org.apache.camel.impl.ProcessorEndpoint;
024import org.apache.camel.model.Constants;
025import org.apache.camel.processor.CamelLogProcessor;
026import org.apache.camel.processor.DefaultExchangeFormatter;
027import org.apache.camel.processor.DefaultMaskingFormatter;
028import org.apache.camel.processor.ThroughputLogger;
029import org.apache.camel.spi.ExchangeFormatter;
030import org.apache.camel.spi.LogListener;
031import org.apache.camel.spi.MaskingFormatter;
032import org.apache.camel.spi.Metadata;
033import org.apache.camel.spi.UriEndpoint;
034import org.apache.camel.spi.UriParam;
035import org.apache.camel.spi.UriPath;
036import org.apache.camel.util.CamelLogger;
037import org.apache.camel.util.ServiceHelper;
038import org.slf4j.Logger;
039
040/**
041 * The log component logs message exchanges to the underlying logging mechanism.
042 *
043 * Camel uses sfl4j which allows you to configure logging to the actual logging system.
044 */
045@UriEndpoint(firstVersion = "1.1.0", scheme = "log", title = "Log", syntax = "log:loggerName", producerOnly = true, label = "core,monitoring")
046public class LogEndpoint extends ProcessorEndpoint {
047
048    private volatile Processor logger;
049    private Logger providedLogger;
050    private ExchangeFormatter localFormatter;
051
052    @UriPath(description = "Name of the logging category to use") @Metadata(required = "true")
053    private String loggerName;
054    @UriParam(defaultValue = "INFO", enums = "ERROR,WARN,INFO,DEBUG,TRACE,OFF")
055    private String level;
056    @UriParam
057    private String marker;
058    @UriParam
059    private Integer groupSize;
060    @UriParam
061    private Long groupInterval;
062    @UriParam(defaultValue = "true")
063    private Boolean groupActiveOnly;
064    @UriParam
065    private Long groupDelay;
066    // we want to include the uri options of the DefaultExchangeFormatter
067    @UriParam(label = "advanced")
068    private DefaultExchangeFormatter exchangeFormatter;
069    @UriParam
070    private Boolean logMask;
071
072    public LogEndpoint() {
073    }
074
075    public LogEndpoint(String endpointUri, Component component) {
076        super(endpointUri, component);
077    }
078
079    public LogEndpoint(String endpointUri, Component component, Processor logger) {
080        super(endpointUri, component);
081        setLogger(logger);
082    }
083
084    @Override
085    protected void doStart() throws Exception {
086        if (logger == null) {
087            logger = createLogger();
088        }
089        ServiceHelper.startService(logger);
090    }
091
092    @Override
093    protected void doStop() throws Exception {
094        ServiceHelper.stopService(logger);
095    }
096
097    public void setLogger(Processor logger) {
098        this.logger = logger;
099        // the logger is the processor
100        setProcessor(this.logger);
101    }
102
103    public Processor getLogger() {
104        return logger;
105    }
106
107    @Override
108    public Producer createProducer() throws Exception {
109        // ensure logger is created and started first
110        if (logger == null) {
111            logger = createLogger();
112        }
113        ServiceHelper.startService(logger);
114        return new LogProducer(this, logger);
115    }
116
117    @Override
118    protected String createEndpointUri() {
119        return "log:" + logger.toString();
120    }
121
122    /**
123     * Creates the logger {@link Processor} to be used.
124     */
125    protected Processor createLogger() throws Exception {
126        Processor answer;
127        // setup a new logger here
128        CamelLogger camelLogger;
129        LoggingLevel loggingLevel = LoggingLevel.INFO;
130        if (level != null) {
131            loggingLevel = LoggingLevel.valueOf(level);
132        }
133        if (providedLogger == null) {
134            camelLogger = new CamelLogger(loggerName, loggingLevel, getMarker());
135        } else {
136            camelLogger = new CamelLogger(providedLogger, loggingLevel, getMarker());
137        }
138        if (getGroupSize() != null) {
139            answer = new ThroughputLogger(camelLogger, getGroupSize());
140        } else if (getGroupInterval() != null) {
141            Boolean groupActiveOnly = getGroupActiveOnly() != null ? getGroupActiveOnly() : Boolean.TRUE;
142            Long groupDelay = getGroupDelay();
143            answer = new ThroughputLogger(camelLogger, this.getCamelContext(), getGroupInterval(), groupDelay, groupActiveOnly);
144        } else {
145            answer = new CamelLogProcessor(camelLogger, localFormatter, getMaskingFormatter(), getCamelContext().getLogListeners());
146        }
147        // the logger is the processor
148        setProcessor(answer);
149        return answer;
150    }
151
152    private MaskingFormatter getMaskingFormatter() {
153        if (logMask != null ? logMask : getCamelContext().isLogMask()) {
154            MaskingFormatter formatter = getCamelContext().getRegistry().lookupByNameAndType(Constants.CUSTOM_LOG_MASK_REF, MaskingFormatter.class);
155            if (formatter == null) {
156                formatter = new DefaultMaskingFormatter();
157            }
158            return formatter;
159        }
160        return null;
161    }
162
163    /**
164     * Logging level to use.
165     * <p/>
166     * The default value is INFO.
167     */
168    public String getLevel() {
169        return level;
170    }
171
172    /**
173     * Logging level to use.
174     * <p/>
175     * The default value is INFO.
176     */
177    public void setLevel(String level) {
178        this.level = level;
179    }
180
181    /**
182     * An optional Marker name to use.
183     */
184    public String getMarker() {
185        return marker;
186    }
187
188    /**
189     * An optional Marker name to use.
190     */
191    public void setMarker(String marker) {
192        this.marker = marker;
193    }
194
195    /**
196     * An integer that specifies a group size for throughput logging.
197     */
198    public Integer getGroupSize() {
199        return groupSize;
200    }
201
202    /**
203     * An integer that specifies a group size for throughput logging.
204     */
205    public void setGroupSize(Integer groupSize) {
206        this.groupSize = groupSize;
207    }
208
209    /**
210     * If specified will group message stats by this time interval (in millis)
211     */
212    public Long getGroupInterval() {
213        return groupInterval;
214    }
215
216    /**
217     * If specified will group message stats by this time interval (in millis)
218     */
219    public void setGroupInterval(Long groupInterval) {
220        this.groupInterval = groupInterval;
221    }
222
223    /**
224     * If true, will hide stats when no new messages have been received for a time interval, if false, show stats regardless of message traffic.
225     */
226    public Boolean getGroupActiveOnly() {
227        return groupActiveOnly;
228    }
229
230    /**
231     * If true, will hide stats when no new messages have been received for a time interval, if false, show stats regardless of message traffic.
232     */
233    public void setGroupActiveOnly(Boolean groupActiveOnly) {
234        this.groupActiveOnly = groupActiveOnly;
235    }
236
237    /**
238     * Set the initial delay for stats (in millis)
239     */
240    public Long getGroupDelay() {
241        return groupDelay;
242    }
243
244    /**
245     * Set the initial delay for stats (in millis)
246     */
247    public void setGroupDelay(Long groupDelay) {
248        this.groupDelay = groupDelay;
249    }
250
251    public ExchangeFormatter getLocalFormatter() {
252        return localFormatter;
253    }
254
255    public void setLocalFormatter(ExchangeFormatter localFormatter) {
256        this.localFormatter = localFormatter;
257    }
258
259    public Logger getProvidedLogger() {
260        return providedLogger;
261    }
262
263    public void setProvidedLogger(Logger providedLogger) {
264        this.providedLogger = providedLogger;
265    }
266
267    /**
268     * The logger name to use
269     */
270    public String getLoggerName() {
271        return loggerName;
272    }
273
274    /**
275     * The logger name to use
276     */
277    public void setLoggerName(String loggerName) {
278        this.loggerName = loggerName;
279    }
280
281    public Boolean getLogMask() {
282        return logMask;
283    }
284
285    /**
286     * If true, mask sensitive information like password or passphrase in the log.
287     */
288    public void setLogMask(Boolean logMask) {
289        this.logMask = logMask;
290    }
291
292}