ロギング機能が必要なこの種の問題に取り組むとき、私は通常、ロギングのために呼び出す関数を作成します。次に、ロギングを有効または無効にできるマクロで関数をラップします。この一環として、すべてのログがログ ファイルに書き込まれないように、デバッグ レベル インジケーターも使用することがあります。
ロギング関数は、個別の小さなライブラリとして単独でファイルに含まれます。ロギング ライブラリ関数のプロトタイプと、ロギングを有効または無効にするマクロを含むインクルード ファイルがあります。
各ログのタイムスタンプを秒単位またはミリ秒単位にするなど、アプリケーションの種類によっては、ログに役立つことがいくつかあることがわかりました。また、標準的な行の長さを使用すると、テキスト エディターでログを確認しやすくなることもわかりました。ソース ファイルのパスとソース行番号を把握しておくと、非常に役立ちます。
次のコードはフリーハンドで書かれており、テストもコンパイルもされていないため、1 つまたは 2 つのエラーがある可能性があります。
実際のロギング関数は、LogWriteLog()
次のようにマクロでラップされます。
#define LOGISSUELOG(level,logtext) LogWriteLog(level, logtext, __FILE__, __LINE__);
マクロを使用すると、マクロ定義を変更してロギングを有効または無効にすることができます。このマクロは、ソース ファイルのパスとログのソース行番号も自動的に生成します。
このため、ログの一部として変数が必要な場合は、これを次のプリプロセッサ コード シーケンスにラップすることがあります。中かっこを使用すると、複数の行をソースに挿入でき、ローカル スコープの char 変数を使用できます。
#if defined(LOGISSUELOG)
{
char xBuff[128];
sprintf (xBuff, "value 1 %d, error %d", iValue, iErrorStatus);
LOGISSUELOG(4, xBuff);
}
#endif
単純なログ ライブラリには、ログ ファイルを開いてデバッグ レベルを指定する関数、実際にログを作成する関数、完了時にログ ファイルを閉じる関数の 2 つしかありません。
標準の CI/O ルーチンを使用すると、実際のログ機能は次のようになります。string.h
これにもとが必要ですstdio.h
。また、再起動するたびにファイルを切り詰めるか、ファイルに追加するかを検討することもできます。
また、ファイルサイズをチェックして、特定のサイズに達するとfseek ()
、ファイルの先頭にラップアラウンドします。ラップアラウンドを行っている場合、タイムスタンプはほぼ必須になります。ラップアラウンドを行うと、すべてのログ行の標準行幅が実際に必要になる場合、物事が整列するようになります。
// allocate the file scope globals used by the logging library
static FILE *fpLogWriteLog = 0;
static int iLogDebugLevel = 0;
int LogOpenLog (int iDebugLevel, char *aszLogFilePath)
{
// open the log file for writing, truncating what is there already
fpLogWriteLog = fopen (aszLogFilePath, "w");
iLogDebugLevel = iDebugLevel;
return (fpLogWriteLog == 0) ? 0 : 1;
}
void LogCloseLog (void)
{
if (fpLogWriteLog)
fclose (fpLogWriteLog);
}
// allow the debug logging level to be changed.
//return the current value so that it can be used in another call to set it back.
int LogChangeLogLevel (int iDebugLevelNew)
{
int iDebugLevelSave = iLogDebugLevel;
iLogDebugLevel = iDebugLevelNew;
return iDebugLevelSave;
}
// write a log to the log file
int LogWriteLog (int iDebugLevel, char *aszLogText, char *aszFileName, int iLineNo)
{
int iRetStatus = 0;
if (fpLogWriteLog && iDebugLevel < iLogDebugLevel) {
int iLen = strlen (aszFileName);
// we will keep only the last 30 characters of the source file path
if (iLen > 30)
iLen = 30;
else
iLen = 0;
// use print specifiers to provide the same line width for the output log
// use %-60.60s to print log text in case of print format specifiers in it
fprintf (fpLogWriteLog, "%3.3d %-30.30s - %6.6d: %-60.60s", iDebugLevel, aszFileName + iLen, iLineNo, aszLogText);
fflush (fpLogWriteLog);
iRetStatus = 1;
}
return iRetStatus;
}