/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
// //
// plStatusLog Header //
// //
//// Description /////////////////////////////////////////////////////////////
// //
// plStatusLogs are our new encapsulated method of outputting text logs //
// for status (or other things, like, say, errors). They do more than just //
// output to the file, though; they maintain a scrolling buffer that //
// can be drawn on to the screen so you can actually view what's being //
// outputted to the log file (you can disable file writing if you wish). //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _plStatusLog_h
#define _plStatusLog_h
#include "hsTypes.h"
#include "hsThread.h"
#include
class plPipeline;
//// plStatusLog Definition //////////////////////////////////////////////////
// Currently, they all display in the same location, so only one should
// really be visible at any given time.
class plStatusLogMgr;
class hsMutex;
class plStatusLogDrawerStub;
class plStatusLog
{
friend class plStatusLogMgr;
friend class plStatusLogDrawerStub;
friend class plStatusLogDrawer;
protected:
mutable UInt32 fFlags; // Mutable so we can change it in IPrintLineToFile() internally
UInt32 fOrigFlags;
UInt32 fMaxNumLines;
std::string fCFilename; // used ONLY by GetFileName()
std::wstring fFilename;
char **fLines;
UInt32 *fColors;
hsMutex fMutex; // To make multithreaded-safe
FILE* fFileHandle;
UInt32 fSize;
bool fEncryptMe;
bool fForceLog;
plStatusLog *fNext, **fBack;
plStatusLog **fDisplayPointer; // Inside pfConsole
void IUnlink( void );
void ILink( plStatusLog **back );
bool IAddLine( const char *line, Int32 count, UInt32 color );
bool IPrintLineToFile( const char *line, UInt32 count );
void IParseFileName(wchar* file, size_t fnsize, wchar* fileNoExt, wchar** ext) const;
void IInit( void );
void IFini( void );
bool IReOpen( void );
plStatusLog( UInt8 numDisplayLines, const wchar *filename, UInt32 flags );
public:
static UInt32 fLoggingOff;
enum StatusFlagType
{
kFilledBackground = 0x00000001,
kAppendToLast = 0x00000002,
kDontWriteFile = 0x00000004,
kDeleteForMe = 0x00000008, // BE CAREFUL USING THIS!!
// kDeleteForMe instructs the statusLogMgr to delete
// this log itself when it destructs, which is at the
// very end of client shutdown (the manager is static).
// Because of this, it's safe to use this so long as you'll
// never reference it at the very end of shutdown (as an
// object is deleted by the resManager, for example, is
// okay because that's done in plClient::Shutdown(), not
// at the very end of app destruction). If you use this
// and your log is deleted before you, your pointer will
// NOT reflect this; it's up to you
kAlignToTop = 0x00000010,
kDebugOutput = 0x00000020, // Also write string to debug console
kTimestamp = 0x00000040, // Write a timestamp in Local time with each entry.
kStdout = 0x00000080, // Also write string to stdout
kTimeInSeconds = 0x00000100, // Write timestamp as seconds since epoch
kTimeAsDouble = 0x00000200, // Write timestamp as seconds.millis
kDontRotateLogs = 0x00000400, // Don't rename/renumber log fileName
kServerTimestamp = 0x00000800, // Timestamp each entry with the server's time
kRawTimeStamp = 0x00001000, // hsTimer::GetSeconds()
kThreadID = 0x00002000, // ID of current thread
kTimestampGMT = 0x00004000, // Write a timestamp in GMT with each entry.
kNonFlushedLog = 0x00008000, // Do not flush the log after each write
};
enum
{
kRed = 0xffff0000,
kGreen = 0xff00ff00,
kBlue = 0xff0000ff,
kYellow = 0xffffff00,
kWhite = 0xffffffff
};
enum
{
kMaxFileSize = 300000000, // 300 megs
};
~plStatusLog();
bool AddLine( const char *line, UInt32 color = kWhite );
/// printf-like functions
bool AddLineF( const char *format, ... );
bool AddLineF( UInt32 color, const char *format, ... );
bool AddLineV( const char *format, va_list arguments );
bool AddLineV( UInt32 color, const char *format, va_list arguments );
/// Static functions that you give a filename to and it searches for a log based on that
/// (or creates one if it isn't available)
static bool AddLineS( const char *filename, const char *format, ... );
static bool AddLineS( const char *filename, UInt32 color, const char *format, ... );
void Clear( void );
// Clear and open a new file.
void Bounce( UInt32 flags=0 );
const char* GetFileName() const {return fCFilename.c_str();}
const wchar* GetFileNameW() const {return fFilename.c_str();}
void SetForceLog(bool force) { fForceLog = force; }
};
//// Manager Class Definition ////////////////////////////////////////////////
class plStatusLogMgr
{
friend class plStatusLog;
private:
plStatusLogMgr();
static plStatusLogMgr fManager;
protected:
plStatusLog *fDisplays;
plStatusLog *fCurrDisplay;
plStatusLogDrawerStub *fDrawer;
double fLastLogChangeTime;
static wchar fBasePath[];
static const wchar *IGetBasePath( void ) { return fBasePath; }
void IEnsurePathExists( const wchar *dirName );
void IPathAppend( wchar *base, const wchar *extra, unsigned maxLen );
hsMutex fMutex; // To make multithreaded-safe
public:
enum
{
kDefaultNumLines = 40
};
~plStatusLogMgr();
static plStatusLogMgr &GetInstance( void );
void Draw( void );
plStatusLog *CreateStatusLog( UInt8 numDisplayLines, const char *filename, UInt32 flags = plStatusLog::kFilledBackground );
plStatusLog *CreateStatusLog( UInt8 numDisplayLines, const wchar *filename, UInt32 flags = plStatusLog::kFilledBackground );
void ToggleStatusLog( plStatusLog *logToDisplay );
void NextStatusLog( void );
void PrevStatusLog( void );
void SetCurrStatusLog( const char *logName );
void SetCurrStatusLog( const wchar *logName );
plStatusLog *FindLog( const char *filename, hsBool createIfNotFound = true );
plStatusLog *FindLog( const wchar *filename, hsBool createIfNotFound = true );
void SetDrawer( plStatusLogDrawerStub *drawer ) { fDrawer = drawer; }
void SetBasePath( const char * path );
void SetBasePath( const wchar * path );
void BounceLogs();
// Create a new folder and copy all log files into it (returns false on failure)
bool DumpLogs( const char *newFolderName );
bool DumpLogs( const wchar *newFolderName );
};
//// plStatusLogDrawerStub Class ////////////////////////////////////////////
// Sometimes, we want to be able to link to plStatusLog without having the
// pipeline-drawing functionality. So we do it this way: we define a single
// class of type plStatusLogDrawerStub. If it's allocated and we're given a
// pointer to it (by, say, the pipeline), then we use it to draw and all
// is happy. If not, we don't draw.
class plStatusLogDrawerStub
{
protected:
UInt32 IGetMaxNumLines( plStatusLog *log ) const { return log->fMaxNumLines; }
char **IGetLines( plStatusLog *log ) const { return log->fLines; }
const char *IGetFilename( plStatusLog *log ) const { return log->GetFileName(); }
const wchar *IGetFilenameW( plStatusLog *log ) const { return log->GetFileNameW(); }
UInt32 *IGetColors( plStatusLog *log ) const { return log->fColors; }
UInt32 IGetFlags( plStatusLog *log ) const { return log->fFlags; }
public:
virtual ~plStatusLogDrawerStub() {}
virtual void Draw(plStatusLog* curLog, plStatusLog* firstLog) {}
};
#endif //_plStatusLog_h