Logger.java

1
package com.renomad.minum.logging;
2
3
import com.renomad.minum.state.Constants;
4
import com.renomad.minum.queue.AbstractActionQueue;
5
6
import java.util.EnumMap;
7
import java.util.List;
8
import java.util.Map;
9
import java.util.concurrent.ExecutorService;
10
11
import static com.renomad.minum.utils.TimeUtils.getTimestampIsoInstant;
12
13
/**
14
 * Implementation of {@link ILogger}
15
 */
16
public class Logger implements ILogger {
17
    /**
18
     * The {@link LoggingActionQueue} that handles all
19
     * our messages thread-safely by taking
20
     * them off the top of a queue.
21
     */
22
    protected final AbstractActionQueue loggingActionQueue;
23
    private final Constants constants;
24
    private final ExecutorService executorService;
25
    private final String name;
26
    private final Map<LoggingLevel, Boolean> activeLogLevels;
27
28
    /**
29
     * Constructor
30
     * @param constants used for determining enabled log levels
31
     * @param executorService provides thread handling for the logs, used to
32
     *                        build a {@link LoggingActionQueue}
33
     * @param name sets a name on the {@link LoggingActionQueue} to aid debugging, to
34
     *             help distinguish queues.
35
     */
36
    public Logger(Constants constants, ExecutorService executorService, String name) {
37
        this(constants, executorService, name, null);
38
    }
39
40
    private Logger(Constants constants, ExecutorService executorService, String name, AbstractActionQueue loggingActionQueue) {
41
        this.constants = constants;
42
        this.executorService = executorService;
43
        this.name = name;
44
        // this tricky code exists so that a user has the option to create a class extended
45
        // from this one, and can construct it with the logger instance, making it possible
46
        // to inject the running action queue.  This enables us to continue using the same
47
        // action queue amongst descendant classes.
48 1 1. <init> : negated conditional → KILLED
        if (loggingActionQueue == null) {
49
            this.loggingActionQueue = new LoggingActionQueue("loggerPrinter" + name, executorService, constants).initialize();
50
        } else {
51
            this.loggingActionQueue = loggingActionQueue;
52
        }
53
        activeLogLevels = convertToMap(constants.logLevels);
54
    }
55
56
    /**
57
     * A constructor meant for use by descendant classes
58
     * @param logger an existing instance of a running logger, needed in order to have the
59
     *               descendant logger using the same {@link AbstractActionQueue}, which is
60
     *               necessary so logs don't interleave with each other.
61
     */
62
    public Logger(Logger logger) {
63
        this(logger.constants, logger.executorService, logger.name, logger.loggingActionQueue);
64
    }
65
66
    /**
67
     * Convert the list of enabled log levels to a map of enum -> boolean
68
     */
69
    static Map<LoggingLevel, Boolean> convertToMap(List<LoggingLevel> enabledLoggingLevels) {
70
        Map<LoggingLevel, Boolean> activeLogLevels = new EnumMap<>(LoggingLevel.class);
71
        for (LoggingLevel t : LoggingLevel.values()) {
72
            activeLogLevels.put(t, enabledLoggingLevels.contains(t));
73
        }
74
        // these are set specially - they must always be output, no matter what
75
        // the user prefers, because of their critical importance.
76
        activeLogLevels.put(LoggingLevel.ASYNC_ERROR, true);
77
        activeLogLevels.put(LoggingLevel.WARN, true);
78 1 1. convertToMap : replaced return value with Collections.emptyMap for com/renomad/minum/logging/Logger::convertToMap → TIMED_OUT
        return activeLogLevels;
79
    }
80
81
    @Override
82
    public void logDebug(ThrowingSupplier<String, Exception> msg) {
83
        logHelper(msg, LoggingLevel.DEBUG, activeLogLevels, loggingActionQueue);
84
    }
85
86
    @Override
87
    public void logWarn(ThrowingSupplier<String, Exception> msg) {
88
        logHelper(msg, LoggingLevel.WARN, activeLogLevels, loggingActionQueue);
89
    }
90
91
    @Override
92
    public void logTrace(ThrowingSupplier<String, Exception> msg) {
93
        logHelper(msg, LoggingLevel.TRACE, activeLogLevels, loggingActionQueue);
94
    }
95
96
    @Override
97
    public void logAudit(ThrowingSupplier<String, Exception> msg) {
98
        logHelper(msg, LoggingLevel.AUDIT, activeLogLevels, loggingActionQueue);
99
    }
100
101
    @Override
102
    public void stop() {
103 1 1. stop : removed call to com/renomad/minum/queue/AbstractActionQueue::stop → TIMED_OUT
        this.loggingActionQueue.stop();
104
        this.executorService.shutdownNow();
105
    }
106
107
    @Override
108
    public void logAsyncError(ThrowingSupplier<String, Exception> msg) {
109
        logHelper(msg, LoggingLevel.ASYNC_ERROR, activeLogLevels, loggingActionQueue);
110
    }
111
112
    @Override
113
    public Map<LoggingLevel, Boolean> getActiveLogLevels() {
114 1 1. getActiveLogLevels : replaced return value with Collections.emptyMap for com/renomad/minum/logging/Logger::getActiveLogLevels → KILLED
        return activeLogLevels;
115
    }
116
117
    /**
118
     * A helper method to reduce duplication
119
     */
120
    static void logHelper(
121
            ThrowingSupplier<String, Exception> msg,
122
            LoggingLevel loggingLevel,
123
            Map<LoggingLevel, Boolean> activeLogLevels,
124
            AbstractActionQueue loggingActionQueue
125
            ) {
126 1 1. logHelper : negated conditional → TIMED_OUT
        if (Boolean.TRUE.equals(activeLogLevels.get(loggingLevel))) {
127
        String receivedMessage;
128
            try {
129
                receivedMessage = msg.get();
130
            } catch (Exception ex) {
131
                receivedMessage = "EXCEPTION DURING GET: " + ex;
132
            }
133
            String finalReceivedMessage = receivedMessage;
134 2 1. logHelper : negated conditional → TIMED_OUT
2. logHelper : negated conditional → KILLED
            if (loggingActionQueue == null || loggingActionQueue.isStopped()) {
135
                Object[] args = new Object[]{getTimestampIsoInstant(), loggingLevel.name(), showWhiteSpace(finalReceivedMessage)};
136
                System.out.printf("%s\t%s\t%s%n", args);
137
            } else {
138 1 1. logHelper : removed call to com/renomad/minum/queue/AbstractActionQueue::enqueue → TIMED_OUT
                loggingActionQueue.enqueue("Logger#logHelper(" + receivedMessage + ")", () -> {
139
                    Object[] args = new Object[]{getTimestampIsoInstant(), loggingLevel.name(), showWhiteSpace(finalReceivedMessage)};
140
                    System.out.printf("%s\t%s\t%s%n", args);
141
                });
142
            }
143
        }
144
    }
145
146
    /**
147
     * Given a string that may have whitespace chars, render it in a way we can see
148
     */
149
    static String showWhiteSpace(String msg) {
150 2 1. showWhiteSpace : negated conditional → TIMED_OUT
2. showWhiteSpace : replaced return value with "" for com/renomad/minum/logging/Logger::showWhiteSpace → KILLED
        if (msg == null) return "(NULL)";
151 2 1. showWhiteSpace : negated conditional → TIMED_OUT
2. showWhiteSpace : replaced return value with "" for com/renomad/minum/logging/Logger::showWhiteSpace → KILLED
        if (msg.isEmpty()) return "(EMPTY)";
152
153
        // if we have tabs, returns, newlines in the text, show them
154
        String text = msg
155
                .replace("\t", "\\t")
156
                .replace("\r", "\\r")
157
                .replace("\n", "\\n");
158
159 2 1. showWhiteSpace : negated conditional → KILLED
2. showWhiteSpace : replaced return value with "" for com/renomad/minum/logging/Logger::showWhiteSpace → KILLED
        if (text.isBlank()) return "(BLANK)";
160 1 1. showWhiteSpace : replaced return value with "" for com/renomad/minum/logging/Logger::showWhiteSpace → KILLED
        return text;
161
    }
162
163
}

