1 /*
2 * Oceanus: Java Utilities
3 * Copyright 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
18 package io.github.tonywasher.joceanus.oceanus.logger;
19
20 import io.github.tonywasher.joceanus.oceanus.convert.OceanusDataConverter;
21
22 import java.io.ByteArrayOutputStream;
23 import java.io.PrintStream;
24
25 /**
26 * The log engine.
27 */
28 public class OceanusLogEngine {
29 /**
30 * The data section length.
31 */
32 private static final int DATA_SECTION = 32;
33
34 /**
35 * The data advance.
36 */
37 private static final int DATA_ADVANCE = 3;
38
39 /**
40 * The output stream.
41 */
42 private static OceanusLogSink theSink = new OceanusLogStdOut();
43
44 /**
45 * The initial time.
46 */
47 private final long theTimeZero;
48
49 /**
50 * The constructor.
51 */
52 OceanusLogEngine() {
53 theTimeZero = System.nanoTime();
54 }
55
56 /**
57 * Set Sink.
58 *
59 * @param pSink the sink
60 */
61 static void setSink(final OceanusLogSink pSink) {
62 theSink = pSink;
63 }
64
65 /**
66 * Format message.
67 *
68 * @param pOwner the owner
69 * @param pLevel the log level
70 * @param pMessage the message to format
71 * @return the formatted string
72 */
73 String formatMessage(final Class<?> pOwner,
74 final OceanusLogLevel pLevel,
75 final String pMessage) {
76 return (System.nanoTime() - theTimeZero)
77 + " "
78 + pLevel.name()
79 + ": "
80 + pOwner.getSimpleName()
81 + "- "
82 + pMessage;
83 }
84
85 /**
86 * Format data.
87 *
88 * @param pData the data to format
89 * @return the formatted data
90 */
91 public static String formatData(final byte[] pData) {
92 return pData == null
93 ? "\nnull"
94 : formatData(pData, 0, pData.length);
95 }
96
97 /**
98 * Format data.
99 *
100 * @param pData the data to format
101 * @param pOffset the offset
102 * @param pLength the length of data
103 * @return the formatted data
104 */
105 public static String formatData(final byte[] pData,
106 final int pOffset,
107 final int pLength) {
108 /* Handle null data */
109 if (pData == null) {
110 return "\nnull";
111 }
112
113 /* Handle partial buffer */
114 byte[] myData = pData;
115 if (pOffset != 0 || pLength != pData.length) {
116 myData = new byte[pLength];
117 System.arraycopy(pData, pOffset, myData, 0, pLength);
118 }
119
120 /* Format the data */
121 final String myFormatted = OceanusDataConverter.bytesToHexString(myData);
122
123 /* Place it into StringBuilder buffer */
124 final StringBuilder myBuilder = new StringBuilder();
125 myBuilder.append(myFormatted);
126
127 /* Loop through the data */
128 int myOffSet = 0;
129 for (int i = 0; i < pLength; i++) {
130 /* Insert blank/newLine between each HexPair */
131 final char myChar = (i % DATA_SECTION) == 0 ? '\n' : ' ';
132 myBuilder.insert(myOffSet, myChar);
133 myOffSet += DATA_ADVANCE;
134 }
135
136 /* Return the data */
137 return myBuilder.toString();
138 }
139
140 /**
141 * Write log message.
142 *
143 * @param pMessage the message to format
144 */
145 void writeLogMessage(final String pMessage) {
146 synchronized (this) {
147 theSink.writeLogMessage(pMessage);
148 }
149 }
150
151 /**
152 * Write log message and exception.
153 *
154 * @param pMessage the message to format
155 * @param pException the exception
156 */
157 void writeLogMessage(final String pMessage,
158 final Throwable pException) {
159 synchronized (this) {
160 theSink.writeLogMessage(pMessage);
161 final ByteArrayOutputStream myBaos = new ByteArrayOutputStream();
162 try (PrintStream myPs = new PrintStream(myBaos)) {
163 if (pException != null) {
164 pException.printStackTrace(myPs);
165 } else {
166 myPs.println("Null Exception");
167 }
168 theSink.writeLogMessage(myBaos.toString());
169 }
170 }
171 }
172
173 /**
174 * Default Log Sink.
175 */
176 static final class OceanusLogStdOut
177 implements OceanusLogSink {
178 /**
179 * The output stream.
180 */
181 private final PrintStream theOutput = System.out;
182
183 /**
184 * Constructor.
185 */
186 private OceanusLogStdOut() {
187 }
188
189 @Override
190 public void writeLogMessage(final String pMessage) {
191 theOutput.println(pMessage);
192 }
193 }
194 }