1 martin 1.66 //%LICENSE////////////////////////////////////////////////////////////////
|
2 martin 1.67 //
|
3 martin 1.66 // Licensed to The Open Group (TOG) under one or more contributor license
4 // agreements. Refer to the OpenPegasusNOTICE.txt file distributed with
5 // this work for additional information regarding copyright ownership.
6 // Each contributor licenses this file to you under the OpenPegasus Open
7 // Source License; you may not use this file except in compliance with the
8 // License.
|
9 martin 1.67 //
|
10 martin 1.66 // Permission is hereby granted, free of charge, to any person obtaining a
11 // copy of this software and associated documentation files (the "Software"),
12 // to deal in the Software without restriction, including without limitation
13 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
14 // and/or sell copies of the Software, and to permit persons to whom the
15 // Software is furnished to do so, subject to the following conditions:
|
16 martin 1.67 //
|
17 martin 1.66 // The above copyright notice and this permission notice shall be included
18 // in all copies or substantial portions of the Software.
|
19 martin 1.67 //
|
20 martin 1.66 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
21 martin 1.67 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
22 martin 1.66 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23 // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24 // CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
25 // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
26 // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
27 martin 1.67 //
|
28 martin 1.66 //////////////////////////////////////////////////////////////////////////
|
29 mike 1.13 //
30 //%/////////////////////////////////////////////////////////////////////////////
31
32 #include <iostream>
33 #include <fstream>
|
34 kumpf 1.23 #include <cstring>
|
35 mreddy 1.55 #include <Pegasus/Common/Logger.h>
|
36 marek 1.59 #include <Pegasus/Common/Tracer.h>
|
37 mreddy 1.55 #include <Pegasus/Common/System.h>
38 #include <Pegasus/Common/FileSystem.h>
|
39 kumpf 1.48 #include <Pegasus/Common/MessageLoader.h>
|
40 kumpf 1.54 #include <Pegasus/Common/Executor.h>
|
41 mreddy 1.55 #include <Pegasus/Common/Mutex.h>
|
42 kumpf 1.16
|
43 marek 1.47 #if defined(PEGASUS_USE_SYSLOGS)
44 # include <syslog.h>
45 #endif
46
|
47 mike 1.13 PEGASUS_USING_STD;
48
49 PEGASUS_NAMESPACE_BEGIN
50
|
51 mreddy 1.55
|
52 mike 1.13 const Uint32 Logger::TRACE = (1 << 0);
53 const Uint32 Logger::INFORMATION = (1 << 1);
54 const Uint32 Logger::WARNING = (1 << 2);
55 const Uint32 Logger::SEVERE = (1 << 3);
56 const Uint32 Logger::FATAL = (1 << 4);
57
|
58 david 1.26 static char const* LOGLEVEL_LIST[] =
59 {
60 "TRACE",
61 "INFORMATION",
62 "WARNING",
63 "SEVERE",
64 "FATAL"
65 };
66
|
67 mike 1.13 LoggerRep* Logger::_rep = 0;
68 String Logger::_homeDirectory = ".";
|
69 kumpf 1.16
|
70 david 1.26 const Uint32 Logger::_NUM_LOGLEVEL = 5;
71
|
72 kumpf 1.57 Uint32 Logger::_severityMask;
|
73 david 1.26
|
74 mreddy 1.65
|
75 kumpf 1.57 ///////////////////////////////////////////////////////////////////////////////
76 //
77 // LoggerRep
78 //
79 ///////////////////////////////////////////////////////////////////////////////
|
80 kumpf 1.16
|
81 kumpf 1.57 #if defined(PEGASUS_USE_SYSLOGS)
|
82 mike 1.13
|
83 kumpf 1.57 class LoggerRep
84 {
85 public:
|
86 david 1.26
|
87 marek 1.70 LoggerRep(const String&)
|
88 mike 1.13 {
|
89 kumpf 1.57 # ifdef PEGASUS_OS_ZOS
90 logIdentity = strdup(System::CIMSERVER.getCString());
91 // If System Log is used open it
92 System::openlog(logIdentity, LOG_PID, LOG_DAEMON);
93 # endif
94 }
|
95 mike 1.13
|
96 kumpf 1.57 ~LoggerRep()
97 {
98 # ifdef PEGASUS_OS_ZOS
99 System::closelog();
100 free(logIdentity);
101 # endif
102 }
|
103 mike 1.13
|
104 kumpf 1.57 // Actual logging is done in this routine
|
105 marek 1.70 void log(Logger::LogFileType,
|
106 kumpf 1.57 const String& systemId,
107 Uint32 logLevel,
108 const String localizedMsg)
109 {
110 // Log the message
111 System::syslog(systemId, logLevel, localizedMsg.getCString());
112 }
113
114 private:
115
116 # ifdef PEGASUS_OS_ZOS
117 char* logIdentity;
118 # endif
119 };
120
121 #else // !defined(PEGASUS_USE_SYSLOGS)
122
123 static const char* fileNames[] =
124 {
125 "PegasusTrace.log",
126 "PegasusStandard.log",
127 kumpf 1.57 "PegasusAudit.log",
|
128 ouyang.jian 1.60 "PegasusError.log"
|
129 kumpf 1.57 };
130 static const char* lockFileName = "PegasusLog.lock";
131
132 /*
133 _constructFileName builds the absolute file name from homeDirectory
|
134 mreddy 1.55 and fileName.
135 */
136 static CString _constructFileName(
137 const String& homeDirectory,
138 const char * fileName)
139 {
|
140 mike 1.13 String result;
|
141 kumpf 1.57 result.reserveCapacity(
142 (Uint32)(homeDirectory.size() + 1 + strlen(fileName)));
|
143 kumpf 1.20 result.append(homeDirectory);
144 result.append('/');
|
145 mreddy 1.55 result.append(fileName);
|
146 kumpf 1.22 return result.getCString();
|
147 mike 1.13 }
148
149 class LoggerRep
150 {
151 public:
152
153 LoggerRep(const String& homeDirectory)
154 {
|
155 kumpf 1.40 // Add test for home directory set.
|
156 mike 1.13
|
157 kumpf 1.40 // If home directory does not exist, create it.
158 CString lgDir = homeDirectory.getCString();
|
159 mike 1.13
|
160 kumpf 1.40 if (!System::isDirectory(lgDir))
161 System::makeDirectory(lgDir);
|
162 mike 1.13
|
163 kumpf 1.40 // KS: I put the second test in just in case some trys to create
164 // a completly erronous directory. At least we will get a message
|
165 kumpf 1.48 if (!System::isDirectory(lgDir))
166 {
167 MessageLoaderParms parms("Common.Logger.LOGGING_DISABLED",
168 "Logging Disabled");
|
169 kumpf 1.40
|
170 kumpf 1.48 cerr << MessageLoader::getMessage(parms);
|
171 kumpf 1.40 }
172
|
173 mreddy 1.55 //Filelocks are not used for VMS
|
174 kumpf 1.57 # if !defined(PEGASUS_OS_VMS)
|
175 mreddy 1.55 _loggerLockFileName = _constructFileName(homeDirectory, lockFileName);
176
177 // Open and close a file to make sure that the file exists, on which
178 // file lock is requested
179 FILE *fileLockFilePointer;
180 fileLockFilePointer = fopen(_loggerLockFileName, "a+");
181 if(fileLockFilePointer)
182 {
183 fclose(fileLockFilePointer);
184 }
|
185 kumpf 1.57 # endif
|
186 mreddy 1.55
187 _logFileNames[Logger::TRACE_LOG] = _constructFileName(homeDirectory,
188 fileNames[Logger::TRACE_LOG]);
|
189 kumpf 1.40
|
190 mreddy 1.55 _logFileNames[Logger::STANDARD_LOG] = _constructFileName(homeDirectory,
191 fileNames[Logger::STANDARD_LOG]);
|
192 kumpf 1.40
|
193 kumpf 1.57 # ifdef PEGASUS_ENABLE_AUDIT_LOGGER
|
194 mreddy 1.55 _logFileNames[Logger::AUDIT_LOG] = _constructFileName(homeDirectory,
195 fileNames[Logger::AUDIT_LOG]);
|
196 kumpf 1.57 # endif
|
197 thilo.boehm 1.46
|
198 mreddy 1.55 _logFileNames[Logger::ERROR_LOG] = _constructFileName(homeDirectory,
199 fileNames[Logger::ERROR_LOG]);
|
200 marek 1.47 }
201
202 ~LoggerRep()
203 {
|
204 mreddy 1.55 }
205
206 // Actual logging is done in this routine
207 void log(Logger::LogFileType logFileType,
208 const String& systemId,
209 Uint32 logLevel,
|
210 dl.meetei 1.71 const String &localizedMsg)
|
211 mreddy 1.55 {
212 // Prepend the systemId to the incoming message
213 String messageString(systemId);
214 messageString.append(": ");
215 messageString.append(localizedMsg); // l10n
|
216 marek 1.47
|
217 mreddy 1.55 // Get the logLevel String
218 // This converts bitmap to string based on highest order
219 // bit set
220 // ATTN: KS Fix this more efficiently.
221 const char* tmp = "";
222 if (logLevel & Logger::TRACE) tmp = "TRACE ";
223 if (logLevel & Logger::INFORMATION) tmp = "INFO ";
224 if (logLevel & Logger::WARNING) tmp = "WARNING ";
225 if (logLevel & Logger::SEVERE) tmp = "SEVERE ";
226 if (logLevel & Logger::FATAL) tmp = "FATAL ";
|
227 mike 1.13
|
228 mreddy 1.55 # ifndef PEGASUS_OS_VMS
|
229 kumpf 1.68 // Acquire AutoMutex (for thread sync)
|
230 mreddy 1.55 // and AutoFileLock (for Process Sync).
231 AutoMutex am(_mutex);
232 AutoFileLock fileLock(_loggerLockFileName);
233
234 Uint32 logFileSize = 0;
235
236 // Read logFileSize to check if the logfile needs to be pruned.
|
237 kumpf 1.68 FileSystem::getFileSize(String(_logFileNames[logFileType]),
|
238 mreddy 1.55 logFileSize);
239
|
240 mreddy 1.65 // Check if the size of the logfile is exceeding _maxLogFileSizeBytes.
241 if ( logFileSize > _maxLogFileSizeBytes)
|
242 kumpf 1.57 {
|
243 mreddy 1.55 // Prepare appropriate file name based on the logFileType.
244 // Eg: if Logfile name is PegasusStandard.log, pruned logfile name
245 // will be PegasusStandard-062607-122302.log,where 062607-122302
246 // is the time stamp.
247 String prunedLogfile(_logFileNames[logFileType],
248 (Uint32)strlen(_logFileNames[logFileType]) - 4);
249 prunedLogfile.append('-');
250
251 // Get timestamp,remove illegal chars in file name'/' and ':'
252 // (: is illegal Open VMS) from the time stamp. Append the time
253 // info to the file name.
|
254 mike 1.13
|
255 mreddy 1.55 String timeStamp = System::getCurrentASCIITime();
|
256 ajay.rao 1.69 for ( unsigned int i = 0; i < timeStamp.size(); i++ )
|
257 mreddy 1.55 {
|
258 ajay.rao 1.69 if( timeStamp[i] == '/' || timeStamp[i] == ':')
|
259 mreddy 1.55 {
260 timeStamp.remove(i, 1);
261 }
262 }
263 prunedLogfile.append(timeStamp);
|
264 mike 1.13
|
265 mreddy 1.55 // Append '.log' to the file
266 prunedLogfile.append( ".log");
|
267 mike 1.13
|
268 mreddy 1.55 // Rename the logfile
269 FileSystem::renameFile(String(_logFileNames[logFileType]),
270 prunedLogfile);
271
272 } // Check if the logfile needs to be pruned.
273 # endif // ifndef PEGASUS_OS_VMS
274
275 // Open Logfile. Based on the value of logFileType, one of the five
276 // Logfiles will be opened.
277 ofstream logFileStream;
278 logFileStream.open(_logFileNames[logFileType], ios::app);
279 logFileStream << System::getCurrentASCIITime()
280 << " " << tmp << (const char *)messageString.getCString() << endl;
281 logFileStream.close();
|
282 mike 1.13 }
283
|
284 mreddy 1.65 static void setMaxLogFileSize(Uint32 maxLogFileSizeBytes)
285 {
286 _maxLogFileSizeBytes = maxLogFileSizeBytes;
287 }
|
288 mike 1.13 private:
289
|
290 mreddy 1.55 CString _logFileNames[int(Logger::NUM_LOGS)];
|
291 kumpf 1.57
|
292 mreddy 1.65 static Uint32 _maxLogFileSizeBytes;
|
293 kumpf 1.57 # ifndef PEGASUS_OS_VMS
|
294 mreddy 1.55 CString _loggerLockFileName;
295 Mutex _mutex;
|
296 kumpf 1.57 # endif
|
297 mike 1.13 };
298
|
299 mreddy 1.65 Uint32 LoggerRep::_maxLogFileSizeBytes;
300
|
301 kumpf 1.57 #endif // !defined(PEGASUS_USE_SYSLOGS)
302
303
304 ///////////////////////////////////////////////////////////////////////////////
305 //
306 // Logger
307 //
308 ///////////////////////////////////////////////////////////////////////////////
309
|
310 david 1.26 void Logger::_putInternal(
|
311 mike 1.13 LogFileType logFileType,
312 const String& systemId,
|
313 david 1.26 Uint32 logLevel,
|
314 kumpf 1.63 const String& message)
|
315 mike 1.13 {
|
316 kumpf 1.63 if (!_rep)
317 _rep = new LoggerRep(_homeDirectory);
|
318 chuck 1.29
|
319 kumpf 1.63 // Call the actual logging routine is in LoggerRep.
320 _rep->log(logFileType, systemId, logLevel, message);
|
321 kumpf 1.68
|
322 thilo.boehm 1.64 // PEP 315
323 // The trace can be routed into the log. The logged trace messages are
|
324 kumpf 1.68 // logged with logFileType of Logger::TRACE_LOG.
|
325 thilo.boehm 1.64 // To avoid a cirular writing of these messages, log messages with
326 // logFileType of Logger::TRACE_LOG are never send to the trace.
|
327 kumpf 1.63 if (Logger::TRACE_LOG != logFileType)
328 {
|
329 thilo.boehm 1.64 // For all other logFileType's send the log messages to the trace.
330 // But do not write log messages to trace when the trace facility is
331 // set to log. This avoids double messages.
|
332 kumpf 1.63 if (Tracer::TRACE_FACILITY_LOG != Tracer::getTraceFacility())
333 {
334 PEG_TRACE_CSTRING(
335 TRC_LOGMSG,
336 Tracer::LEVEL1,
337 (const char*) message.getCString());
|
338 kumpf 1.40 }
|
339 david 1.26 }
340 }
|
341 mike 1.13
|
342 mike 1.42 ////////////////////////////////////////////////////////////////////////////////
343 //
344 // Public methods start here:
345 //
346 ////////////////////////////////////////////////////////////////////////////////
347
|
348 david 1.26 void Logger::put(
|
349 kumpf 1.40 LogFileType logFileType,
350 const String& systemId,
351 Uint32 logLevel,
352 const String& formatString,
353 const Formatter::Arg& arg0,
354 const Formatter::Arg& arg1,
355 const Formatter::Arg& arg2,
356 const Formatter::Arg& arg3,
357 const Formatter::Arg& arg4,
358 const Formatter::Arg& arg5,
359 const Formatter::Arg& arg6,
360 const Formatter::Arg& arg7,
361 const Formatter::Arg& arg8,
362 const Formatter::Arg& arg9)
|
363 chuck 1.29 {
|
364 mike 1.42 if (wouldLog(logLevel))
365 {
|
366 marek 1.70 Logger::_putInternal(logFileType, systemId, logLevel,
|
367 kumpf 1.63 Formatter::format(formatString, arg0, arg1, arg2, arg3,
368 arg4, arg5, arg6, arg7, arg8, arg9));
|
369 mike 1.42 }
|
370 karl 1.37 }
371
372 void Logger::put(
|
373 kumpf 1.40 LogFileType logFileType,
374 const String& systemId,
375 Uint32 logLevel,
376 const String& formatString)
|
377 karl 1.37 {
|
378 mike 1.42 if (wouldLog(logLevel))
379 {
|
380 marek 1.70 Logger::_putInternal(logFileType, systemId, logLevel, formatString);
|
381 mike 1.42 }
382 }
|
383 karl 1.37
|
384 mike 1.42 void Logger::put(
385 LogFileType logFileType,
386 const String& systemId,
387 Uint32 logLevel,
388 const String& formatString,
389 const Formatter::Arg& arg0)
390 {
391 if (wouldLog(logLevel))
392 {
|
393 marek 1.70 Logger::_putInternal(logFileType, systemId, logLevel,
|
394 kumpf 1.63 Formatter::format(formatString, arg0));
|
395 mike 1.42 }
|
396 karl 1.37 }
397
398 void Logger::put(
|
399 kumpf 1.40 LogFileType logFileType,
400 const String& systemId,
401 Uint32 logLevel,
402 const String& formatString,
|
403 mike 1.42 const Formatter::Arg& arg0,
404 const Formatter::Arg& arg1)
|
405 karl 1.37 {
|
406 mike 1.42 if (wouldLog(logLevel))
407 {
|
408 marek 1.70 Logger::_putInternal(logFileType, systemId, logLevel,
|
409 kumpf 1.63 Formatter::format(formatString, arg0, arg1));
|
410 mike 1.42 }
411 }
|
412 karl 1.37
|
413 mike 1.42 void Logger::put(
414 LogFileType logFileType,
415 const String& systemId,
416 Uint32 logLevel,
417 const String& formatString,
418 const Formatter::Arg& arg0,
419 const Formatter::Arg& arg1,
420 const Formatter::Arg& arg2)
421 {
422 if (wouldLog(logLevel))
423 {
|
424 marek 1.70 Logger::_putInternal(logFileType, systemId, logLevel,
|
425 kumpf 1.63 Formatter::format(formatString, arg0, arg1, arg2));
|
426 mike 1.42 }
|
427 chuck 1.29 }
428
429 void Logger::put_l(
|
430 kumpf 1.40 LogFileType logFileType,
431 const String& systemId,
432 Uint32 logLevel,
|
433 kumpf 1.63 const MessageLoaderParms& msgParms)
|
434 mike 1.42 {
435 if (wouldLog(logLevel))
436 {
|
437 kumpf 1.63 MessageLoaderParms parms = msgParms;
438 parms.useProcessLocale = true;
|
439 marek 1.70 Logger::_putInternal(logFileType, systemId, logLevel,
|
440 kumpf 1.63 MessageLoader::getMessage(parms));
|
441 mike 1.42 }
|
442 david 1.26 }
443
444 void Logger::trace(
|
445 kumpf 1.40 LogFileType logFileType,
446 const String& systemId,
|
447 kumpf 1.62 const String& message)
|
448 chuck 1.29 {
|
449 mike 1.42 if (wouldLog(Logger::TRACE))
450 {
|
451 marek 1.70 Logger::_putInternal(logFileType, systemId, Logger::TRACE,
|
452 kumpf 1.63 message);
|
453 mike 1.42 }
|
454 mike 1.13 }
455
456 void Logger::setHomeDirectory(const String& homeDirectory)
457 {
458 _homeDirectory = homeDirectory;
459 }
|
460 david 1.26
|
461 dl.meetei 1.71 void Logger::setlogLevelMask( const String &logLevelList )
|
462 david 1.26 {
|
463 karl 1.37 Uint32 logLevelType = 0;
|
464 david 1.26 String logLevelName = logLevelList;
465
466 // Check if logLevel has been specified
467 if (logLevelName != String::EMPTY)
468 {
469 // initialise _severityMask
470 _severityMask = 0;
471
|
472 kumpf 1.40 // Set logLevelType to indicate the level of logging
|
473 david 1.26 // required by the user.
|
474 kumpf 1.40 if (String::equalNoCase(logLevelName,"TRACE"))
475 {
476 logLevelType = Logger::TRACE;
477 }
478 else if (String::equalNoCase(logLevelName,"INFORMATION"))
479 {
480 logLevelType = Logger::INFORMATION;
481 }
482 else if (String::equalNoCase(logLevelName,"WARNING"))
483 {
484 logLevelType = Logger::WARNING;
485 }
486 else if (String::equalNoCase(logLevelName,"SEVERE"))
487 {
488 logLevelType = Logger::SEVERE;
489 }
490 else if (String::equalNoCase(logLevelName,"FATAL"))
491 {
492 logLevelType = Logger::FATAL;
493 }
494 // Setting _severityMask. NOTE: When adding new logLevels
|
495 david 1.26 // it is essential that they are adding in ascending order
496 // based on priority. Once a case statement is true we will
497 // continue to set all following log levels with a higher
498 // priority.
|
499 kumpf 1.40 switch(logLevelType)
500 {
501 case Logger::TRACE:
502 _severityMask |= Logger::TRACE;
503 case Logger::INFORMATION:
504 _severityMask |= Logger::INFORMATION;
505 case Logger::WARNING:
506 _severityMask |= Logger::WARNING;
507 case Logger::SEVERE:
508 _severityMask |= Logger::SEVERE;
509 case Logger::FATAL:
510 _severityMask |= Logger::FATAL;
511 }
|
512 kumpf 1.54
513 Executor::updateLogLevel(logLevelName.getCString());
|
514 david 1.26 }
515 else
516 {
|
517 kumpf 1.40 // Property logLevel not specified, set default value.
518 _severityMask = ~Logger::TRACE;
|
519 kumpf 1.54 Executor::updateLogLevel("INFORMATION");
|
520 david 1.26 }
521 }
522
|
523 dl.meetei 1.71 Boolean Logger::isValidlogLevel(const String &logLevel)
|
524 david 1.26 {
525 // Validate the logLevel and modify the logLevel argument
526 // to reflect the invalid logLevel
527
528 Uint32 index=0;
529 String logLevelName = String::EMPTY;
530 Boolean validlogLevel=false;
531
532 logLevelName = logLevel;
533
534 if (logLevelName != String::EMPTY)
535 {
|
536 kumpf 1.40 // Lookup the index for logLevel name in _logLevel_LIST
537 index = 0;
538 validlogLevel = false;
539
540 while (index < _NUM_LOGLEVEL)
541 {
542 if (String::equalNoCase(logLevelName, LOGLEVEL_LIST[index]))
543 {
544 // Found logLevel, break from the loop
545 validlogLevel = true;
546 break;
547 }
548 else
549 {
550 index++;
551 }
552 }
|
553 david 1.26 }
554 else
555 {
|
556 kumpf 1.40 // logLevels is empty, it is a valid value so return true
|
557 kumpf 1.57 return true;
|
558 david 1.26 }
559
560 return validlogLevel;
561 }
562
|
563 mreddy 1.65 #if !defined (PEGASUS_USE_SYSLOGS)
564 void Logger::setMaxLogFileSize(Uint32 maxLogFileSizeBytes)
565 {
566 LoggerRep::setMaxLogFileSize(maxLogFileSizeBytes);
567 }
568 #endif
569
|
570 mike 1.13 PEGASUS_NAMESPACE_END
|