View Javadoc
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 }