Kernel/Debug - Fix normal log lines to be printed in one go
[tpg/acess2.git] / KernelLand / Kernel / logging.c
1 /*
2  * Acess 2 Kernel
3  * - By John Hodge (thePowersGang)
4  *
5  * logging.c - Kernel Logging Service
6  */
7 #include <acess.h>
8 #include <adt.h>
9
10 #define CACHE_MESSAGES  0
11 #define PRINT_ON_APPEND 1
12 #define USE_RING_BUFFER 1
13 #define RING_BUFFER_SIZE        4096
14
15 // === CONSTANTS ===
16 enum eLogLevels
17 {
18         LOG_LEVEL_KPANIC,
19         LOG_LEVEL_PANIC,
20         LOG_LEVEL_FATAL,
21         LOG_LEVEL_ERROR,
22         LOG_LEVEL_WARNING,
23         LOG_LEVEL_NOTICE,
24         LOG_LEVEL_LOG,
25         LOG_LEVEL_DEBUG,
26         NUM_LOG_LEVELS
27 };
28 const char      *csaLevelColours[] = {
29                 "\x1B[35m", "\x1B[34m", "\x1B[36m", "\x1B[31m",
30                 "\x1B[33m", "\x1B[32m", "\x1B[0m", "\x1B[0m"
31                 };
32 const char      *csaLevelCodes[] =  {
33                 "k","p","f","e",
34                 "w","n","l","d"
35                 };
36
37 // === TYPES ===
38 typedef struct sLogEntry
39 {
40         struct sLogEntry        *Next;
41         struct sLogEntry        *LevelNext;
42         Sint64  Time;
43          int    Level;
44          int    Length;
45         char    Ident[9];
46         char    Data[];
47 }       tLogEntry;
48 typedef struct sLogList
49 {
50         tLogEntry       *Head;
51         tLogEntry       *Tail;
52 }       tLogList;
53
54 // === PROTOTYPES ===
55 void    Log_AddEvent(const char *Ident, int Level, const char *Format, va_list Args);
56 static void     Log_Int_PrintMessage(tLogEntry *Entry);
57 //void  Log_KernelPanic(const char *Ident, const char *Message, ...);
58 //void  Log_Panic(const char *Ident, const char *Message, ...);
59 //void  Log_Error(const char *Ident, const char *Message, ...);
60 //void  Log_Warning(const char *Ident, const char *Message, ...);
61 //void  Log_Notice(const char *Ident, const char *Message, ...);
62 //void  Log_Log(const char *Ident, const char *Message, ...);
63 //void  Log_Debug(const char *Ident, const char *Message, ...);
64
65 // === EXPORTS ===
66 EXPORT(Log_Panic);
67 EXPORT(Log_Error);
68 EXPORT(Log_Warning);
69 EXPORT(Log_Notice);
70 EXPORT(Log_Log);
71 EXPORT(Log_Debug);
72
73 // === GLOBALS ===
74 tShortSpinlock  glLogOutput;
75 #if CACHE_MESSAGES
76 # if USE_RING_BUFFER
77 Uint8   gaLog_RingBufferData[sizeof(tRingBuffer)+RING_BUFFER_SIZE];
78 tRingBuffer     *gpLog_RingBuffer = (void*)gaLog_RingBufferData;
79 # else
80 tMutex  glLog;
81 tLogList        gLog;
82 tLogList        gLog_Levels[NUM_LOG_LEVELS];
83 # endif // USE_RING_BUFFER
84 #endif // CACHE_MESSAGES
85
86 // === CODE ===
87 /**
88  * \brief Adds an event to the log
89  */
90 void Log_AddEvent(const char *Ident, int Level, const char *Format, va_list Args)
91 {
92          int    len;
93         tLogEntry       *ent;
94         va_list args_tmp;
95         
96         if( Level >= NUM_LOG_LEVELS )   return;
97
98         va_copy(args_tmp, Args);
99         len = vsnprintf(NULL, 0, Format, args_tmp);
100         
101         #if USE_RING_BUFFER || !CACHE_MESSAGES
102         {
103         char    buf[sizeof(tLogEntry)+len+1];
104         ent = (void*)buf;
105         #else
106         ent = malloc(sizeof(tLogEntry)+len+1);
107         #endif
108         ent->Time = now();
109         strncpy(ent->Ident, Ident, 8);
110         ent->Ident[8] = '\0';
111         ent->Level = Level;
112         ent->Length = len;
113         vsnprintf( ent->Data, len+1, Format, Args );
114
115         #if CACHE_MESSAGES
116         # if USE_RING_BUFFER
117         {
118                 #define LOG_HDR_LEN     (14+1+2+8+2)
119                 char    newData[ LOG_HDR_LEN + len + 2 + 1 ];
120                 sprintf( newData, "%014lli%s [%-8.8s] ",
121                         ent->Time, csaLevelCodes[Level], Ident);
122                 strcpy( newData + LOG_HDR_LEN, ent->Data );
123                 strcpy( newData + LOG_HDR_LEN + len, "\r\n" );
124                 gpLog_RingBuffer->Space = RING_BUFFER_SIZE;     // Needed to init the buffer
125                 RingBuffer_Write( gpLog_RingBuffer, newData, LOG_HDR_LEN + len + 2 );
126         }
127         # else
128         Mutex_Acquire( &glLog );
129         
130         ent->Next = gLog.Tail;
131         tLogEntry       **pnp = (gLog.Tail ? &gLog.Tail->Next : &gLog.Head);
132         *pnp = ent;
133         gLog.Tail = ent;
134         
135         ent->LevelNext = gLog_Levels[Level].Tail;
136         pnp = (gLog_Levels[Level].Tail ? &gLog_Levels[Level].Tail->LevelNext : &gLog_Levels[Level].Head);
137         *pnp = ent;
138         gLog_Levels[Level].Tail = ent;
139         
140         Mutex_Release( &glLog );
141         # endif
142         #endif
143         
144         #if PRINT_ON_APPEND || !CACHE_MESSAGES
145         Log_Int_PrintMessage( ent );
146         #endif
147         
148         #if USE_RING_BUFFER || !CACHE_MESSAGES
149         }
150         #endif
151 }
152
153 /**
154  * \brief Prints a log message to the debug console
155  */
156 void Log_Int_PrintMessage(tLogEntry *Entry)
157 {
158         if( CPU_HAS_LOCK(&glLogOutput) )
159                 return ;        // TODO: Error?
160         SHORTLOCK( &glLogOutput );
161         bool completed = LogF(
162                 "%s%014lli%s [%-8s] %i - %.*s\x1B[0m\r\n",
163                 csaLevelColours[Entry->Level],
164                 Entry->Time,
165                 csaLevelCodes[Entry->Level],
166                 Entry->Ident,
167                 Threads_GetTID(),
168                 Entry->Length,
169                 Entry->Data
170                 );
171         if( !completed )
172                 LogF("\x1B[0m\r\n");    // Separate in case Entry->Data is too long
173         SHORTREL( &glLogOutput );
174 }
175
176 /**
177  * \brief KERNEL PANIC!!!!
178  */
179 void Log_KernelPanic(const char *Ident, const char *Message, ...)
180 {
181         va_list args;   
182         va_start(args, Message);
183         Log_AddEvent(Ident, LOG_LEVEL_KPANIC, Message, args);
184         va_end(args);
185         Panic("Log_KernelPanic - %s", Ident);
186 }
187
188 /**
189  * \brief Panic Message - Driver Unrecoverable error
190  */
191 void Log_Panic(const char *Ident, const char *Message, ...)
192 {
193         va_list args;   
194         va_start(args, Message);
195         Log_AddEvent(Ident, LOG_LEVEL_PANIC, Message, args);
196         va_end(args);
197 }
198
199 /**
200  * \brief Error Message - Recoverable Error
201  */
202 void Log_Error(const char *Ident, const char *Message, ...)
203 {
204         va_list args;   
205         va_start(args, Message);
206         Log_AddEvent(Ident, LOG_LEVEL_ERROR, Message, args);
207         va_end(args);
208 }
209
210 /**
211  * \brief Warning Message - Something the user should know
212  */
213 void Log_Warning(const char *Ident, const char *Message, ...)
214 {
215         va_list args;
216         
217         va_start(args, Message);
218         Log_AddEvent(Ident, LOG_LEVEL_WARNING, Message, args);
219         va_end(args);
220 }
221
222 /**
223  * \brief Notice Message - Something the user might like to know
224  */
225 void Log_Notice(const char *Ident, const char *Message, ...)
226 {
227         va_list args;   
228         va_start(args, Message);
229         Log_AddEvent(Ident, LOG_LEVEL_NOTICE, Message, args);
230         va_end(args);
231 }
232
233 /**
234  * \brief Log Message - Possibly useful information
235  */
236 void Log_Log(const char *Ident, const char *Message, ...)
237 {
238         va_list args;   
239         va_start(args, Message);
240         Log_AddEvent(Ident, LOG_LEVEL_LOG, Message, args);
241         va_end(args);
242 }
243
244 /**
245  * \brief Debug Message - Only a developer would want this info
246  */
247 void Log_Debug(const char *Ident, const char *Message, ...)
248 {
249         va_list args;   
250         va_start(args, Message);
251         Log_AddEvent(Ident, LOG_LEVEL_DEBUG, Message, args);
252         va_end(args);
253 }

UCC git Repository :: git.ucc.asn.au