/*++ Copyright (c) 1996-1999 Microsoft Corporation Module Name : asclogc.cpp Abstract: MS Logging Format implementation Author: Terence Kwan ( terryk ) 18-Sep-1996 Project: IIS Logging 3.0 --*/ #include "precomp.hxx" #include #include #include #include "LogScript.hxx" #include #include "filectl.hxx" #include "asclogc.hxx" CHAR szAsciiNoPeriodPattern[] = "inetsv*.log"; // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- CASCLOG::CASCLOG() { } // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- CASCLOG::~CASCLOG() { } // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- LPCSTR CASCLOG::QueryNoPeriodPattern( VOID ) { return szAsciiNoPeriodPattern; } // CASCLOG::QueryNoPeriodPattern // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- VOID CASCLOG::FormNewLogFileName( IN LPSYSTEMTIME pstNow ) /*++ This function that forms the new log file name based on type of periodic logging done. Arguments: pstNow pointer to SystemTime which contains the current time. fBackup flag indicating if we want to make current file a backup. Returns: TRUE on success in forming the name or FALSE if there is any error. --*/ { I_FormNewLogFileName(pstNow,DEFAULT_LOG_FILE_NAME); return; } // INET_FILE_LOG::FormNewLogFileName() // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- VOID FormatLogDwords( IN IInetLogInformation * pLogObj, IN LPSTR *pBuffer, IN DWORD *pcbSize, IN PDWORD pRequired ) { CHAR tmpBuf[32]; DWORD cbTmp; // // Processing Time // cbTmp = FastDwToA( tmpBuf, pLogObj->GetTimeForProcessing() ); *pRequired += cbTmp; if ( *pRequired <= *pcbSize ) { tmpBuf[cbTmp] = ','; tmpBuf[cbTmp+1] = ' '; CopyMemory(*pBuffer, tmpBuf, cbTmp+2); *pBuffer += cbTmp+2; } // // Bytes Received // cbTmp = FastDwToA( tmpBuf, pLogObj->GetBytesRecvd() ); *pRequired += cbTmp; if ( *pRequired <= *pcbSize ) { tmpBuf[cbTmp] = ','; tmpBuf[cbTmp+1] = ' '; CopyMemory(*pBuffer, tmpBuf, cbTmp+2); *pBuffer += cbTmp+2; } // // Bytes Sent // cbTmp = FastDwToA( tmpBuf, pLogObj->GetBytesSent() ); *pRequired += cbTmp; if ( *pRequired <= *pcbSize ) { tmpBuf[cbTmp] = ','; tmpBuf[cbTmp+1] = ' '; CopyMemory(*pBuffer, tmpBuf, cbTmp+2); *pBuffer += cbTmp+2; } // // HTTP Status // cbTmp = FastDwToA( tmpBuf, pLogObj->GetProtocolStatus() ); *pRequired += cbTmp; if ( *pRequired <= *pcbSize ) { tmpBuf[cbTmp] = ','; tmpBuf[cbTmp+1] = ' '; CopyMemory(*pBuffer, tmpBuf, cbTmp+2); *pBuffer += cbTmp+2; } // // Win32 status // cbTmp = FastDwToA( tmpBuf, pLogObj->GetWin32Status() ); *pRequired += cbTmp; if ( *pRequired <= *pcbSize ) { tmpBuf[cbTmp] = ','; tmpBuf[cbTmp+1] = ' '; CopyMemory(*pBuffer, tmpBuf, cbTmp+2); *pBuffer += cbTmp+2; } return; } // FormatLogDwords // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- BOOL CASCLOG::FormatLogBuffer( IN IInetLogInformation *pLogObj, IN LPSTR pBuf, IN DWORD *pcbSize, OUT SYSTEMTIME *pSystemTime ) { CHAR rgchDateTime[ 32]; PCHAR pBuffer = pBuf; PCHAR pTmp; DWORD cbTmp; DWORD nRequired; if ( pBuf == NULL ) { return ERROR_INVALID_PARAMETER; } // // Format is: // Host UserName Date Time Service ComputerName ServerIP // msProcessingTime bytesR bytesS protocolStat Win32Stat // Operation Target Parameters // // // Host ID // pTmp = pLogObj->GetClientHostName( NULL, &cbTmp ); if ( cbTmp == 0 ) { cbTmp = 1; pTmp = "-"; } nRequired = cbTmp + 2; // 2 for delimiter if ( nRequired <= *pcbSize ) { CopyMemory(pBuffer, pTmp, cbTmp); pBuffer += cbTmp; *(pBuffer++) = ','; *(pBuffer++) = ' '; } // // UserName // pTmp = pLogObj->GetClientUserName( NULL, &cbTmp ); if ( cbTmp == 0 ) { cbTmp = 1; pTmp = "-"; } nRequired += cbTmp + 2; //2 for delimiter if ( nRequired <= *pcbSize ) { CopyMemory(pBuffer, pTmp, cbTmp); pBuffer += cbTmp; *(pBuffer++) = ','; *(pBuffer++) = ' '; } // // Date/Time (already delimited) // m_DateTimeCache.SetLocalTime(pSystemTime); cbTmp = m_DateTimeCache.GetFormattedDateTime(pSystemTime,rgchDateTime); nRequired += cbTmp; if ( nRequired <= *pcbSize ) { CopyMemory(pBuffer, rgchDateTime, cbTmp); pBuffer += cbTmp; } // // Site Name // pTmp = pLogObj->GetSiteName( NULL, &cbTmp ); if ( cbTmp == 0 ) { cbTmp = 1; pTmp = "-"; } nRequired += cbTmp + 2; // 2 for delimiter if ( nRequired <= *pcbSize ) { CopyMemory(pBuffer, pTmp, cbTmp); pBuffer += cbTmp; *(pBuffer++) = ','; *(pBuffer++) = ' '; } // // ComputerName // pTmp = pLogObj->GetComputerName( NULL, &cbTmp ); if ( cbTmp == 0 ) { cbTmp = 1; pTmp = "-"; } nRequired += cbTmp + 2; // 2 for delimiter if ( nRequired <= *pcbSize ) { CopyMemory(pBuffer, pTmp, cbTmp); pBuffer += cbTmp; *(pBuffer++) = ','; *(pBuffer++) = ' '; } // // Server IP // pTmp = pLogObj->GetServerAddress( NULL, &cbTmp ); if ( cbTmp == 0 ) { cbTmp = 1; pTmp = "-"; } nRequired += cbTmp + 2; // 2 for delimiter if ( nRequired <= *pcbSize ) { CopyMemory(pBuffer, pTmp, cbTmp); pBuffer += cbTmp; *(pBuffer++) = ','; *(pBuffer++) = ' '; } // // Use fast path ? // All numbers are < 4G (10 charaters) // add 2 per number for delimiters // so we need 10 * 5 numbers == 30 bytes // nRequired += 10; // 10 for delimiters of 5 numbers if ( (nRequired + 50) <= *pcbSize ) { // // Processing Time // cbTmp = FastDwToA( pBuffer, pLogObj->GetTimeForProcessing() ); nRequired += cbTmp; pBuffer += cbTmp; *(pBuffer++) = ','; *(pBuffer++) = ' '; // // Bytes Received // cbTmp = FastDwToA( pBuffer, pLogObj->GetBytesRecvd() ); nRequired += cbTmp; pBuffer += cbTmp; *(pBuffer++) = ','; *(pBuffer++) = ' '; // // Bytes Sent // cbTmp = FastDwToA( pBuffer, pLogObj->GetBytesSent() ); nRequired += cbTmp; pBuffer += cbTmp; *(pBuffer++) = ','; *(pBuffer++) = ' '; // // HTTP Status // cbTmp = FastDwToA( pBuffer, pLogObj->GetProtocolStatus() ); nRequired += cbTmp; pBuffer += cbTmp; *(pBuffer++) = ','; *(pBuffer++) = ' '; // // Win32 status // cbTmp = FastDwToA( pBuffer, pLogObj->GetWin32Status() ); nRequired += cbTmp; pBuffer += cbTmp; *(pBuffer++) = ','; *(pBuffer++) = ' '; } else { FormatLogDwords( pLogObj, &pBuffer, pcbSize, &nRequired ); } // // Operation // pTmp = pLogObj->GetOperation( NULL, &cbTmp ); if ( cbTmp == 0 ) { cbTmp = 1; pTmp = "-"; } nRequired += cbTmp + 2; // 2 for delimiter if ( nRequired <= *pcbSize ) { CopyMemory(pBuffer, pTmp, cbTmp); pBuffer += cbTmp; *(pBuffer++) = ','; *(pBuffer++) = ' '; } // // Target // pTmp = pLogObj->GetTarget( NULL, &cbTmp ); if ( cbTmp == 0 ) { cbTmp = 1; pTmp = "-"; } nRequired += cbTmp + 2; // 2 for delimiter if ( nRequired <= *pcbSize ) { CopyMemory(pBuffer, pTmp, cbTmp); pBuffer += cbTmp; *(pBuffer++) = ','; *(pBuffer++) = ' '; } // // Parameters // pTmp = pLogObj->GetParameters( NULL, &cbTmp ); if ( cbTmp == 0 ) { cbTmp = 1; pTmp = "-"; } nRequired += cbTmp + 1 + 2; // 1 for delimiter, 2 for EOL if ( nRequired <= *pcbSize ) { CopyMemory(pBuffer, pTmp, cbTmp); pBuffer += cbTmp; // NOTE // Documentation is ambiguous about the presence of a comma // at the end of the log record, but the comma is required // for backward compatability with site server *(pBuffer++) = ','; *(pBuffer++) = '\r'; *(pBuffer++) = '\n'; } if ( nRequired > *pcbSize ) { *pcbSize = nRequired; SetLastError(ERROR_INSUFFICIENT_BUFFER); return(FALSE); } else { *pcbSize = nRequired; return(TRUE); } } // FormatLogBuffer // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- HRESULT CASCLOG::ReadFileLogRecord( IN FILE *fpLogFile, IN LPINET_LOGLINE pInetLogLine, IN PCHAR pszLogLine, IN DWORD dwLogLineSize ) { CHAR * pCh; CHAR * szDateString, * szTimeString; getnewline: pCh = pszLogLine; if (fgets(pCh, dwLogLineSize, fpLogFile) == NULL) { return E_FAIL; } pCh = SkipWhite(pCh); if (('\n' == *pCh) || ('\0' == *pCh)) { // Empty line. Get Next line goto getnewline; } // // We have a log line. Parse it. // // Format is: // Host UserName Date Time Service ComputerName ServerIP // msProcessingTime bytesR bytesS protocolStat Win32Stat // Operation Target Parameters // if ( NULL == (pCh = strtok(pCh,",")) ) { return E_FAIL; } while (isspace((UCHAR)(*pCh))) pCh++; pInetLogLine->pszClientHostName = pCh; if ( NULL == (pCh = strtok(NULL,",")) ) { return E_FAIL; } while (isspace((UCHAR)(*pCh))) pCh++; pInetLogLine->pszClientUserName = pCh; // // Date & Time. // if ( NULL == (pCh = strtok(NULL,",")) ) { return E_FAIL; } while (isspace((UCHAR)(*pCh))) pCh++; szDateString = pCh; if ( NULL == (pCh = strtok(NULL,",")) ) { return E_FAIL; } while (isspace((UCHAR)(*pCh))) pCh++; szTimeString = pCh; if ( ! ConvertASCDateToVariantDate(szDateString, szTimeString, &(pInetLogLine->DateTime)) ) { return E_FAIL; } // // Service & Server information // if ( NULL == (pCh = strtok(NULL,",")) ) { return E_FAIL; } while (isspace((UCHAR)(*pCh))) pCh++; pInetLogLine->pszSiteName = pCh; if ( NULL == (pCh = strtok(NULL,",")) ) { return E_FAIL; } while (isspace((UCHAR)(*pCh))) pCh++; pInetLogLine->pszComputerName = pCh; if ( NULL == (pCh = strtok(NULL,",")) ) { return E_FAIL; } while (isspace((UCHAR)(*pCh))) pCh++; pInetLogLine->pszServerAddress = pCh; // // Statistics - processing time, bytes recvd, bytes sent // if ( NULL == (pCh = strtok(NULL,",")) ) { return E_FAIL; } while (isspace((UCHAR)(*pCh))) pCh++; pInetLogLine->pszTimeForProcessing = pCh; if ( NULL == (pCh = strtok(NULL,",")) ) { return E_FAIL; } while (isspace((UCHAR)(*pCh))) pCh++; pInetLogLine->pszBytesRecvd = pCh; if ( NULL == (pCh = strtok(NULL,",")) ) { return E_FAIL; } while (isspace((UCHAR)(*pCh))) pCh++; pInetLogLine->pszBytesSent = pCh; // // Status information - protocol, Win32 // if ( NULL == (pCh = strtok(NULL,",")) ) { return E_FAIL; } while (isspace((UCHAR)(*pCh))) pCh++; pInetLogLine->pszProtocolStatus = pCh; if ( NULL == (pCh = strtok(NULL,",")) ) { return E_FAIL; } while (isspace((UCHAR)(*pCh))) pCh++; pInetLogLine->pszWin32Status = pCh; // // Request information - operation, target, parameters // if ( NULL == (pCh = strtok(NULL,",")) ) { return E_FAIL; } while (isspace((UCHAR)(*pCh))) pCh++; pInetLogLine->pszOperation = pCh; if ( NULL == (pCh = strtok(NULL,",")) ) { return E_FAIL; } while (isspace((UCHAR)(*pCh))) pCh++; pInetLogLine->pszTarget = pCh; if ( NULL == (pCh = strtok(NULL," ,\t\r\n")) ) { return E_FAIL; } while (isspace((UCHAR)(*pCh))) pCh++; pInetLogLine->pszParameters = pCh; return S_OK; } // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- HRESULT CASCLOG::WriteFileLogRecord( IN FILE *fpLogFile, IN ILogScripting *pILogScripting, IN bool ) { HRESULT hr = E_FAIL; CHAR szLogLine[4096]; DWORD dwIndex = 0; // // Format is: // Host, UserName, Date, Time, Service, ComputerName, ServerIP, // msProcessingTime, bytesR, bytesS, protocolStat, Win32Stat, // Operation, Target, Parameters, // VARIANT szHostName, szUserName, szServiceName, szComputerName; VARIANT szServerIP, szOperation, szTarget, szParameters; VARIANT DateTime; VARIANT lTimeForProcessing, lBytesSent, lBytesRecvd, lProtocolStatus, lWin32Status; SYSTEMTIME sysTime; CHAR rgchDateTime[ 32]; if (SUCCEEDED(pILogScripting->get_ClientIP ( &szHostName)) && SUCCEEDED(pILogScripting->get_UserName ( &szUserName)) && SUCCEEDED(pILogScripting->get_DateTime ( &DateTime)) && SUCCEEDED(pILogScripting->get_ServiceName ( &szServiceName)) && SUCCEEDED(pILogScripting->get_ServerName ( &szComputerName)) && SUCCEEDED(pILogScripting->get_ServerIP ( &szServerIP)) && SUCCEEDED(pILogScripting->get_TimeTaken ( &lTimeForProcessing)) && SUCCEEDED(pILogScripting->get_BytesReceived ( &lBytesRecvd)) && SUCCEEDED(pILogScripting->get_BytesSent ( &lBytesSent)) && SUCCEEDED(pILogScripting->get_ProtocolStatus( &lProtocolStatus)) && SUCCEEDED(pILogScripting->get_Win32Status ( &lWin32Status)) && SUCCEEDED(pILogScripting->get_Method ( &szOperation)) && SUCCEEDED(pILogScripting->get_URIStem ( &szTarget)) && SUCCEEDED(pILogScripting->get_URIQuery ( &szParameters)) && VariantTimeToSystemTime( DateTime.date, &sysTime) ) { m_DateTimeCache.GetFormattedDateTime( &sysTime, rgchDateTime); dwIndex = sprintf(szLogLine, "%ws, %ws, %s%ws, %ws, %ws,", GetBstrFromVariant( &szHostName), GetBstrFromVariant( &szUserName), rgchDateTime, // This guy already contains a trailing ", " GetBstrFromVariant( &szServiceName), GetBstrFromVariant( &szComputerName), GetBstrFromVariant( &szServerIP) ); szLogLine[dwIndex++] = ' '; dwIndex += GetLongFromVariant( &lTimeForProcessing, szLogLine+dwIndex) ; szLogLine[dwIndex++] = ','; szLogLine[dwIndex++] = ' '; dwIndex += GetLongFromVariant( &lBytesRecvd, szLogLine+dwIndex); szLogLine[dwIndex++] = ','; szLogLine[dwIndex++] = ' '; dwIndex += GetLongFromVariant( &lBytesSent, szLogLine+dwIndex); szLogLine[dwIndex++] = ','; szLogLine[dwIndex++] = ' '; dwIndex += GetLongFromVariant( &lProtocolStatus, szLogLine+dwIndex); szLogLine[dwIndex++] = ','; szLogLine[dwIndex++] = ' '; dwIndex += GetLongFromVariant( &lWin32Status, szLogLine+dwIndex); sprintf( szLogLine+dwIndex ,", %ws, %ws, %ws", GetBstrFromVariant( &szOperation), GetBstrFromVariant( &szTarget), GetBstrFromVariant( &szParameters) ); // Include a , at the end of the log record. See NOTE in // FormatLogBuffer for more details on why. fprintf(fpLogFile, "%s,\n", szLogLine); hr = S_OK; } return hr; } // ----------------------------------------------------------------------------- // ----------------------------------------------------------------------------- BOOL CASCLOG::ConvertASCDateToVariantDate(PCHAR szDateString, PCHAR szTimeString, DATE * pDateTime) { USES_CONVERSION; BOOL fSuccess = FALSE; HRESULT hr; LCID lcid; BSTR bstrDate; BSTR bstrTime; DATE dateTime; DATE dateDate; DECIMAL decDate; DECIMAL decTime; DECIMAL decDateTimeComposite; bstrDate = SysAllocString(A2OLE(szDateString)); bstrTime = SysAllocString(A2OLE(szTimeString)); if ((NULL == bstrDate) || (NULL == bstrTime)) { goto error_converting; } // // On IIS6, http.sys writes IIS log format always in US format // lcid = MAKELCID(MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), SORT_DEFAULT); hr = VarDateFromStr(bstrTime, lcid, LOCALE_NOUSEROVERRIDE, &dateTime); if (FAILED(hr)) { goto error_converting; } hr = VarDateFromStr(bstrDate, lcid, LOCALE_NOUSEROVERRIDE, &dateDate); if (FAILED(hr)) { goto error_converting; } hr = VarDecFromDate(dateDate, &decDate); if (FAILED(hr)) { goto error_converting; } hr = VarDecFromDate(dateTime, &decTime); if (FAILED(hr)) { goto error_converting; } hr = VarDecAdd(&decDate, &decTime, &decDateTimeComposite); if (FAILED(hr)) { goto error_converting; } hr = VarDateFromDec(&decDateTimeComposite, pDateTime); if (FAILED(hr)) { goto error_converting; } fSuccess = TRUE; error_converting: if (NULL != bstrDate) { SysFreeString(bstrDate); bstrDate = NULL; } if (NULL != bstrTime) { SysFreeString(bstrTime); bstrTime = NULL; } return fSuccess; } // ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------