001/*
002 * Copyright (C) 2019 Michael N. Lipp (http://www.mnl.de)
003 * 
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *        http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package de.mnl.osgi.lf4osgi.core;
018
019import java.security.AccessController;
020import java.security.PrivilegedAction;
021import java.util.Optional;
022import java.util.Queue;
023import java.util.concurrent.ConcurrentLinkedQueue;
024import org.osgi.framework.Bundle;
025import org.osgi.service.log.LogLevel;
026import org.osgi.service.log.Logger;
027import org.osgi.service.log.LoggerFactory;
028
029/**
030 * A factory for creating {@link BufferingLogger}s.
031 */
032public class BufferingLoggerFactory implements LoggerFactory {
033
034    public static final String LOG_THRESHOLD_PROPERTY
035        = "de.mnl.osgi.lf4osgi.bufferThreshold";
036    public static final String BUFFER_SIZE_PROPERTY
037        = "de.mnl.osgi.lf4osgi.bufferSize";
038    @SuppressWarnings("PMD.LooseCoupling")
039    private final Queue<BufferedEvent> events;
040    private LogLevel threshold = LogLevel.DEBUG;
041    private int bufferSize = 100;
042
043    /**
044     * Instantiates a new buffering logger factory with an
045     * event buffer with given size, buffering only events with
046     * at least the given threshold. 
047     */
048    public BufferingLoggerFactory() {
049        super();
050        this.events = new ConcurrentLinkedQueue<>();
051        AccessController.doPrivileged(new PrivilegedAction<Void>() {
052            @Override
053            public Void run() {
054                threshold = Optional.ofNullable(System
055                    .getProperty(LOG_THRESHOLD_PROPERTY))
056                    .map(LogLevel::valueOf).orElse(LogLevel.TRACE);
057                bufferSize = Optional.ofNullable(System
058                    .getProperty(BUFFER_SIZE_PROPERTY))
059                    .map(Integer::parseInt).orElse(1000);
060                return null;
061            }
062        });
063    }
064
065    /**
066     * Sets the buffer size.
067     *
068     * @param bufferSize the buffer size
069     * @return the buffering logger factory
070     */
071    public BufferingLoggerFactory setBufferSize(int bufferSize) {
072        this.bufferSize = bufferSize;
073        while (events.size() > bufferSize) {
074            events.poll();
075        }
076        return this;
077    }
078
079    /**
080     * Sets the threshold.
081     *
082     * @param threshold the threshold
083     * @return the buffering logger factory
084     */
085    public BufferingLoggerFactory setThreshold(LogLevel threshold) {
086        this.threshold = threshold;
087        return this;
088    }
089
090    public LogLevel threshold() {
091        return threshold;
092    }
093
094    /**
095     * Adds the event, removing the oldest event if the buffer sise is reached.
096     *
097     * @param event the event
098     */
099    public void addEvent(BufferedEvent event) {
100        if (events.size() == bufferSize) {
101            events.poll();
102        }
103        events.add(event);
104    }
105
106    /**
107     * Forward all buffered events.
108     *
109     * @param factory the factory
110     */
111    public void flush(LoggerFactory factory) {
112        while (true) {
113            BufferedEvent event = events.poll();
114            if (event == null) {
115                break;
116            }
117            event.forward(factory);
118        }
119    }
120
121    @Override
122    public Logger getLogger(String name) {
123        throw new UnsupportedOperationException();
124    }
125
126    @Override
127    public Logger getLogger(Class<?> clazz) {
128        throw new UnsupportedOperationException();
129    }
130
131    @Override
132    public <L extends Logger> L getLogger(String name, Class<L> loggerType) {
133        throw new UnsupportedOperationException();
134    }
135
136    @Override
137    public <L extends Logger> L getLogger(Class<?> clazz, Class<L> loggerType) {
138        throw new UnsupportedOperationException();
139    }
140
141    @SuppressWarnings("unchecked")
142    @Override
143    public <L extends Logger> L getLogger(Bundle bundle, String name,
144            Class<L> loggerType) {
145        return (L) new BufferingLogger(this, bundle, name);
146    }
147
148}