00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <spl/types.h>
00019
00020 #ifdef _WINDOWS
00021 #include <spl/configwin32.h>
00022 #else
00023 #include <spl/autoconf/config.h>
00024 #endif
00025
00026 #include <spl/Debug.h>
00027 #include <spl/Log.h>
00028 #ifdef HAVE_STRING_H
00029 #include <string.h>
00030 #endif
00031 #ifdef HAVE_TIME_H
00032 #include <time.h>
00033 #endif
00034 #ifdef HAVE_SYS_TIME_H
00035 #include <sys/time.h>
00036 #endif
00037 #include <stdio.h>
00038 #include <spl/Environment.h>
00039 #include <spl/Exception.h>
00040 #include <spl/io/File.h>
00041 #include <spl/Int32.h>
00042 #include <spl/threading/Mutex.h>
00043 #include <spl/text/StringBuffer.h>
00044 #include <spl/net/UdpSocket.h>
00045
00046 bool Log::_LogDoLog(const Log::LogEntry& le, Log::OutputConfig m_msgToLog)
00047 {
00048 return (le.GetSeverity() == Log::SevAlert && m_msgToLog.m_doLogAlert) ||
00049 (le.GetSeverity() == Log::SevCritical && m_msgToLog.m_doLogCritical) ||
00050 (le.GetSeverity() == Log::SevDebug && m_msgToLog.m_doLogDebug) ||
00051 (le.GetSeverity() == Log::SevEmergency && m_msgToLog.m_doLogEmergency) ||
00052 (le.GetSeverity() == Log::SevError && m_msgToLog.m_doLogError) ||
00053 (le.GetSeverity() == Log::SevInfo && m_msgToLog.m_doLogInfo) ||
00054 (le.GetSeverity() == Log::SevNotice && m_msgToLog.m_doLogNotice) ||
00055 (le.GetSeverity() == Log::SevWarning && m_msgToLog.m_doLogWarning);
00056 }
00057
00058 Log::LogEntry::LogEntry()
00059 : m_facility(Log::FacLocal1),
00060 m_severity(Log::SevInfo),
00061 m_dts(),
00062 m_host(Environment::HostName()),
00063 m_process(Environment::ProcessName()),
00064 m_pid(),
00065 m_message()
00066 {
00067 #ifndef _WINDOWS
00068 m_pid = (int)getpid();
00069 #endif
00070 }
00071
00072 Log::LogEntry::LogEntry(Log::Facility facility, Log::Severity severity, const String& message)
00073 : m_facility(facility),
00074 m_severity(severity),
00075 m_dts(),
00076 m_host(Environment::HostName()),
00077 m_process(Environment::ProcessName()),
00078 m_pid(),
00079 m_message(message)
00080 {
00081 #ifndef _WINDOWS
00082 m_pid = (int)getpid();
00083 #endif
00084 }
00085
00086 Log::LogEntry::LogEntry(const LogEntry& le)
00087 : m_facility(le.m_facility),
00088 m_severity(le.m_severity),
00089 m_dts(le.m_dts),
00090 m_host(le.m_host),
00091 m_process(le.m_process),
00092 m_pid(le.m_pid),
00093 m_message(le.m_message)
00094 {
00095 }
00096
00097 Log::LogEntry::LogEntry
00098 (
00099 Log::Facility facility,
00100 Log::Severity severity,
00101 const String& host,
00102 const String& process,
00103 int pid,
00104 const String& message
00105 )
00106 : m_facility(facility),
00107 m_severity(severity),
00108 m_dts(),
00109 m_host(host),
00110 m_process(process),
00111 m_pid(pid),
00112 m_message(message)
00113 {
00114 }
00115
00116 Log::LogEntry::~LogEntry()
00117 {
00118 }
00119
00120 Log::LogEntry& Log::LogEntry::operator =(const LogEntry& le)
00121 {
00122 m_facility = le.m_facility;
00123 m_severity = le.m_severity;
00124 m_dts = le.m_dts;
00125 m_host = le.m_host;
00126 m_process = le.m_process;
00127 m_pid = le.m_pid;
00128 m_message = le.m_message;
00129
00130 return *this;
00131 }
00132
00133 StringPtr Log::LogEntry::ToString() const
00134 {
00135 StringBuffer buf(30 + m_host.Length() + m_process.Length() + m_message.Length());
00136 buf.Append('<');
00137 buf.Append(Int32::ToString(Priority()));
00138 buf.Append('>');
00139 buf.Append(m_dts.ToStringISO8601());
00140 buf.Append(' ');
00141 buf.Append(m_host);
00142 buf.Append(' ');
00143 buf.Append(m_process);
00144 if (m_pid > 0)
00145 {
00146 buf.Append('[');
00147 buf.Append(Int32::ToString(m_pid));
00148 buf.Append(']');
00149 }
00150 buf.Append(": ");
00151 buf.Append(m_message);
00152
00153 if (buf.Length() < 1025)
00154 {
00155 return buf.ToString();
00156 }
00157
00158 StringPtr line(buf.ToString());
00159 return line->Substring(0, 1024);
00160 }
00161
00162 StringPtr Log::LogEntry::ToShortString() const
00163 {
00164 StringBuffer buf(20 + m_message.Length());
00165 buf.Append(m_dts.ToTimeString());
00166 buf.Append(' ');
00167
00168 switch(m_severity)
00169 {
00170 case Log::SevEmergency:
00171 buf.Append("PANIC ");
00172 break;
00173 case Log::SevAlert:
00174 buf.Append("ALERT ");
00175 break;
00176 case Log::SevCritical:
00177 buf.Append("CRITL ");
00178 break;
00179 case Log::SevError:
00180 buf.Append("ERROR ");
00181 break;
00182 case Log::SevWarning:
00183 buf.Append("WARNG ");
00184 break;
00185 case Log::SevNotice:
00186 buf.Append("NOTIC ");
00187 break;
00188 case Log::SevInfo:
00189 buf.Append("INFO: ");
00190 break;
00191 case Log::SevDebug:
00192 buf.Append("DEBUG ");
00193 break;
00194 default:
00195 buf.Append("????? ");
00196 break;
00197 }
00198
00199 buf.Append(m_message);
00200
00201 if (buf.Length() < 1025)
00202 {
00203 return buf.ToString();
00204 }
00205
00206 StringPtr line(buf.ToString());
00207 return line->Substring(0, 1024);
00208 }
00209
00210 Log::LogEntry Log::LogEntry::Parse(const String& msg, unsigned long sourceIp)
00211 {
00212 LogEntry le;
00213 le.GetMessage() = msg;
00214
00215 struct in_addr ia;
00216 ia.s_addr = sourceIp;
00217 le.GetHost() = String(inet_ntoa(ia));
00218
00219 if (msg.CharAt(0) != '<')
00220 {
00221 return le;
00222 }
00223
00224 int idx = msg.IndexOf('>');
00225 if (0 > idx)
00226 {
00227 return le;
00228 }
00229
00230 StringPtr str(msg.Mid(1, idx));
00231 if (! Int32::IsInt(str))
00232 {
00233 return le;
00234 }
00235 int priority = Int32::Parse(str);
00236 le.GetFacility() = (Log::Facility)(priority / 8);
00237 le.GetSeverity() = (Log::Severity)(priority >> 3);
00238
00239 int colonPos = msg.LastIndexOf(':');
00240 if (0 > colonPos)
00241 {
00242 return le;
00243 }
00244
00245 StringPtr header = msg.Mid(idx+1, colonPos);
00246 StringPtr text = msg.Substring(colonPos + 1)->Trim();
00247
00248 RefCountPtr<Vector<StringPtr> > parts(header->Split(" "));
00249 if (parts->Count() < 2 || parts->Count() > 4 || ! Date::IsDate(parts->ElementAt(0)))
00250 {
00251 return le;
00252 }
00253 String sdtm = *parts->ElementAt(0) + " " + *parts->ElementAt(1);
00254 if (! DateTime::IsDateTime(sdtm))
00255 {
00256 return le;
00257 }
00258 le.GetDateTime() = DateTime::Parse(sdtm);
00259
00260 le.GetMessage() = msg;
00261 if (parts->Count() > 2)
00262 {
00263 le.GetHost() = parts->ElementAt(2);
00264 }
00265 if (parts->Count() > 3)
00266 {
00267 StringPtr tag = parts->ElementAt(3);
00268 if ((idx = tag->IndexOf('[')) > -1 && tag->IndexOf(']') > -1 )
00269 {
00270 le.GetProcess() = tag->Substring(0, idx);
00271 StringPtr spid = tag->Mid(idx+1, tag->IndexOf(']'));
00272 if (Int32::IsInt(spid))
00273 {
00274 le.GetPID() = Int32::Parse(spid);
00275 }
00276 else
00277 {
00278 le.GetProcess() = tag;
00279 }
00280 }
00281 else
00282 {
00283 le.GetProcess() = tag;
00284 }
00285 }
00286
00287 return le;
00288 }
00289
00290 #if defined(DEBUG)
00291 void Log::LogEntry::CheckMem() const
00292 {
00293 m_host.CheckMem();
00294 m_process.CheckMem();
00295 m_message.CheckMem();
00296 }
00297
00298 void Log::LogEntry::ValidateMem() const
00299 {
00300 m_host.CheckMem();
00301 m_process.CheckMem();
00302 m_message.CheckMem();
00303 }
00304 #endif
00305
00306 Log::LogServerInfo::LogServerInfo()
00307 : m_server(), m_port(0), m_sock()
00308 {
00309 }
00310
00311 Log::LogServerInfo::LogServerInfo(const String& server, int port)
00312 : m_server(server), m_port(port), m_sock()
00313 {
00314 m_logMsgTypes.m_doLogAlert = 1;
00315 m_logMsgTypes.m_doLogCritical = 1;
00316 m_logMsgTypes.m_doLogDebug = 1;
00317 m_logMsgTypes.m_doLogEmergency = 1;
00318 m_logMsgTypes.m_doLogError = 1;
00319 m_logMsgTypes.m_doLogInfo = 1;
00320 m_logMsgTypes.m_doLogNotice = 1;
00321 m_logMsgTypes.m_doLogWarning = 1;
00322
00323 m_sock = UdpSocketPtr(new UdpSocket(server, port));
00324 }
00325
00326 Log::LogServerInfo::LogServerInfo(const String& server, int port, OutputConfig logMsgTypes)
00327 : m_server(server), m_port(port), m_logMsgTypes(logMsgTypes), m_sock()
00328 {
00329 m_sock = UdpSocketPtr(new UdpSocket(server, port));
00330 }
00331
00332 Log::LogServerInfo::~LogServerInfo()
00333 {
00334 if (m_sock.IsNotNull())
00335 {
00336 m_sock->Close();
00337 }
00338 }
00339
00340 Log::LogServerInfo& Log::LogServerInfo::operator =(const LogServerInfo& lsi)
00341 {
00342 m_server = lsi.m_server;
00343 m_port = lsi.m_port;
00344 m_logMsgTypes = lsi.m_logMsgTypes;
00345 m_sock = lsi.m_sock;
00346
00347 return *this;
00348 }
00349
00350 void Log::LogServerInfo::Send(const LogEntry& le)
00351 {
00352 m_sock->Send(le.ToString()->ToByteArray());
00353 }
00354
00355 void Log::LogServerInfo::Send(const String& line)
00356 {
00357 m_sock->Send(line.ToByteArray());
00358 }
00359
00360 #if defined(DEBUG)
00361 void Log::LogServerInfo::CheckMem() const
00362 {
00363 m_server.CheckMem();
00364 m_sock.CheckMem();
00365 }
00366
00367 void Log::LogServerInfo::ValidateMem() const
00368 {
00369 m_server.ValidateMem();
00370 m_sock.ValidateMem();
00371 }
00372 #endif
00373
00374 Log::Log()
00375 : m_facility(Log::FacLocal0),
00376 m_logType(Log::LogToConsole),
00377 m_messageCount(0),
00378 m_servers(),
00379 m_fileName(),
00380 m_msgToLog()
00381 {
00382 }
00383
00384 Log::Log(Facility facility, LogType logType)
00385 : m_facility(facility),
00386 m_logType(logType),
00387 m_servers(),
00388 m_messageCount(0),
00389 m_fileName(),
00390 m_msgToLog()
00391 {
00392 }
00393
00394 Log::Log(const Log& l)
00395 : m_facility(l.m_facility),
00396 m_logType(l.m_logType),
00397 m_messageCount(l.m_messageCount),
00398 m_fileName(l.m_fileName),
00399 m_servers(l.m_servers)
00400 {
00401 m_msgToLog = l.m_msgToLog;
00402 }
00403
00404 Log::~Log()
00405 {
00406 for (List<LogServerInfo>::Iterator iter = m_servers.Begin(); iter.Next(); )
00407 {
00408 iter.CurrentRef().Close();
00409 }
00410 }
00411
00412 Log& Log::operator =(const Log& l)
00413 {
00414 m_facility = l.m_facility;
00415 m_logType = l.m_logType;
00416 m_messageCount = l.m_messageCount;
00417 m_fileName = l.m_fileName;
00418 m_servers = l.m_servers;
00419 m_msgToLog = l.m_msgToLog;
00420 return *this;
00421 }
00422
00423 int Log::m_staticLogType = Log::LogToConsole;
00424 char Log::m_staticFileName[512] = {0};
00425 char Log::m_staticServerName[128] = {0};
00426 int Log::m_staticServerPort = 514;
00427 volatile int Log::m_staticMessageCount = 0;
00428 volatile int Log::m_staticOldMsgCount = 0;
00429
00430 static Mutex g_loglock;
00431
00432 static void _LogWriteFile(const Log::LogEntry& le, const String& filename)
00433 {
00434 ASSERT(filename.Length() > 0);
00435
00436 g_loglock.Lock();
00437
00438 try
00439 {
00440 TextWriterPtr writer = File::AppendText(filename);
00441 writer->WriteLine(le.ToString());
00442 writer->Close();
00443 }
00444 catch(Exception *ex)
00445 {
00446 printf("Error writing log file (%s) %s\n", filename.GetChars(), ex->Message());
00447 delete ex;
00448 }
00449
00450 g_loglock.Unlock();
00451 }
00452
00453 static void _LogWriteServer(const Log::LogEntry& le, const String& server, int port)
00454 {
00455 ASSERT(server.Length() > 0 && port > 0);
00456
00457 StringPtr line(le.ToString());
00458 UdpSocket sock(port);
00459 sock.Send(line->ToByteArray(), server);
00460 sock.Close();
00461 }
00462
00463 static void _LogWriteConsole(const Log::LogEntry& le)
00464 {
00465 g_loglock.Lock();
00466 StringPtr line(le.ToShortString());
00467 printf("%s\n", line->GetChars());
00468 g_loglock.Unlock();
00469 }
00470
00471 static void _LogWrite(const Log::LogEntry& le, int logType, const String& filename, const String& server, int port)
00472 {
00473 if (0 != (logType & Log::LogToFile) && filename.Length() > 0)
00474 {
00475 _LogWriteFile(le, filename);
00476 }
00477 if (0 != (logType & Log::LogToServer) && server.Length() > 0)
00478 {
00479 _LogWriteServer(le, server, port);
00480 }
00481 if (0 != (logType & Log::LogToConsole))
00482 {
00483 _LogWriteConsole(le);
00484 }
00485 }
00486
00487 bool Log::DoLog(const LogEntry& le)
00488 {
00489 return _LogDoLog(le, m_msgToLog);
00490 }
00491
00492 void Log::SWrite(const LogEntry& le)
00493 {
00494 m_staticMessageCount++;
00495 _LogWrite(le, m_staticLogType, m_staticFileName, m_staticServerName, m_staticServerPort);
00496 }
00497
00498 void Log::Write(const LogEntry& le)
00499 {
00500 if (! DoLog(le))
00501 {
00502 return;
00503 }
00504 m_messageCount++;
00505
00506 _LogWrite(le, m_logType, m_fileName, "", 0);
00507
00508 if (0 != (m_logType & Log::LogToServer) && m_servers.Count() > 0)
00509 {
00510 for (List<LogServerInfo>::Iterator iter = m_servers.Begin(); iter.Next(); )
00511 {
00512 if( _LogDoLog(le, iter.CurrentRef().GetWhereToLog()))
00513 {
00514 iter.CurrentRef().Send(le);
00515 }
00516 }
00517 }
00518 }
00519
00520 void Log::SWriteOkFail( const String& msg )
00521 {
00522 LogEntry le;
00523
00524 if ( m_staticMessageCount == m_staticOldMsgCount )
00525 {
00526 le.GetMessage() = msg + " OK";
00527 }
00528 else
00529 {
00530 le.GetMessage() = msg + " FAIL";
00531 }
00532 SWrite(le);
00533
00534 m_staticOldMsgCount = m_staticMessageCount;
00535 }
00536
00537 void Log::SWriteEndOfRunTotal()
00538 {
00539 LogEntry le;
00540 if ( 0 == m_staticMessageCount )
00541 {
00542 le.GetMessage() = "No errors.";
00543 }
00544 else
00545 {
00546 le.GetMessage() = "Errors.";
00547 }
00548 SWrite(le);
00549 }
00550
00551 void Log::Write(const OutOfMemoryException& mex)
00552 {
00553 WriteError(mex.Message());
00554 }
00555
00556 void Log::Write(Exception *ex)
00557 {
00558 WriteError(ex->Message());
00559 }
00560
00561 void Log::Write(Severity severity, const String& message)
00562 {
00563 LogEntry le(m_facility, severity, message);
00564 Write(le);
00565 }
00566
00567 void Log::Write(Severity severity, Facility facility, const String& process, const String& message)
00568 {
00569 LogEntry le(facility, severity, message);
00570 le.GetProcess() = process;
00571 le.GetPID() = 0;
00572 Write(le);
00573 }
00574
00575 void Log::Write(Severity severity, Facility facility, const String& process, int pid, const String& message)
00576 {
00577 LogEntry le(facility, severity, message);
00578 le.GetProcess() = process;
00579 le.GetPID() = pid;
00580 Write(le);
00581 }
00582
00583 void Log::Write(Severity severity, Facility facility, const String& host, const String& process, int pid, const String& message)
00584 {
00585 LogEntry le(facility, severity, host, process, pid, message);
00586 Write(le);
00587 }
00588
00589 void Log::WriteError(const String& message)
00590 {
00591 LogEntry le(m_facility, Log::SevError, message);
00592 Write(le);
00593 }
00594
00595 void Log::WriteWarn(const String& message)
00596 {
00597 LogEntry le(m_facility, Log::SevWarning, message);
00598 Write(le);
00599 }
00600
00601 void Log::WriteInfo(const String& message)
00602 {
00603 LogEntry le(m_facility, Log::SevInfo, message);
00604 Write(le);
00605 }
00606
00607 void Log::SSetLogType(LogType lt)
00608 {
00609 m_staticLogType = lt;
00610 }
00611
00612 void Log::SSetLogFileName(const String& filename)
00613 {
00614 spl::StrCpyLen(m_staticFileName, filename.GetChars(), sizeof(m_staticFileName));
00615 }
00616
00617 void Log::SSetSyslogServer(const String& server)
00618 {
00619 spl::StrCpyLen(m_staticServerName, server.GetChars(), sizeof(m_staticServerName));
00620 }
00621
00622 void Log::SSetStaticSyslogPort(int port)
00623 {
00624 m_staticServerPort = port;
00625 }
00626
00627 void Log::SWrite(const OutOfMemoryException& mex)
00628 {
00629 SWriteError(mex.Message());
00630 }
00631
00632 void Log::SWrite(Exception *ex)
00633 {
00634 SWriteError(ex->Message());
00635 }
00636
00637 void Log::SWrite(Severity severity, const String& message)
00638 {
00639 LogEntry le(Log::FacLocal0, severity, message);
00640 SWrite(le);
00641 }
00642
00643 void Log::SWrite(Severity severity, Facility facility, const String& process, const String& message)
00644 {
00645 LogEntry le(facility, severity, message);
00646 le.GetProcess() = process;
00647 le.GetPID() = 0;
00648 SWrite(le);
00649 }
00650
00651 void Log::SWrite(Severity severity, Facility facility, const String& process, int pid, const String& message)
00652 {
00653 LogEntry le(facility, severity, message);
00654 le.GetProcess() = process;
00655 le.GetPID() = pid;
00656 SWrite(le);
00657 }
00658
00659 void Log::SWrite(Severity severity, Facility facility, const String& host, const String& process, int pid, const String& message)
00660 {
00661 LogEntry le(facility, severity, host, process, pid, message);
00662 SWrite(le);
00663 }
00664
00665 void Log::SWriteError(const String& message)
00666 {
00667 LogEntry le(Log::FacLocal0, Log::SevError, message);
00668 SWrite(le);
00669 }
00670
00671 void Log::SWriteWarn(const String& message)
00672 {
00673 LogEntry le(Log::FacLocal0, Log::SevWarning, message);
00674 SWrite(le);
00675 }
00676
00677 void Log::SWriteInfo(const String& message)
00678 {
00679 LogEntry le(Log::FacLocal0, Log::SevInfo, message);
00680 SWrite(le);
00681 }
00682
00683 int Log::SMessageCount()
00684 {
00685 return m_staticMessageCount;
00686 }
00687
00688 #if defined(DEBUG)
00689 void Log::CheckMem() const
00690 {
00691 m_fileName.CheckMem();
00692 m_servers.CheckMem();
00693 }
00694
00695 void Log::ValidateMem() const
00696 {
00697 m_fileName.ValidateMem();
00698 m_servers.ValidateMem();
00699 }
00700 #endif