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 |
1
1. convertToMap : replaced return value with Collections.emptyMap for com/renomad/minum/logging/Logger::convertToMap → KILLED |
return activeLogLevels; |
75 | } | |
76 | ||
77 | @Override | |
78 | public void logDebug(ThrowingSupplier<String, Exception> msg) { | |
79 | logHelper(msg, LoggingLevel.DEBUG, activeLogLevels, loggingActionQueue); | |
80 | } | |
81 | ||
82 | @Override | |
83 | public void logTrace(ThrowingSupplier<String, Exception> msg) { | |
84 | logHelper(msg, LoggingLevel.TRACE, activeLogLevels, loggingActionQueue); | |
85 | } | |
86 | ||
87 | @Override | |
88 | public void logAudit(ThrowingSupplier<String, Exception> msg) { | |
89 | logHelper(msg, LoggingLevel.AUDIT, activeLogLevels, loggingActionQueue); | |
90 | } | |
91 | ||
92 | @Override | |
93 | public void stop() { | |
94 |
1
1. stop : removed call to com/renomad/minum/queue/AbstractActionQueue::stop → TIMED_OUT |
this.loggingActionQueue.stop(); |
95 | this.executorService.shutdownNow(); | |
96 | } | |
97 | ||
98 | @Override | |
99 | public void logAsyncError(ThrowingSupplier<String, Exception> msg) { | |
100 | logHelper(msg, LoggingLevel.ASYNC_ERROR, activeLogLevels, loggingActionQueue); | |
101 | } | |
102 | ||
103 | @Override | |
104 | public Map<LoggingLevel, Boolean> getActiveLogLevels() { | |
105 |
1
1. getActiveLogLevels : replaced return value with Collections.emptyMap for com/renomad/minum/logging/Logger::getActiveLogLevels → KILLED |
return activeLogLevels; |
106 | } | |
107 | ||
108 | /** | |
109 | * A helper method to reduce duplication | |
110 | */ | |
111 | static void logHelper( | |
112 | ThrowingSupplier<String, Exception> msg, | |
113 | LoggingLevel loggingLevel, | |
114 | Map<LoggingLevel, Boolean> activeLogLevels, | |
115 | AbstractActionQueue loggingActionQueue | |
116 | ) { | |
117 |
1
1. logHelper : negated conditional → KILLED |
if (Boolean.TRUE.equals(activeLogLevels.get(loggingLevel))) { |
118 | String receivedMessage; | |
119 | try { | |
120 | receivedMessage = msg.get(); | |
121 | } catch (Exception ex) { | |
122 | receivedMessage = "EXCEPTION DURING GET: " + ex; | |
123 | } | |
124 | String finalReceivedMessage = receivedMessage; | |
125 |
2
1. logHelper : negated conditional → TIMED_OUT 2. logHelper : negated conditional → TIMED_OUT |
if (loggingActionQueue == null || loggingActionQueue.isStopped()) { |
126 | Object[] args = new Object[]{getTimestampIsoInstant(), loggingLevel.name(), showWhiteSpace(finalReceivedMessage)}; | |
127 | System.out.printf("%s\t%s\t%s%n", args); | |
128 | } else { | |
129 |
1
1. logHelper : removed call to com/renomad/minum/queue/AbstractActionQueue::enqueue → TIMED_OUT |
loggingActionQueue.enqueue("Logger#logHelper(" + receivedMessage + ")", () -> { |
130 | Object[] args = new Object[]{getTimestampIsoInstant(), loggingLevel.name(), showWhiteSpace(finalReceivedMessage)}; | |
131 | System.out.printf("%s\t%s\t%s%n", args); | |
132 | }); | |
133 | } | |
134 | } | |
135 | } | |
136 | ||
137 | /** | |
138 | * Given a string that may have whitespace chars, render it in a way we can see | |
139 | */ | |
140 | static String showWhiteSpace(String msg) { | |
141 |
2
1. showWhiteSpace : negated conditional → KILLED 2. showWhiteSpace : replaced return value with "" for com/renomad/minum/logging/Logger::showWhiteSpace → KILLED |
if (msg == null) return "(NULL)"; |
142 |
2
1. showWhiteSpace : replaced return value with "" for com/renomad/minum/logging/Logger::showWhiteSpace → KILLED 2. showWhiteSpace : negated conditional → KILLED |
if (msg.isEmpty()) return "(EMPTY)"; |
143 | ||
144 | // if we have tabs, returns, newlines in the text, show them | |
145 | String text = msg | |
146 | .replace("\t", "\\t") | |
147 | .replace("\r", "\\r") | |
148 | .replace("\n", "\\n"); | |
149 | ||
150 |
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)"; |
151 |
1
1. showWhiteSpace : replaced return value with "" for com/renomad/minum/logging/Logger::showWhiteSpace → KILLED |
return text; |
152 | } | |
153 | ||
154 | } | |
Mutations | ||
48 |
1.1 |
|
74 |
1.1 |
|
94 |
1.1 |
|
105 |
1.1 |
|
117 |
1.1 |
|
125 |
1.1 2.2 |
|
129 |
1.1 |
|
141 |
1.1 2.2 |
|
142 |
1.1 2.2 |
|
150 |
1.1 2.2 |
|
151 |
1.1 |