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