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;
024
025import org.osgi.framework.Bundle;
026import org.osgi.service.log.LogLevel;
027import org.osgi.service.log.Logger;
028import org.osgi.service.log.LoggerFactory;
029
030/**
031 * A factory for creating {@link BufferingLogger}s.
032 */
033public class BufferingLoggerFactory implements LoggerFactory {
034
035    public static final String LOG_THRESHOLD_PROPERTY
036        = "de.mnl.osgi.lf4osgi.bufferThreshold";
037    public static final String BUFFER_SIZE_PROPERTY
038        = "de.mnl.osgi.lf4osgi.bufferSize";
039    @SuppressWarnings("PMD.LooseCoupling")
040    private final Queue<BufferedEvent> events;
041    private LogLevel threshold = LogLevel.DEBUG;
042    private int bufferSize = 100;
043
044    /**
045     * Instantiates a new buffering logger factory with an
046     * event buffer with given size, buffering only events with
047     * at least the given threshold. 
048     */
049    public BufferingLoggerFactory() {
050        super();
051        this.events = new ConcurrentLinkedQueue<>();
052        AccessController.doPrivileged(new PrivilegedAction<Void>() {
053            @Override
054            public Void run() {
055                threshold = Optional.ofNullable(System
056                    .getProperty(LOG_THRESHOLD_PROPERTY))
057                    .map(LogLevel::valueOf).orElse(LogLevel.TRACE);
058                bufferSize = Optional.ofNullable(System
059                    .getProperty(BUFFER_SIZE_PROPERTY))
060                    .map(Integer::parseInt).orElse(1000);
061                return null;
062            }
063        });
064    }
065
066    /**
067     * Sets the buffer size.
068     *
069     * @param bufferSize the buffer size
070     * @return the buffering logger factory
071     */
072    public BufferingLoggerFactory setBufferSize(int bufferSize) {
073        this.bufferSize = bufferSize;
074        while (events.size() > bufferSize) {
075            events.poll();
076        }
077        return this;
078    }
079
080    /**
081     * Sets the threshold.
082     *
083     * @param threshold the threshold
084     * @return the buffering logger factory
085     */
086    public BufferingLoggerFactory setThreshold(LogLevel threshold) {
087        this.threshold = threshold;
088        return this;
089    }
090
091    public LogLevel threshold() {
092        return threshold;
093    }
094
095    /**
096     * Adds the event, removing the oldest event if the buffer sise is reached.
097     *
098     * @param event the event
099     */
100    public void addEvent(BufferedEvent event) {
101        if (events.size() == bufferSize) {
102            events.poll();
103        }
104        events.add(event);
105    }
106
107    /**
108     * Forward all buffered events.
109     *
110     * @param factory the factory
111     */
112    public void flush(LoggerFactory factory) {
113        while (true) {
114            BufferedEvent event = events.poll();
115            if (event == null) {
116                break;
117            }
118            event.forward(factory);
119        }
120    }
121
122    @Override
123    public Logger getLogger(String name) {
124        throw new UnsupportedOperationException();
125    }
126
127    @Override
128    public Logger getLogger(Class<?> clazz) {
129        throw new UnsupportedOperationException();
130    }
131
132    @Override
133    public <L extends Logger> L getLogger(String name, Class<L> loggerType) {
134        throw new UnsupportedOperationException();
135    }
136
137    @Override
138    public <L extends Logger> L getLogger(Class<?> clazz, Class<L> loggerType) {
139        throw new UnsupportedOperationException();
140    }
141
142    @SuppressWarnings("unchecked")
143    @Override
144    public <L extends Logger> L getLogger(Bundle bundle, String name,
145            Class<L> loggerType) {
146        return (L) new BufferingLogger(this, bundle, name);
147    }
148
149}