Assignment 2 -- Embedded Debug/Activity Logging
Due: Monday August 11
This assignment is worth 11 marks total.
Business Case (Marketing, Project Manager, Senior Executives)
A product goes through the phases of business case, requirements, design, implementation, testing and rework, and eventually
deployment to customers. Testing and rework attempts to simulate conditions at a customer site, but does not always catch
every defect in the product. There are cases where the product malfunctions or stops working at a customer site, with very
few clues as to what went wrong.
Linux has some built in logging mechanisms such as syslog, rsyslog and syslog-ng. These logs can be found in the /var/log/
directory and can be useful. More useful is if the code for the product itself had logging embedded into it. Embedding
debug logs in the code assists in debugging such problems in the field which are difficult to recreate in the lab. This
will greatly assist in working through problems with a customer without losing customer confidence and thereby harming
the reputation of the company.
Our task then is to develop an embedded logging mechanism in our code with logs being sent to a central server which can keep track of how the code is performing.
Requirements (Marketing, Project Manager, Project Lead)
- Logging must be terse but contain useful information.
- Each embedded log entry must contain a log severity. It must also contain the filename, the function name, the line number that the log appears in. Finally, it must contain a brief message.
- Logging must be fast. It cannot slow down the performance of the product.
- Logging must the filtered by the filter level severity. This means any logs at the filter level severity or higher will be reported. Any logs of lower severity than the filter level severity will be ignored.
- The severity levels will be debug, warning, error, and critical.
- The code itself will initialize logging and set the filter severity level.
- Logs must be sent to a central server on another machine for future reference.
- The server will collect all log messages on one common log file called the server log file.
- The server gives the option to dump the server log file to the screen.
- The server gives the option to overwrite the filter level severity.
Design (Project Lead, Senior Engineers)
Each Process:
- Each process will initialize logging for its process, set the filter level severity, call log functions to report any unusual activity, and shutdown the logger before exiting.
The Logger:
- The logging code will be contained within one file which can be included in the Makefile for each process.
- The logging code will communicate with the server via an IP address and port on the server.
- The logging code will collect logs from the process.
- If the logs are below the filter level severity, they are thrown away.
- If the logs are at or higher than the filter level severity, they are written to a server via UDP for fast delivery.
- The logging code will have a separate thread for reading UDP messages from the server.
The Server:
- The server must bind a socket to its IP address and to an available port.
- The server must have the ability to write messages to the logger via UDP for fast delivery.
- The server will have a separate thread for reading UDP messages from the logger.
- The server must give the user the option to dump the server log file to the screen.
- The server must give the user the option to overwrite the filter level severity of the logs.
Implementation (Junior and Senior Engineers)
Each Process:
- The process code will include a Logger.h file.
- The process Makefile will include Logger.cpp to its list of files.
- The process will initialize logging with a call to InitializeLog() of the logger.
- The process will set the filter severity level with a call to SetLogLevel().
- The process will send log messages to the logger by calling Log() of the logger with the following information:
- Log Severity - DEBUG, WARNING, ERROR, CRITICAL.
- File name - ./assign2.wml. This is a Linux macro which contains the filename. It is of type char *.
- Function name - __func__. This is a Linux macro which contains the function name. It is of type char *.
- Line number - 80. This is a Linux macro which contains the line number of the log. It is of type int.
- Message - The log message. This can be any user defined message contained as a string.
Example:
Log(DEBUG, ./assign2.wml, __func__, 83, "Created the objects");
- When the process is ready to exit, it will call ExitLog() to shut down the logger.
The Logger:
- The logger will type-define an enumeration called LOG_LEVEL in its header file (Logger.h) specifying the log levels: DEBUG, WARNING, ERROR, CRITICAL.
- The logger will expose the following functions to each process via its header file (Logger.h):
- int InitializeLog();
- void SetLogLevel(LOG_LEVEL level);
- void Log(LOG_LEVEL level, const char *prog, const char *func, int line, const char *message);
- void ExitLog();
- The logger will implement the above functions in its CPP file (Logger.cpp):
- InitializeLog() will
- create a non-blocking socket for UDP communications (AF_INET, SOCK_DGRAM).
- Set the address and port of the server.
- Create a mutex to protect any shared resources.
- Start the receive thread and pass the file descriptor to it.
- SetLogLevel() will set the filter log level and store in a variable global within Logger.cpp.
- Log() will
- compare the severity of the log to the filter log severity. The log will be thrown away if its severity is lower than the filter log severity.
- create a timestamp to be added to the log message. Code for creating the log message will look something like:
time_t now = time(0);
char *dt = ctime(&now);
memset(buf, 0, BUF_LEN);
char levelStr[][16]={"DEBUG", "WARNING", "ERROR", "CRITICAL"};
len = sprintf(buf, "%s %s %s:%s:%d %s\n", dt, levelStr[level], file, func, line, message)+1;
buf[len-1]='\0';
- apply mutexing to any shared resources used within the Log() function.
- The message will be sent to the server via UDP sendto().
- ExitLog() will stop the receive thread via an is_running flag and close the file descriptor.
- The receive thread is waiting for any commands from the server. So far there is only one command from the server: "Set Log Level=<level>". The receive thread will
- accept the file descriptor as an argument.
- run in an endless loop via an is_running flag.
- apply mutexing to any shared resources used within the recvfrom() function.
- ensure the recvfrom() function is non-blocking with a sleep of 1 second if nothing is received.
- act on the command "Set Log Level=<level>" from the server to overwrite the filter log severity.
The Server:
- The server will shutdown gracefully via a ctrl-C via a shutdownHandler.
- The server's main() function will create a non-blocking socket for UDP communications (AF_INET, SOCK_DGRAM).
- The server's main() function will bind the socket to its IP address and to an available port.
- The server's main() function will create a mutex and apply mutexing to any shared resources.
- The server's main() function will start a receive thread and pass the file descriptor to it.
- The server's main() function will present the user with three options via a user menu:
- 1.Set the log level
- The user will be prompted to enter the filter log severity.
- The information will be sent to the logger. Sample code will look something like:
memset(buf, 0, BUF_LEN);
len=sprintf(buf, "Set Log Level=%d", level)+1;
sendto(fd, buf, len, 0, (struct sockaddr *)&remaddr, addrlen);
- 2.Dump the log file here
- The server will open its server log file for read only.
- It will read the server's log file contents and display them on the screen.
- On completion, it will prompt the user with:
"Press any key to continue:"
- 0. Shut down
- The receive thread will be shutdown via an is_running flag.
- The server will exit its user menu.
- The server will join the receive thread to itself so it doesn't shut down before the receive thread does.
- The server's receive thread will:
- open the server log file for write only with permissions rw-rw-rw-
- run in an endless while loop via an is_running flag.
- apply mutexing to any shared resources used within the recvfrom() function.
- ensure the recvfrom() function is non-blocking with a sleep of 1 second if nothing is received.
- take any content from recvfrom() and write to the server log file.
On the process side you have been provided with a
Makefile, TravelSimulator.cpp, Automobile.cpp, and Automobile.h
which are available here:
https://github.com/jsellens/unx511_samples/tree/main/assign_2
You have to implement Logger.cpp and Logger.h.
On the server side you have to implement LogServer.cpp and you also have to create a Makefile.
Testing and Rework (Junior and Senior Engineers, Product Support)
- Start the server on one machine. Make sure you have the correct IP address and port.
- Start the test application on another machine, which in this case is called TravelSimulator.
- Make sure your logger has the correct IP address and port of the server.
- Logging has been added to the TravelSimulator, along with calls to InitializeLog(), SetLogLevel() and ExitLog().
- The TravelSimulator runs indefinitely until the user administers a ctrl-C.
- Observe the server log file as it grows either by dumping to the screen or looking at the file itself.
- Change the filter log severity on the server.
- Observe the server log file again.
- Is it getting all of the log messages?
- Are the log messages in sequence?
- For each log message verify the timestamp, log level, file name, function, line number and the message.
Screenshots
Take from 1 to 4 screenshots to show your
software in use, and include with your assignment submission.
Timeline
Days 1-7: Create the Logger.
Days 8-14: Create the Server.
Days 15-21: Test and Rework. Answer questions. Submit assignment.
Marking Rubric
Assignment 2 is worth 11% of your final grade and as such is marked out of 11 as follows:
| Does not meet expectations | Satisfactory | Good | Exceeds Expectations |
The Logger (5 marks) | Does not meet requirements | Meets the most important requirements | Meets all requirements with minor errors | Meets all requirements with no errors |
The Server (5 marks) | Does not meet requirements | Meets the most important requirements | Meets all requirements with minor errors | Meets all requirements with no errors |
Documentation (1 marks) | Does not contain documentation | Contains header documentation for either all files or for all functions within each file |
Contains header documentation for all files and for most functions within each file | Contains header documentation for all files and for all functions within each file.
Documents unclear code. |
Assignment Submission:
- Follow the instructions above
- Send email
- To: john.sellens@senecapolytechnic.ca
- Subject: assignment 2 submission
- Attach all files for the assignment
- Attach the screenshots you took of your software in action
- Submit assignment 2 through blackboard at
https://learn.senecapolytechnic.ca/
UNX511 NSB Class Links
References
Tools
Links