Jump to content
  • Advertisement
  • entries
  • comments
  • views

Html Logs

Sign in to follow this  


Somebody asked me today why I spent so much time working on my debug log. An exact quote is "It's just the debug log!"

Let us do a little comparison:
Text Log
Log w/ CSS
Log w/ HTML & CSS

The first has a few problems - the lines blend together and for a lot of people the letters tend to blend together. It also has no formatting and is squished (plus errors and such do not stick out.)

The second has almost all of the first's problem other than it is formatted and easier to read.

The last obviously is my favorite. It's easy to read, important parts stick out a lot more, and it doesn't blend (as much.)

Edit: It doesn't quite look as nice for you IE users since IE doesn't support 0 height HRs (meaning you have HRs in the section headers and firefox users don't) and it doesn't support the :before and :after tags. I'll be removing the HRs, but I can't fix the tag problem. *leers at readers using IE* you can though *cough*firefox*cough*.

I'm almost finished tweaking the code for the dftCommon module. Once that's done I'll upload the header, source, and lib file.

(Aside to Raymond - AIM won't let me send/recieve messages for some reason. Just wanted to let you know that I am doing work Malathedra work [grin].)
Sign in to follow this  


Recommended Comments

[lol] Thanks!

Is there anybody reading this that would actually use it though? Here's a quick example of how to use it:

#include <dftCommon.h>
#pragma comment(lib, "dftCommon")
#include <iostream>

class State
std::string m_Name;
State(const std::string& Name)
m_Name = Name;

void OnEnter()
dft::HtmlLog::GetCurrentLog()->LogDebugOutput("Entering %s", dft::DOT_TEXT, m_Name.c_str());

void OnExit()
dft::HtmlLog::GetCurrentLog()->LogDebugOutput("Exiting %s", dft::DOT_TEXT, m_Name.c_str());

class Application
dft::HtmlLog m_Log;

static bool LogListener(const std::string& Text, int nType)
// This strips HTML tags and then outputs the info to the console
std::string StrippedText = "";

int nStart = 0;
int nLastEnd = 0;
for(unsigned int nIndex = 0; nIndex < Text.size(); ++nIndex)
if(Text[nIndex] == '<')
nStart = nIndex;
for(unsigned int nSubIndex = nIndex + 1; nSubIndex < Text.size(); ++nSubIndex)
if(Text[nSubIndex] == '<')
nIndex = nSubIndex - 1;

if(Text[nSubIndex] == '>')
StrippedText += Text.substr(nLastEnd, nStart - nLastEnd);
nLastEnd = nSubIndex + 1;
nIndex = nSubIndex + 1;

if(nLastEnd != Text.size() - 1)
StrippedText += Text.substr(nLastEnd, Text.size() - nLastEnd);

static std::string OutputTypes[] = { "Text", "Warning", "Error" };
std::cout<<"["<<OutputTypes[nType]<<"]: "<<StrippedText.c_str()<<std::endl;
return true;
m_Log.Create("logname.html", "Html File Title", "style1.css\nstyle2.css");

State Intro("IntroState");
State MainMenu("MainMenuState");
State Game("GameState");


int main()
Application Appy;
return 0;

You may ask "Why not just use a singleton?" Well, I had originally designed it so that I could have multiple logs, but I'm comtemplating switching to a singleton.

Anyway, I'll leave this entry for a few days. If you'd use it, leave a comment and if I get enough people that want it I'll throw it up here early (instead of releasing it with the rest of the library.) I'd appreciate it if those of you that wouldn't use it would tell me why (for example, bad code design, naming, you hate me, etc.)

Share this comment

Link to comment
Eh, I probably won't use it, mostly because I've already got one I like, but partly because it strikes me as overly complex. I need logging to work no matter what, far moreso than I need the logging output to be pretty.

Share this comment

Link to comment
Thanks for the input Telastyn!

The code for it is actually fairly simple. The interface has 10 functions:


void Create(const std::string& Filename, const std::string& Title, const std::string& StyleSheets);
void StartSection(const std::string& Name);
void LogDebugOutput(const std::string& Text, int nType, ...);

void SetUserListener(USERLISTENER fpListner);
USERLISTENER GetUserListener() const;

static void SetCurrentLog(HtmlLog* pLog);
static HtmlLog* GetCurrentLog();

The biggest chunk of code is in the LogDebugOutput() function, which is 13 lines long. Almost all of the HTML formatting is left up to the user and ALL of the 'pretty' is left up to the user (via CSS files.)

Also the output HTML is fairly clean. The example produces this:

<title>Html File Title</title>
<link rel=stylesheet type=text/css href=style1.css>
<link rel=stylesheet type=text/css href=style2.css>

<div class=SectionHeader><hr>
<font class=SectionHeader>IntroState</font>
<hr></div><div class=SectionBody>
dftLog [01:09:51] - <font class=OUTPUTTYPE0>Entering IntroState</font><br>
dftLog [01:09:51] - <font class=OUTPUTTYPE0>Exiting IntroState</font><br>

<div class=SectionHeader><hr>
<font class=SectionHeader>MainMenuState</font>
<hr></div><div class=SectionBody>
dftLog [01:09:51] - <font class=OUTPUTTYPE0>Entering MainMenuState</font><br>
dftLog [01:09:51] - <font class=OUTPUTTYPE0>Exiting MainMenuState</font><br>

<div class=SectionHeader><hr>
<font class=SectionHeader>GameState</font>
<hr></div><div class=SectionBody>
dftLog [01:09:51] - <font class=OUTPUTTYPE0>Entering GameState</font><br>
dftLog [01:09:51] - <font class=OUTPUTTYPE0>Exiting GameState</font><br>

I agree though, it does seem overly complex and is prone to errors (since you have to supply a file of your own.) I get around this by having making my logs global or putting them in my Application-esque class.

Again, thanks for the input!

Share this comment

Link to comment
Eh, mine might be more complex in that case (currently ~4 target loggers, and 5 decorating loggers). All pretty simple code, but...

Share this comment

Link to comment

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Advertisement

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!