Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
FileLogging.c
/* |
File: FileLogging.c |
Contains: File logging engine for OTStreamLogViewer. |
Written by: Quinn "The Eskimo!" |
Copyright: © 1998 by Apple Computer, Inc., all rights reserved. |
Change History (most recent first): |
You may incorporate this sample code into your applications without |
restriction, though the sample code has been provided "AS IS" and the |
responsibility for its operation is 100% yours. However, what you are |
not permitted to do is to redistribute the source as "DSC Sample Code" |
after having made changes. If you're going to re-distribute the source, |
we require that you make it clear in the source that the code was |
descended from Apple Sample Code, but that you've made changes. |
*/ |
#define qDebug 1 |
///////////////////////////////////////////////////////////////////// |
// Standard C stuff. |
#include <stdio.h> |
// Pick up toolbox stuff. |
#include <OpenTransport.h> |
#include <Files.h> |
#include <TextUtils.h> |
#include <MacErrors.h> |
#include <Devices.h> |
// Pick up our resource definitions. |
#include "StreamLogResources.h" |
// Pick up our own prototypes. |
#include "FileLogging.h" |
///////////////////////////////////////////////////////////////////// |
// OTDebugStr is defined in a wacky OT library. Let's just use |
// lowercase debugstr instead. |
#define OTDebugStr debugstr |
///////////////////////////////////////////////////////////////////// |
static OSStatus FSWriteQAtLEOF(SInt16 fileRefNum, SInt32 count, void *buffer) |
// Writes the count bytes at buffer to the end of fileRefNum. |
{ |
ParamBlockRec pb; |
pb.ioParam.ioRefNum = fileRefNum; |
pb.ioParam.ioBuffer = buffer; |
pb.ioParam.ioReqCount = count; |
pb.ioParam.ioPosMode = fsFromLEOF; |
pb.ioParam.ioPosOffset = 0; |
return PBWriteSync(&pb); |
} |
///////////////////////////////////////////////////////////////////// |
// File Logging Stuff |
static SInt16 gLogFileRefNum = 0; |
// The file refnum of the log file, or 0 if logging |
// is not active. |
static char gLogAssemblyBuffer[10240]; |
// A temporary buffer used to assemble log text |
// we're about to write to the file. |
static UInt32 gTicksOfLastFileWrite; |
// The TickCount time at which we last wrote to the file. |
// If TickCount is more than this value plus |
// kTicksPerFlush, we need to flush the file now. |
enum { |
kTicksPerFlush = 6, |
// Number of ticks from when we write to a file to when |
// we perform a FlushFile to make sure it gets to the disk. |
kLogFileCleanTicks = (UInt32) -(kTicksPerFlush+1) |
// When the file is flushed we set gTicksOfLastFileWrite |
// to this value to prevent further writes from happening. |
// This corresponds to "far in the future". |
}; |
static char kStartFileLogString[] = "Sequence\tFlags\tFlags (as number)\tTime (ms)\tReal Time\tModule ID\tStream ID\tMessage\r"; |
// When we start logging, we write this line to the file |
// to give the user some idea of the what each column means. |
extern OSStatus StartFileLogging(void) |
// See comment in interface part. |
{ |
OSStatus err; |
Str255 logFileName; |
FSSpec logFile; |
OTAssert("StartFileLogging: We're already logging!", gLogFileRefNum == 0); |
gTicksOfLastFileWrite = kLogFileCleanTicks; |
// Open up the log file, creating it if necessary. |
GetIndString(logFileName, rMiscStrings, strLogFileName); |
err = FSMakeFSSpec(-1, fsRtDirID, logFileName, &logFile); |
if (err == fnfErr) { |
err = noErr; |
} |
if (err == noErr) { |
(void) FSpCreate(&logFile, 'R*ch', 'TEXT', 0); |
err = FSpOpenDF(&logFile, fsWrPerm, &gLogFileRefNum); |
if (err != noErr) { |
gLogFileRefNum = 0; |
} |
} |
// Write the header to the file. |
if (err == noErr) { |
err = FSWriteQAtLEOF(gLogFileRefNum, OTStrLength(kStartFileLogString), kStartFileLogString); |
} |
// Clean up. |
if (err != noErr) { |
if ( gLogFileRefNum != 0 ) { |
StopFileLogging(); |
} |
} |
return err; |
} |
enum { |
kFlagsToStringBufferSize = 50 |
// flagStr must point to a buffer of at least 50 characters. |
}; |
static void FlagsToString(char flags, char *flagStr) |
// Create a verbose string that represents the various |
// flag bits in flags. |
{ |
flagStr[0] = 0; |
if ((flags & SL_TRACE) != 0) { |
OTStrCat(flagStr, "Trace "); |
} |
if ((flags & SL_ERROR) != 0) { |
OTStrCat(flagStr, "Error "); |
} |
if ((flags & SL_CONSOLE) != 0) { |
OTStrCat(flagStr, "Console "); |
} |
if ((flags & SL_FATAL) != 0) { |
OTStrCat(flagStr, "Fatal "); |
} |
if ((flags & SL_NOTIFY) != 0) { |
OTStrCat(flagStr, "Notify "); |
} |
if ((flags & SL_WARN) != 0) { |
OTStrCat(flagStr, "Warning "); |
} |
if ((flags & SL_NOTE) != 0) { |
OTStrCat(flagStr, "Notice "); |
} |
// Remove the trailing space. |
if ( flagStr[0] != 0 ) { |
flagStr[ OTStrLength(flagStr) - 1 ] = 0; |
} |
} |
extern char *LogEntryToCString(LogEntryPtr thisEntry) |
// See comment in interface part. |
{ |
Str255 dateStr; |
Str255 timeStr; |
char flagStr[kFlagsToStringBufferSize]; |
OTAssert("LogEntryToCString: paramErr", thisEntry != nil); |
FlagsToString(thisEntry->fLogHeader.flags, flagStr); |
// ltime is generated by calling OTGetTimeStamp and converting |
// the result to milliseconds using OTTimeStampInMilliseconds. |
// ttime is the result of the low-memory global Time, which |
// is the same as the result of GetDateTime. |
DateString(thisEntry->fLogHeader.ttime, shortDate, dateStr, nil); |
TimeString(thisEntry->fLogHeader.ttime, true, timeStr, nil); |
sprintf(gLogAssemblyBuffer, "%ld\t%s\t0x%02x\t0x%08x\t%#s %#s\t%d\t%d\t%s\r", |
thisEntry->fLogHeader.seq_no, |
flagStr, |
thisEntry->fLogHeader.flags, |
thisEntry->fLogHeader.ltime, |
dateStr, |
timeStr, |
thisEntry->fLogHeader.mid, |
thisEntry->fLogHeader.sid, |
(char *) thisEntry + sizeof(LogEntry) |
); |
return gLogAssemblyBuffer; |
} |
extern void RecordLogEntryToFile(LogEntryPtr thisEntry) |
// See comment in interface part. |
{ |
OSStatus junk; |
if ( gLogFileRefNum != 0 ) { |
(void) LogEntryToCString(thisEntry); |
junk = FSWriteQAtLEOF(gLogFileRefNum, OTStrLength(gLogAssemblyBuffer), gLogAssemblyBuffer); |
OTAssert("RecordLogEntryToFile: Error writing log entry", junk == noErr); |
gTicksOfLastFileWrite = TickCount(); |
} |
} |
extern void FileLoggingIdle(void) |
// See comment in interface part. |
{ |
OSStatus junk; |
ParamBlockRec pb; |
if ( gLogFileRefNum != 0 ) { |
if ( TickCount() > gTicksOfLastFileWrite + kTicksPerFlush ) { |
pb.ioParam.ioRefNum = gLogFileRefNum; |
junk = PBFlushFileSync(&pb); |
OTAssert("DoIdle: FlushFile returned an error", junk == noErr); |
gTicksOfLastFileWrite = kLogFileCleanTicks; |
} |
} |
} |
extern Boolean FileLoggingActive(void) |
// See comment in interface part. |
{ |
return gLogFileRefNum != 0; |
} |
extern void StopFileLogging(void) |
// See comment in interface part. |
{ |
OSStatus junk; |
OTAssert("StopFileLogging: We're not logging!", gLogFileRefNum != 0); |
junk = FSClose(gLogFileRefNum); |
OTAssert("StopFileLogging: Could not close log file", junk == noErr); |
gLogFileRefNum = 0; |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-07-22