1 /*
2 * Oceanus: Java Utilities
3 * Copyright 2012-2026. Tony Washer
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
6 * use this file except in compliance with the License. You may obtain a copy
7 * of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14 * License for the specific language governing permissions and limitations under
15 * the License.
16 */
17 package io.github.tonywasher.joceanus.oceanus.logger;
18
19 import io.github.tonywasher.joceanus.oceanus.convert.OceanusDataConverter;
20
21 import java.io.ByteArrayOutputStream;
22 import java.io.PrintStream;
23
24 /**
25 * Log Manager.
26 */
27 public final class OceanusLogManager {
28 /**
29 * The data section length.
30 */
31 private static final int DATA_SECTION = 32;
32
33 /**
34 * The data advance.
35 */
36 private static final int DATA_ADVANCE = 3;
37
38 /**
39 * The output stream.
40 */
41 private static OceanusLogSink theSink = new OceanusLogStdOut();
42
43 /**
44 * The initial time.
45 */
46 private final long theTimeZero;
47
48 /**
49 * The constructor.
50 */
51 private OceanusLogManager() {
52 theTimeZero = System.nanoTime();
53 }
54
55 /**
56 * Obtain the singleton instance.
57 *
58 * @return the instance.
59 */
60 private static OceanusLogManager getInstance() {
61 return OceanusLogManagerHelper.INSTANCE;
62 }
63
64 /**
65 * Obtain a logger.
66 *
67 * @param pOwner the owning class
68 * @return the logger
69 */
70 public static OceanusLogger getLogger(final Class<?> pOwner) {
71 return new OceanusLogger(getInstance(), pOwner);
72 }
73
74 /**
75 * Set Sink.
76 *
77 * @param pSink the sink
78 */
79 public static void setSink(final OceanusLogSink pSink) {
80 theSink = pSink;
81 }
82
83 /**
84 * Format message.
85 *
86 * @param pOwner the owner
87 * @param pLevel the log level
88 * @param pMessage the message to format
89 * @return the formatted string
90 */
91 String formatMessage(final Class<?> pOwner,
92 final OceanusLogLevel pLevel,
93 final String pMessage) {
94 return (System.nanoTime() - theTimeZero)
95 + " "
96 + pLevel.name()
97 + ": "
98 + pOwner.getSimpleName()
99 + "- "
100 + pMessage;
101 }
102
103 /**
104 * Format data.
105 *
106 * @param pData the data to format
107 * @return the formatted data
108 */
109 public static String formatData(final byte[] pData) {
110 return pData == null
111 ? "\nnull"
112 : formatData(pData, 0, pData.length);
113 }
114
115 /**
116 * Format data.
117 *
118 * @param pData the data to format
119 * @param pOffset the offset
120 * @param pLength the length of data
121 * @return the formatted data
122 */
123 public static String formatData(final byte[] pData,
124 final int pOffset,
125 final int pLength) {
126 /* Handle null data */
127 if (pData == null) {
128 return "\nnull";
129 }
130
131 /* Handle partial buffer */
132 byte[] myData = pData;
133 if (pOffset != 0 || pLength != pData.length) {
134 myData = new byte[pLength];
135 System.arraycopy(pData, pOffset, myData, 0, pLength);
136 }
137
138 /* Format the data */
139 final String myFormatted = OceanusDataConverter.bytesToHexString(myData);
140
141 /* Place it into StringBuilder buffer */
142 final StringBuilder myBuilder = new StringBuilder();
143 myBuilder.append(myFormatted);
144
145 /* Loop through the data */
146 int myOffSet = 0;
147 for (int i = 0; i < pLength; i++) {
148 /* Insert blank/newLine between each HexPair */
149 final char myChar = (i % DATA_SECTION) == 0 ? '\n' : ' ';
150 myBuilder.insert(myOffSet, myChar);
151 myOffSet += DATA_ADVANCE;
152 }
153
154 /* Return the data */
155 return myBuilder.toString();
156 }
157
158 /**
159 * Write log message.
160 *
161 * @param pMessage the message to format
162 */
163 void writeLogMessage(final String pMessage) {
164 synchronized (this) {
165 theSink.writeLogMessage(pMessage);
166 }
167 }
168
169 /**
170 * Write log message and exception.
171 *
172 * @param pMessage the message to format
173 * @param pException the exception
174 */
175 void writeLogMessage(final String pMessage,
176 final Throwable pException) {
177 synchronized (this) {
178 theSink.writeLogMessage(pMessage);
179 final ByteArrayOutputStream myBaos = new ByteArrayOutputStream();
180 try (PrintStream myPs = new PrintStream(myBaos)) {
181 if (pException != null) {
182 pException.printStackTrace(myPs);
183 } else {
184 myPs.println("Null Exception");
185 }
186 theSink.writeLogMessage(myBaos.toString());
187 }
188 }
189 }
190
191 /**
192 * Log Manager Helper.
193 */
194 private static final class OceanusLogManagerHelper {
195 /**
196 * The Log Manager instance.
197 */
198 private static final OceanusLogManager INSTANCE = new OceanusLogManager();
199 }
200
201 /**
202 * Default Log Sink.
203 */
204 static final class OceanusLogStdOut
205 implements OceanusLogSink {
206 /**
207 * The output stream.
208 */
209 private final PrintStream theOutput = System.out;
210
211 /**
212 * Constructor.
213 */
214 private OceanusLogStdOut() {
215 }
216
217 @Override
218 public void writeLogMessage(final String pMessage) {
219 theOutput.println(pMessage);
220 }
221 }
222 }