Log record format

So, we've got log files, secured from Prying Eyes, not susceptible to overflow attacks. Cool!

Let's talk about what data should be in each record, and how we should format it. Remember, we want to store data in a format tools like Excel can work with.

What data to record?

We want to work out what data should be in each log record. Each log record is about an event. Let's make a list of fields we want in a log record.

We might want to know:

  • When the event happened
  • Who did it
  • What happened

The data for when is the date and time, so let's start our field list with that:

Log record

Fields:

  • Date/time of the event
  • ?

There are many date/time formats we could use. Let's choose a common one that PHP supports, ISO-8601 (we'll see how it works later). Excel, and just about everything else, can read date/times in that format.

That's the first field.

  • When the event happened DONE
  • Who did it
  • What happened

OK, what about who? The answer depends on whether there are user accounts. For example, in the textbook-like-website you're using right now, you log in to, say, submit an exercise solution. You have a user name. Let's record it in the log.

Log record

Fields:

  • Date/time of the event
  • User name
  • ?

If there aren't user names (e.g., on a public info site), you might record someone's IP address. But let's just stick to systems where there are accounts.

Now we have:

  • When the event happened DONE
  • Who did it DONE
  • What happened

For what, we might store two things. The first is a code, maybe a short string, for the type of thing that happened.

Say we're making a course enrollment app for a university. Some event codes might be:

  • create user account - someone made a new user account
  • login - someone logged in
  • enroll - someone enrolled in a course
  • drop - someone deleted an enrollment
  • course update - someone updated a course record (e.g., changed the course title)

Having event type codes makes logs easier to search and analyze. If we suspect there is some password guessing going on, we might extract the login records for analysis.

Log record

Fields:

  • Date/time of the event
  • User name
  • Event code
  • ?

We might also want to store some deets about what happened.

Log record

Fields:

  • Date/time of the event
  • User name
  • Event code
  • Deets

You want different deets for different events. For enrollment events, you want to know the course, and that's about it (you already have the user name in another field). For user account creation events, you want to know more stuff, like name, and roles.

Let's just store strings for the deets, like "User account tjhooker created." You might do more in a real app, like store an XML representation of the event, but strings are fine for us.

Record format

Here are the fields:

Log record

Fields:

  • Date/time of the event
  • User name
  • Event code
  • Deets

We want to write each event log record in a way that's easy to use. Let's use CSV, or comma separated values. It's one of the most common data formats, read by just about everything.

CSV is easy, just separate each field by commas. For example:

  • 2020-11-26T15:54:40+0000,tjhooker,enroll,"Enrolled in course 3322"

There are four fields, with commas separating them.

  • Event date/time.
  • User name
  • Event code
  • Event deets

Time codes can get messy. 2020-11-26T15:54:40+0000 has a date (2020-11-26), a time (15:54:40), and a time zone (+0000). The time zone is hours different from universal time (UTC), also known as Greenwich Mean Time. Fortunately, we don't need to format that ourselves. PHP will do it for us.

The deets string has “” around it, showing that it's one string. This is easier for some analysis software to handle.

A logging function

Let's make a function that will write a log record to a file.

  1. function logEvent($userName, $eventCode, $eventDeets) {
  2.     // Get current date/time in ISO-8601.
  3.     $now = date(DATE_ISO8601);
  4.     // Make a record.
  5.     $logEntry = "$now,$userName,$eventCode,\"$eventDeets\"\n";
  6.     // Write it.
  7.     $filePath = 'D:/logfiles/dog-log.csv';
  8.     //$filePath = '/home/cullenma/logfiles/dog-log.csv';
  9.     if ( file_exists($filePath) && filesize($filePath) > 10000) {
  10.         header('Location: log-file-size-warning.php');
  11.         exit();
  12.     }
  13.     file_put_contents($filePath, $logEntry, FILE_APPEND);
  14. }

We pass it three variables: user name, event code, and deets. The function deals with date/time itself.

This line...

  • $now = date(DATE_ISO8601);

... creates a variable called $now, and puts the current date/time into it, in ISO-8601 format.

This line...

  • $logEntry = "$now,$userName,$eventCode,\"$eventDeets\"\n";

... makes a string variable with the log record. The current date/time, then a comma, then the user name, then a comma, then the event code, then a comma.

Then we want to add the deets with " around it. But " by itself would end the log event string. We want to say to PHP:

Hey, I want you to write ".

That's what \" The backslash means "output the next character as is."

Finally, we put a \n. Remember, that's new line, like pressing Enter as you're typing. So each log record will be on a new line.

The rest of the code is as before, except for the file extension. csv is the most common extension for CSV files.

Calling the function

For example:

  • <?php
  • // Get data from the URL.
  • $cutestDog = $_GET['name'];
  • $rating = $_GET['cuteness'];
  • // Log.
  • logEvent('tjhooker', 'cute dog', "Dog $cutestDog, rating $rating");

Here's what the log file looks like after two events.

  • 2020-11-26T17:17:03+0100,tjhooker,cute dog,"Dog Rosie, rating 12"
  • 2020-11-26T17:17:17+0100,tjhooker,cute dog,"Dog Renata, rating 11"

Excel loads the data easily:

Excel loads the data

Add to the code library

Add logEvent() to your code library Then you can call it as needed.

Exercise

Exercise

Mortgage payments error log file

Update your mortgage payment program. Log valid user inputs to a log file. You can try it.

  • Make a logging function in your function library. Call it from your mortgage app.
  • Only log if the log file isn't too large.
  • Store the log in a folder that can't be accessed through the web directly.
  • Use a CSV format, with the current/time, the principle, rate, and term.
  • Add a link to a program that shows the log, as in the example. (You wouldn't do this in a real app, of course.)

Hint: file_get_contents()

Upload a link to your solution on your server, and a zip file with your code. The usual standards apply.