//
// File: hzLogger.cpp
//
// Legal Notice: This file is part of the HadronZoo C++ Class Library. Copyright 2025 HadronZoo Project (http://www.hadronzoo.com)
//
// The HadronZoo C++ Class Library is free software: You can redistribute it, and/or modify it under the terms of the GNU Lesser General Public License, as published by the Free
// Software Foundation, either version 3 of the License, or any later version.
//
// The HadronZoo C++ Class Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License along with the HadronZoo C++ Class Library. If not, see http://www.gnu.org/licenses.
//
//
// Implimentation of the hzLogger class.
//
#include <iostream>
#include <stdarg.h>
#include "hzChars.h"
#include "hzChain.h"
#include "hzIpServer.h"
#include "hzTcpClient.h"
#include "hzIpaddr.h"
#include "hzProcess.h"
/*
** Variables
*/
static hzString s_LocalHost = "127.0.0.1" ; // This server IP address
/*
** hzLogger functios
*/
hzLogger::hzLogger (void)
{
// hzLogger constructor. Initialize logger, and set the logger for the thread to this logger.
m_pFile = 0 ;
m_pDataPtr = m_cvData + 11 ;
m_nIndent = 0 ;
m_nSessID = 0 ;
m_pConnection = 0 ;
m_bVerbose = false ;
// Set the logger for the calling thread to be this locker
SetThreadLogger(this) ;
}
hzLogger::~hzLogger (void)
{
// hzLogger destructor. There is currently no de-registration facility.
}
hzEcode hzLogger::OpenFile (const char* fpath, hzLogRotate eRotate)
{
// Purpose: Open a LogChannel to use a file regime
//
// Arguments: 1) fpath The logfile's base name or path
// 2) eRotate The log rotate edict
//
// Returns: E_ARGUMENT If no file path is supplied
// E_INITDUP If logger already open
// E_OK If channel opened OK
_hzfunc("hzLogger::OpenFile") ;
char cvDir [HZ_MAXPATHLEN] ; // Current working directory
char* cpCWD ; // Path iterator
if (!fpath || !fpath[0])
hzexit(E_ARGUMENT, "No path supplied") ;
if (IsOpen())
hzexit(E_INITDUP, "%s: This log channel is already open", fpath) ;
if (fpath[0] == CHAR_FWSLASH)
m_Base = fpath ;
else
{
cpCWD = getcwd(cvDir, HZ_MAXPATHLEN) ;
for (; *cpCWD ; cpCWD++) ;
*cpCWD++ = CHAR_FWSLASH ;
strcpy(cpCWD, fpath) ;
m_Base = cvDir ;
}
// Set this to non zero to indicate channel open
m_nSessID = 0 ;
// Set rotate edict
m_eRotate = eRotate ;
// Set data pointer
m_pDataPtr = m_cvData ;
return E_OK ;
}
hzEcode hzLogger::OpenPublic (const char* fpath, hzLogRotate eRotate)
{
// Purpose: Open a LogChannel to use a public logfile
//
// Arguments: 1) fpath The logfile's publicly known path which must be in /etc/logserver.d/public_logs.conf
// 2) eRotate The log rotate edict
//
// Returns: E_HOSTFAIL If no connection to the logserver could be established
// E_SENDFAIL If the open command could not be sent to the logserver
// E_RECVFAIL If the logserver's response could not be received
// E_WRITEFAIL If the logserver fails to find the named public logfile
// E_PROTOCOL If the uid of the calling process is not permitted to write to the file
// E_OK If the logserver has opened a channel to the named public logfile
_hzfunc("hzLogger::OpenPublic") ;
uint32_t nSize ; // Size of logserver client request
uint32_t nUsr ; // UNIX user id
uint32_t nGrp ; // UNIX group id
uint32_t nProcID ; // Caller process id
uchar* u ; // Pointer into message buffer
// Connect to the logserver
m_pConnection = new hzTcpClient() ;
if (m_pConnection->ConnectStd(s_LocalHost, PORT_LOGSERVER) != E_OK)
return E_HOSTFAIL ;
// Prepare header
nSize = 16 + strlen(fpath) ;
nProcID = getpid() ;
nUsr = geteuid() ;
nGrp = getegid() ;
u = (uchar*) m_cvData ;
// Command
u[0] = LS_OPEN_PUB ;
// Size of message
u[1] = (nSize & 0xff00) >> 8 ;
u[2] = (nSize & 0xff) ;
// Process ID
u[3] = (nProcID & 0xff000000) >> 24 ;
u[4] = (nProcID & 0xff0000) >> 16 ;
u[5] = (nProcID & 0xff00) >> 8 ;
u[6] = (nProcID & 0xff) ;
// User ID
u[7] = (nUsr & 0xff000000) >> 24 ;
u[8] = (nUsr & 0xff0000) >> 16 ;
u[9] = (nUsr & 0xff00) >> 8 ;
u[10] = (nUsr & 0xff) ;
// Group ID
u[11] = (nGrp & 0xff000000) >> 24 ;
u[12] = (nGrp & 0xff0000) >> 16 ;
u[13] = (nGrp & 0xff00) >> 8 ;
u[14] = (nGrp & 0xff) ;
// Filename
strncpy(m_cvData + 15, fpath, HZ_MAXPATHLEN) ;
// Send message and recv response
if (m_pConnection->Send(m_cvData, nSize) != E_OK)
return E_SENDFAIL ;
if (m_pConnection->Recv(m_cvData, nSize, 64) != E_OK)
return E_RECVFAIL ;
if (nSize == 4 && m_cvData[0] == LS_OK)
{
m_nSessID = 0 ;
m_nSessID |= (u[1] << 16) ;
m_nSessID |= (u[2] << 8) ;
m_nSessID |= u[3] ;
return E_OK ;
}
if (m_cvData[0] == LS_ERR_PERM)
return E_WRITEFAIL ;
// Set data pointer
m_pDataPtr = m_cvData + 10 ;
return E_PROTOCOL ;
}
hzEcode hzLogger::OpenPrivate (const char* fpath, hzLogRotate eRotate, uint32_t nPerms)
{
// Purpose: Open a LogChannel to use a private logserver file
//
// Arguments: 1) fpath The base pathname of the logfile
// 2) eRotate The log rotate edict
// 3) nPerms Access permissions to be applied to the file. This will be ignored by the logserver if the file already exists and the calling
// process has write permission.
//
// Returns: E_HOSTFAIL If no connection to the logserver could be established
// E_SENDFAIL If the open command could not be sent to the logserver
// E_RECVFAIL If the logserver's response could not be received
// E_WRITEFAIL If the logserver fails to find the named public logfile
// E_PROTOCOL If the uid of the calling process is not permitted to write to the file
// E_OK If the logserver has opened a channel to the named public logfile
_hzfunc("hzLogger::OpenPrivate") ;
uint32_t nSize ; // Size of logserver client request
uint32_t nUsr ; // UNIX user id
uint32_t nGrp ; // UNIX group id
uint32_t nProcID ; // Caller process id
uchar* u ; // Pointer into message buffer
// Connect to the logserver
if (m_pConnection->ConnectStd(s_LocalHost, PORT_LOGSERVER) != E_OK)
return E_HOSTFAIL ;
// Prepare header
nSize = 21 + strlen(fpath) ;
nProcID = getpid() ;
nUsr = geteuid() ;
nGrp = getegid() ;
u = (uchar*) m_cvData ;
// Command
u[ 0] = LS_OPEN_PUB ;
// Size of message
u[ 1] = (nSize & 0xff00) >> 8 ;
u[ 2] = (nSize & 0xff) ;
// Process ID
u[ 3] = (nProcID & 0xff000000) >> 24 ;
u[ 4] = (nProcID & 0xff0000) >> 16 ;
u[ 5] = (nProcID & 0xff00) >> 8 ;
u[ 6] = (nProcID & 0xff) ;
// User ID
u[ 7] = (nUsr & 0xff000000) >> 24 ;
u[ 8] = (nUsr & 0xff0000) >> 16 ;
u[ 9] = (nUsr & 0xff00) >> 8 ;
u[10] = (nUsr & 0xff) ;
// Group ID
u[11] = (nGrp & 0xff000000) >> 24 ;
u[12] = (nGrp & 0xff0000) >> 16 ;
u[13] = (nGrp & 0xff00) >> 8 ;
u[14] = (nGrp & 0xff) ;
// Permissions
u[15] = (nPerms & 0xff000000) >> 24 ;
u[16] = (nPerms & 0xff0000) >> 16 ;
u[17] = (nPerms & 0xff00) >> 8 ;
u[18] = (nPerms & 0xff) ;
// Rotate edict
u[19] = eRotate ;
// Filename
strncpy(m_cvData + 20, fpath, HZ_MAXPATHLEN) ;
// Send message and recv response
if (m_pConnection->Send(m_cvData, nSize) != E_OK)
return E_SENDFAIL ;
if (m_pConnection->Recv(m_cvData, nSize, 64) != E_OK)
return E_RECVFAIL ;
if (nSize == 4 && m_cvData[0] == LS_OK)
{
m_nSessID = 0 ;
m_nSessID |= (u[1] << 16) ;
m_nSessID |= (u[2] << 8) ;
m_nSessID |= u[3] ;
// Set data pointer
m_pDataPtr = m_cvData + 10 ;
return E_OK ;
}
return E_PROTOCOL ;
}
hzEcode hzLogger::Close (void)
{
// Close a log channel and remove it from the thread-logger table.
//
// Arguments: None
//
// Returns: E_SENDFAIL If the open command could not be sent to the logserver
// E_RECVFAIL If the logserver's response could not be received
// E_PROTOCOL If the uid of the calling process is not permitted to write to the file
// E_OK If the log channel was successfully closed
_hzfunc("hzLogger::Close") ;
uint32_t nBytes ; // Size of logserver client request
uint32_t nProcID ; // Caller process id
uchar* u ; // Pointer into message buffer
if (m_File)
{
// Log channel is using a direct file
if (m_pFile)
fclose(m_pFile) ;
m_pFile = 0 ;
m_nSessID = 0 ;
m_Base.Clear() ;
m_File.Clear() ;
return E_OK ;
}
// Log channel is using the logserver
u = (uchar*) m_cvData ;
nProcID = getpid() ;
// Command
u[0] = LS_STOP ;
// Size of message is 8 bytes
u[1] = 0 ;
u[2] = 8 ;
// Session ID
u[3] = (m_nSessID & 0x00ff0000) >> 16 ;
u[4] = (m_nSessID & 0x0000ff00) >> 8 ;
u[5] = (m_nSessID & 0x000000ff) ;
// Proc ID (not applicable)
u[6] = (nProcID & 0xff00) >> 8 ;
u[7] = (nProcID & 0xff00) >> 8 ;
u[8] = (nProcID & 0xff00) >> 8 ;
u[9] = (nProcID & 0xff) ;
nBytes = 10 ;
// Send message and receive response
if (m_pConnection->Send(m_cvData, nBytes) != E_OK)
return E_SENDFAIL ;
if (m_pConnection->Recv(m_cvData, nBytes, 64) != E_OK)
return E_RECVFAIL ;
if (m_cvData[0] == LS_OK)
return E_OK ;
return E_PROTOCOL ;
}
void hzLogger::_logrotate (void)
{
// Private method to change the hzLogger output file so as to seperate logfiles into approapriate time periods.
//
// Arguments: None
// Returns: None
_hzfunc("hzLogger::_logrotate") ;
bool bChange = false ; // Log rotation on/off indicator
char buf [32] ; // Log filename buffer
m_datCurr.SysDateTime() ;
switch (m_eRotate)
{
case LOGROTATE_NEVER: bChange = (m_Base && m_pFile == 0) ; break ;
case LOGROTATE_OFLOW: bChange = (m_Base && m_pFile == 0) ; break ;
case LOGROTATE_YEAR: bChange = (m_datCurr.Year() != m_datLast.Year()) ; break ;
case LOGROTATE_QTR: bChange = ((m_datCurr.Month() / 3) != (m_datLast.Month() / 3)) ; break ;
case LOGROTATE_MONTH: bChange = (m_datCurr.Month() != m_datLast.Month()) ; break ;
case LOGROTATE_MON: bChange = (m_datCurr.NoDays() != m_datLast.NoDays() && m_datCurr.Dow() == 0) ; break ;
case LOGROTATE_TUE: bChange = (m_datCurr.NoDays() != m_datLast.NoDays() && m_datCurr.Dow() == 1) ; break ;
case LOGROTATE_WED: bChange = (m_datCurr.NoDays() != m_datLast.NoDays() && m_datCurr.Dow() == 2) ; break ;
case LOGROTATE_THR: bChange = (m_datCurr.NoDays() != m_datLast.NoDays() && m_datCurr.Dow() == 3) ; break ;
case LOGROTATE_FRI: bChange = (m_datCurr.NoDays() != m_datLast.NoDays() && m_datCurr.Dow() == 4) ; break ;
case LOGROTATE_SAT: bChange = (m_datCurr.NoDays() != m_datLast.NoDays() && m_datCurr.Dow() == 5) ; break ;
case LOGROTATE_SUN: bChange = (m_datCurr.NoDays() != m_datLast.NoDays() && m_datCurr.Dow() == 6) ; break ;
case LOGROTATE_DAY: bChange = (m_datCurr.NoDays() != m_datLast.NoDays()) ; break ;
case LOGROTATE_12HR: bChange = ((m_datCurr.Hour() / 12) != (m_datLast.Hour() / 12)) ; break ;
case LOGROTATE_HOUR: bChange = (m_datCurr.Hour() != m_datLast.Hour()) ; break ;
}
if (!bChange && m_pFile == 0 && *m_Base)
bChange = true ;
if (bChange)
{
m_datLast = m_datCurr ;
if (m_pFile)
fclose(m_pFile) ;
switch (m_eRotate)
{
case LOGROTATE_NEVER: sprintf(buf, ".log") ; break ;
case LOGROTATE_OFLOW: sprintf(buf, ".log") ; break ;
case LOGROTATE_YEAR: sprintf(buf, "_%04d.log", m_datCurr.Year()) ; break ;
case LOGROTATE_QTR: sprintf(buf, "_%04dQ%d.log", m_datCurr.Year(), (m_datCurr.Month()/3) + 1) ; break ;
case LOGROTATE_MONTH: sprintf(buf, "_%04d%02d.log", m_datCurr.Year(), m_datCurr.Month()) ; break ;
case LOGROTATE_MON: sprintf(buf, "_%04d%02d%02dMon.log", m_datCurr.Year(), m_datCurr.Month(), m_datCurr.Day()) ; break ;
case LOGROTATE_TUE: sprintf(buf, "_%04d%02d%02dTue.log", m_datCurr.Year(), m_datCurr.Month(), m_datCurr.Day()) ; break ;
case LOGROTATE_WED: sprintf(buf, "_%04d%02d%02dWed.log", m_datCurr.Year(), m_datCurr.Month(), m_datCurr.Day()) ; break ;
case LOGROTATE_THR: sprintf(buf, "_%04d%02d%02dThr.log", m_datCurr.Year(), m_datCurr.Month(), m_datCurr.Day()) ; break ;
case LOGROTATE_FRI: sprintf(buf, "_%04d%02d%02dFri.log", m_datCurr.Year(), m_datCurr.Month(), m_datCurr.Day()) ; break ;
case LOGROTATE_SAT: sprintf(buf, "_%04d%02d%02dSat.log", m_datCurr.Year(), m_datCurr.Month(), m_datCurr.Day()) ; break ;
case LOGROTATE_SUN: sprintf(buf, "_%04d%02d%02dSun.log", m_datCurr.Year(), m_datCurr.Month(), m_datCurr.Day()) ; break ;
case LOGROTATE_DAY: sprintf(buf, "_%04d%02d%02d.log", m_datCurr.Year(), m_datCurr.Month(), m_datCurr.Day()) ; break ;
case LOGROTATE_12HR: sprintf(buf, "_%04d%02d%02d%s.log", m_datCurr.Year(), m_datCurr.Month(), m_datCurr.Day(), m_datCurr.Hour() > 11 ? "PM" : "AM") ;
break ;
case LOGROTATE_HOUR: sprintf(buf, "_%04d%02d%02d%02d.log", m_datCurr.Year(), m_datCurr.Month(), m_datCurr.Day(), m_datCurr.Hour()) ;
break ;
}
m_File = m_Base ;
m_File += buf ;
if (m_eRotate == LOGROTATE_NEVER)
m_pFile = fopen(*m_File, "w") ;
else
m_pFile = fopen(*m_File, "a") ;
if (!m_pFile)
{
std::cout << "Cannot open logfile [" << m_File << "] Terminating process\n" ;
exit(-1) ;
}
}
}
hzEcode hzLogger::_write (uint32_t nBytes)
{
// Private support function to unify logfile writing to either a logfile or a virtual logfile managed by the logserver.
//
// Arguments: 1) nBytes Number of bytes to write
//
// Returns: E_SENDFAIL If the open command could not be sent to the logserver
// E_RECVFAIL If the logserver's response could not be received
// E_PROTOCOL If the uid of the calling process is not permitted to write to the file
// E_OK If the log channel was successfully closed
_hzfunc("hzLogger::_write") ;
uint32_t nSize ; // Size of logserver client request
uint32_t nProcID ; // Caller process id
// If log channel not open just return
if (!IsOpen())
return E_OK ;
/*
** If log channel is using a direct file
*/
if (m_nSessID == 0)
{
/*
if (m_bVerbose)
{
std::cout.write(m_pDataPtr, nBytes) ;
fflush(stdout) ;
}
*/
if (m_pFile)
{
fwrite(m_pDataPtr, nBytes, 1, m_pFile) ;
fflush(m_pFile) ;
}
return E_OK ;
}
/*
** Log channel is using the logserver
*/
uchar* u = (uchar*) m_cvData ; // Pointer into logserver transport buffer
nSize = 11 + nBytes ;
nProcID = getpid() ;
// Command
u[0] = LS_LOG ;
// Size of message
u[1] = (nSize & 0xff00) >> 8 ;
u[2] = (nSize & 0xff) ;
// Session ID is 0 in this case
u[3] = (m_nSessID & 0xff0000) >> 16 ;
u[4] = (m_nSessID & 0xff00) >> 8 ;
u[5] = (m_nSessID & 0xff) ;
// Process ID
u[6] = (nProcID & 0xff00) >> 24 ;
u[7] = (nProcID & 0xff00) >> 16 ;
u[8] = (nProcID & 0xff00) >> 8 ;
u[9] = (nProcID & 0xff) ;
// Send message
if (m_pConnection->Send(m_cvData, nSize) != E_OK)
return E_SENDFAIL ;
if (m_pConnection->Recv(m_cvData, nSize, 64) != E_OK)
return E_RECVFAIL ;
if (m_cvData[0] == LS_OK)
return E_OK ;
return E_PROTOCOL ;
}
hzEcode hzLogger::Log (const char* va_alist ...)
{
// Log a variable argument message to the log channel. Deprecated as the hzFuncname class is to be reviewed.
//
// Arguments: va_alist Variable argument format string
//
// Returns: E_SENDFAIL If logging is to the logserver and could not be sent
// E_RECVFAIL If logging is to the logserver and acknowledgemnt was not recieved
// E_PROTOCOL If logging is to the logserver and said logserver did not observe protocol
// E_OK If the log action was completed
//_hzfunc("hzLogger::Log") ;
va_list ap1 ; // Variable arguments list
va_list ap2 ; // Copy of variable arguments list
const char* fmt ; // Format control string
uchar* u ; // Pointer into message buffer
uint32_t i ; // Indent counter
uint32_t nSize ; // Size of logserver client request
uint32_t nProcID ; // Caller process id
va_start(ap1, va_alist) ;
va_copy(ap2, ap1) ;
fmt = va_alist ;
// If log channel not open just return
if (!IsOpen())
return E_OK ;
if (m_nSessID == 0)
{
// Log channel is using a direct file
m_Lock.Lock() ;
_logrotate() ;
if (m_bVerbose)
{
for (i = m_nIndent ; i ; i--)
printf("\t") ;
printf("T%uL%d: %04d/%02d/%02d-%02d:%02d:%02d.%06d %s:\t",
_hzGlobal_currProc->GetId(),
_hzGlobal_currProc->Level(),
m_datCurr.Year(), m_datCurr.Month(), m_datCurr.Day(), m_datCurr.Hour(), m_datCurr.Min(), m_datCurr.Sec(), m_datCurr.uSec(),
_hzGlobal_currProc->GetCurrFunc()) ;
// Print supplied message
vprintf(fmt, ap1) ;
va_end(ap1) ;
fflush(stdout) ;
}
if (m_pFile)
{
for (i = m_nIndent ; i ; i--)
fprintf(m_pFile, "\t") ;
fprintf(m_pFile, "T%uL%d: %04d/%02d/%02d-%02d:%02d:%02d.%06d %s:\t",
_hzGlobal_currProc->GetId(),
_hzGlobal_currProc->Level(),
m_datCurr.Year(), m_datCurr.Month(), m_datCurr.Day(), m_datCurr.Hour(), m_datCurr.Min(), m_datCurr.Sec(), m_datCurr.uSec(),
_hzGlobal_currProc->GetCurrFunc()) ;
// Write supplied message to logfile
vfprintf(m_pFile, fmt, ap2) ;
va_end(ap2) ;
fflush(m_pFile) ;
}
m_Lock.Unlock() ;
return E_OK ;
}
// Log channel is using the logserver
u = (uchar*) m_cvData ;
vsprintf(m_cvData + 10, fmt, ap1) ;
nSize = 11 + strlen(m_cvData + 10) ;
nProcID = getpid() ;
// Command
u[0] = LS_LOG ;
// Size of message
u[1] = (nSize & 0xff00) >> 8 ;
u[2] = (nSize & 0xff) ;
// Session ID is 0 in this case
u[3] = (m_nSessID & 0xff0000) >> 16 ;
u[4] = (m_nSessID & 0xff00) >> 8 ;
u[5] = (m_nSessID & 0xff) ;
// Process ID
u[6] = (nProcID & 0xff00) >> 24 ;
u[7] = (nProcID & 0xff00) >> 16 ;
u[8] = (nProcID & 0xff00) >> 8 ;
u[9] = (nProcID & 0xff) ;
// Send message
if (m_pConnection->Send(m_cvData, nSize) != E_OK)
return E_SENDFAIL ;
if (m_pConnection->Recv(m_cvData, nSize, 64) != E_OK)
return E_RECVFAIL ;
if (m_cvData[0] == LS_OK)
return E_OK ;
return E_PROTOCOL ;
}
hzEcode hzLogger::Log (const hzChain& Z)
{
// Writes out the supplied chain to the logfile 'as is' with no time-stamp or other supporting information.
//
// Arguments: 1) Z Chain to output to logfile
//
// Returns: E_SENDFAIL If logging is to the logserver and could not be sent
// E_RECVFAIL If logging is to the logserver and acknowledgemnt was not recieved
// E_PROTOCOL If logging is to the logserver and said logserver did not observe protocol
// E_OK If the log action was completed
hzChain::Iter zi ; // Message chain iterator
char* i ; // For population of buffer
int32_t n ; // Indent counter
uint32_t nBytes ; // Number of bytes in buffer
hzEcode rc = E_OK ; // Return code
// m_Temp.Clear() ;
if (Z.Size())
{
m_Lock.Lock() ;
_logrotate() ;
if (m_bVerbose)
{
for (n = m_nIndent ; n ; n--)
printf("\t") ;
printf("T%uL%d: %04d/%02d/%02d-%02d:%02d:%02d.%06d %s:\t",
_hzGlobal_currProc->GetId(),
_hzGlobal_currProc->Level(),
m_datCurr.Year(), m_datCurr.Month(), m_datCurr.Day(), m_datCurr.Hour(), m_datCurr.Min(), m_datCurr.Sec(), m_datCurr.uSec(),
_hzGlobal_currProc->GetCurrFunc()) ;
std::cout << Z ;
}
// Write to file
for (n = m_nIndent ; n ; n--)
fprintf(m_pFile, "\t") ;
fprintf(m_pFile, "T%uL%d: %04d/%02d/%02d-%02d:%02d:%02d.%06d %s:\t",
_hzGlobal_currProc->GetId(),
_hzGlobal_currProc->Level(),
m_datCurr.Year(), m_datCurr.Month(), m_datCurr.Day(), m_datCurr.Hour(), m_datCurr.Min(), m_datCurr.Sec(), m_datCurr.uSec(),
_hzGlobal_currProc->GetCurrFunc()) ;
for (zi = Z ; rc == E_OK && !zi.eof() ;)
{
for (i = m_pDataPtr, nBytes = 0 ; !zi.eof() && nBytes < HZ_LOGCHUNK ; nBytes++, zi++)
*i++ = *zi ;
if (!nBytes)
break ;
m_pDataPtr[nBytes] = 0 ;
rc = _write(nBytes) ;
}
m_Lock.Unlock() ;
}
return rc ;
}
hzEcode hzLogger::Out (const hzChain& Z)
{
// Writes out the supplied chain to the logfile 'as is' with no time-stamp or other supporting information.
//
// Arguments: 1) Z Chain to output to logfile
//
// Returns: E_SENDFAIL If logging is to the logserver and could not be sent
// E_RECVFAIL If logging is to the logserver and acknowledgemnt was not recieved
// E_PROTOCOL If logging is to the logserver and said logserver did not observe protocol
// E_OK If the log action was completed
//_hzfunc("hzLogger::Out(hzChain)") ;
hzChain::Iter zi ; // Message chain iterator
char* i ; // For population of buffer
uint32_t nBytes ; // Number of bytes in buffer
hzEcode rc = E_OK ; // Return code
if (!_hzGlobal_currProc)
{
printf("Fatal - no current process\n") ;
exit(-1) ;
}
if (Z.Size())
{
m_Lock.Lock() ;
_logrotate() ;
if (m_bVerbose)
std::cout << Z ;
if (m_pFile)
{
for (zi = Z ; rc == E_OK && !zi.eof() ;)
{
for (i = m_pDataPtr, nBytes = 0 ; !zi.eof() && nBytes < HZ_LOGCHUNK ; nBytes++, zi++)
*i++ = *zi ;
if (!nBytes)
break ;
m_pDataPtr[nBytes] = 0 ;
rc = _write(nBytes) ;
}
}
m_Lock.Unlock() ;
}
return rc ;
}
hzEcode hzLogger::Out (const char* va_alist ...)
{
// Writes out the supplied character string with varags to the logfile 'as is' with no time-stamp or other supporting information.
//
// Arguments: 1) va_alist Variable argument format string
//
// Returns: E_SENDFAIL If logging is to the logserver and could not be sent
// E_RECVFAIL If logging is to the logserver and acknowledgemnt was not recieved
// E_PROTOCOL If logging is to the logserver and said logserver did not observe protocol
// E_OK If the log action was completed
//_hzfunc("hzLogger::Out(...)") ;
va_list ap1 ; // Variable arguments list
va_list ap2 ; // Copy of variable arguments list
const char* fmt ; // Format control string
uchar* u ; // Pointer into message buffer
uint32_t i ; // Indent counter
uint32_t nSize ; // Size of logserver client request
uint32_t nProcID ; // Caller process id
va_start(ap1, va_alist) ;
va_copy(ap2, ap1) ;
fmt = va_alist ;
// m_Temp.Clear() ;
// If log channel not open just return
if (!IsOpen())
return E_OK ;
// If log channel is using a direct file
if (m_nSessID == 0)
{
m_Lock.Lock() ;
_logrotate() ;
if (m_bVerbose)
{
for (i = m_nIndent ; i ; i--)
printf("\t") ;
vprintf(fmt, ap1) ;
va_end(ap1) ;
fflush(stdout) ;
}
if (m_pFile)
{
for (i = m_nIndent ; i ; i--)
fprintf(m_pFile, "\t") ;
vfprintf(m_pFile, fmt, ap2) ;
va_end(ap2) ;
fflush(m_pFile) ;
}
m_Lock.Unlock() ;
return E_OK ;
}
// Log channel is using the logserver
u = (uchar*) m_cvData ;
vsprintf(m_cvData + 10, fmt, ap1) ;
nSize = 11 + strlen(m_cvData + 10) ;
nProcID = getpid() ;
// Command
u[0] = LS_LOG ;
// Size of message
u[1] = (nSize & 0xff00) >> 8 ;
u[2] = (nSize & 0xff) ;
// Session ID is 0 in this case
u[3] = (m_nSessID & 0xff0000) >> 16 ;
u[4] = (m_nSessID & 0xff00) >> 8 ;
u[5] = (m_nSessID & 0xff) ;
// Process ID
u[6] = (nProcID & 0xff00) >> 24 ;
u[7] = (nProcID & 0xff00) >> 16 ;
u[8] = (nProcID & 0xff00) >> 8 ;
u[9] = (nProcID & 0xff) ;
// Send message
if (m_pConnection->Send(m_cvData, nSize) != E_OK)
return E_SENDFAIL ;
if (m_pConnection->Recv(m_cvData, nSize, 64) != E_OK)
return E_RECVFAIL ;
if (m_cvData[0] == LS_OK)
return E_OK ;
return E_PROTOCOL ;
}
hzLogger& hzLogger::operator<< (hzChain& Z)
{
// Stream operator so that an entire hzChain contents can be output to the logfile.
//
// Arguments: 1) Z Chain to aggregate to logger
//
// Returns: Reference to this logger
//_hzfunc("hzLogger::operator<<(hzChain)") ;
hzChain::Iter zi ; // Message chain iterator
char* i ; // For population of buffer
uint32_t nBytes ; // Number of bytes in buffer
hzEcode rc = E_OK ; // Return code
// m_Temp.Clear() ;
if (Z.Size())
{
m_Lock.Lock() ;
_logrotate() ;
if (m_bVerbose)
{
std::cout.write(m_pDataPtr, nBytes) ;
fflush(stdout) ;
}
zi = Z ;
for (; rc == E_OK ;)
{
for (i = m_pDataPtr, nBytes = 0 ; !zi.eof() && nBytes < HZ_LOGCHUNK ; nBytes++, zi++)
*i++ = *zi ;
if (!nBytes)
break ;
m_pDataPtr[nBytes] = 0 ;
rc = _write(nBytes) ;
}
m_Lock.Unlock() ;
}
return *this ;
}
hzLogger& hzLogger::operator<< (hzString& S)
{
// Stream operator so that a hzString can be output to the logfile.
//
// Arguments: 1) S String to aggregate to logger
//
// Returns: Reference to this logger
//_hzfunc("hzLogger::operator<<(hzString)") ;
const char* i ; // Message as null terminated string
char* j ; // Message iterator
uint32_t nBytes ; // Size of message
hzEcode rc = E_OK ; // Return code
// m_Temp.Clear() ;
if (S.Length())
{
m_Lock.Lock() ;
_logrotate() ;
i = *S ;
for (; rc == E_OK ;)
{
for (j = m_pDataPtr, nBytes = 0 ; *i && nBytes < HZ_LOGCHUNK ; nBytes++)
*j++ = *i++ ;
if (!nBytes)
break ;
m_pDataPtr[nBytes] = 0 ;
rc = _write(nBytes) ;
}
m_Lock.Unlock() ;
}
return *this ;
}
hzLogger& hzLogger::operator<< (const char* str)
{
// Stream operator so that a char string can be output to the logfile.
//
// Arguments: 1) str Char string to aggregate to logger
//
// Returns: Reference to this logger
//_hzfunc("hzLogger::operator<<(cstr)") ;
const char* i ; // Message as null terminated string
char* j ; // Message iterator
uint32_t nBytes ; // Size of message
hzEcode rc = E_OK ; // Return code
// m_Temp.Clear() ;
if (str && str[0])
{
m_Lock.Lock() ;
_logrotate() ;
i = str ;
for (; rc == E_OK ;)
{
for (j = m_pDataPtr, nBytes = 0 ; *i && nBytes < HZ_LOGCHUNK ; nBytes++)
*j++ = *i++ ;
if (!nBytes)
break ;
m_pDataPtr[nBytes] = 0 ;
rc = _write(nBytes) ;
}
m_Lock.Unlock() ;
}
return *this ;
}
hzEcode threadLog (const char* va_alist ...)
{
// Category: Diagnostics
//
// Write message supplied as a vararg CStr to the defualt log-channel of the current thread. If there is no defualt log-channel open, the message is written to stdout.
//
// Arguments: 1) va_alist Variable args format string
//
// Returns: E_SENDFAIL If logging is to the logserver and could not be sent
// E_RECVFAIL If logging is to the logserver and acknowledgemnt was not recieved
// E_PROTOCOL If logging is to the logserver and said logserver did not observe protocol
// E_OK If the log action was completed
//_hzfunc("threadLog(va_alist)") ;
va_list ap ; // Variable argument list
hzLogger* plog ; // The calling thread's logfile
hzChain errmsg ; // The log message
// Do the varargs
va_start(ap, va_alist) ;
errmsg._vainto(va_alist, ap) ;
va_end(ap) ;
// Obtain the log if available
plog = GetThreadLogger() ;
if (!plog)
{
std::cout << errmsg ;
fflush(stdout) ;
return E_NOINIT ;
}
// Do the log
return plog->Log(errmsg) ;
}
hzEcode threadLog (const hzChain& msg)
{
// Category: Diagnostics
//
// Write message supplied as a chain to the defualt log-channel of the current thread. If there is no defualt log-channel open, the message is written to stdout.
//
// Arguments: 1) msg Output message as chain
//
// Returns: E_SENDFAIL If logging is to the logserver and could not be sent
// E_RECVFAIL If logging is to the logserver and acknowledgemnt was not recieved
// E_PROTOCOL If logging is to the logserver and said logserver did not observe protocol
// E_OK If the log action was completed
//_hzfunc("threadLog(chain)") ;
hzLogger* plog ; // The calling thread's logfile
plog = GetThreadLogger() ; //phz ? phz->GetLog() : 0 ;
if (!plog)
{
std::cout << msg ;
fflush(stdout) ;
return E_NOINIT ;
}
return plog->Log(msg) ;
}
hzEcode threadOut (const char* va_alist ...)
{
// Category: Diagnostics
//
// Write message supplied as a vararg CStr to the defualt log-channel of the current thread. If there is no defualt log-channel open, the message is written to stdout.
//
// Arguments: 1) va_alist Variable args format string
//
// Returns: E_SENDFAIL If logging is to the logserver and could not be sent
// E_RECVFAIL If logging is to the logserver and acknowledgemnt was not recieved
// E_PROTOCOL If logging is to the logserver and said logserver did not observe protocol
// E_OK If the log action was completed
//_hzfunc("threadLog(va_alist)") ;
va_list ap ; // Variable argument list
hzLogger* plog ; // The calling thread's logfile
hzChain errmsg ; // The log message
// Do the varargs
va_start(ap, va_alist) ;
errmsg._vainto(va_alist, ap) ;
va_end(ap) ;
// Obtain the log if available
plog = GetThreadLogger() ;
if (!plog)
{
std::cout << errmsg ;
fflush(stdout) ;
return E_NOINIT ;
}
// Do the log
return plog->Out(errmsg) ;
}
hzEcode threadOut (const hzChain& msg)
{
// Category: Diagnostics
//
// Write message supplied as a chain to the defualt log-channel of the current thread. If there is no defualt log-channel open, the message is written to stdout.
//
// Arguments: 1) msg Output message as chain
//
// Returns: E_SENDFAIL If logging is to the logserver and could not be sent
// E_RECVFAIL If logging is to the logserver and acknowledgemnt was not recieved
// E_PROTOCOL If logging is to the logserver and said logserver did not observe protocol
// E_OK If the log action was completed
//_hzfunc("threadLog(chain)") ;
hzLogger* plog ; // The calling thread's logfile
plog = GetThreadLogger() ; //phz ? phz->GetLog() : 0 ;
if (!plog)
{
std::cout << msg ;
fflush(stdout) ;
return E_NOINIT ;
}
return plog->Out(msg) ;
}