Mutations

48

1.1
Location : <init>
Killed by : com.renomad.minum.web.PathDetailsTests
negated conditional → KILLED

78

1.1
Location : convertToMap
Killed by : none
replaced return value with Collections.emptyMap for com/renomad/minum/logging/Logger::convertToMap → TIMED_OUT

103

1.1
Location : stop
Killed by : none
removed call to com/renomad/minum/queue/AbstractActionQueue::stop → TIMED_OUT

114

1.1
Location : getActiveLogLevels
Killed by : com.renomad.minum.logging.LoggerTests
replaced return value with Collections.emptyMap for com/renomad/minum/logging/Logger::getActiveLogLevels → KILLED

126

1.1
Location : logHelper
Killed by : none
negated conditional → TIMED_OUT

134

1.1
Location : logHelper
Killed by : com.renomad.minum.logging.LoggerTests
negated conditional → KILLED

2.2
Location : logHelper
Killed by : none
negated conditional → TIMED_OUT

138

1.1
Location : logHelper
Killed by : none
removed call to com/renomad/minum/queue/AbstractActionQueue::enqueue → TIMED_OUT

150

1.1
Location : showWhiteSpace
Killed by : none
negated conditional → TIMED_OUT

2.2
Location : showWhiteSpace
Killed by : com.renomad.minum.logging.LoggerTests
replaced return value with "" for com/renomad/minum/logging/Logger::showWhiteSpace → KILLED

151

1.1
Location : showWhiteSpace
Killed by : com.renomad.minum.logging.LoggerTests
replaced return value with "" for com/renomad/minum/logging/Logger::showWhiteSpace → KILLED

2.2
Location : showWhiteSpace
Killed by : none
negated conditional → TIMED_OUT

159

1.1
Location : showWhiteSpace
Killed by : com.renomad.minum.logging.LoggerTests
negated conditional → KILLED

2.2
Location : showWhiteSpace
Killed by : com.renomad.minum.logging.LoggerTests
replaced return value with "" for com/renomad/minum/logging/Logger::showWhiteSpace → KILLED

160

1.1
Location : showWhiteSpace
Killed by : com.renomad.minum.logging.LoggerTests
replaced return value with "" for com/renomad/minum/logging/Logger::showWhiteSpace → KILLED

Active mutators

Tests examined


Report generated by PIT 1.17.0