<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>https://wiki.expertiza.ncsu.edu/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Cshimes</id>
	<title>Expertiza_Wiki - User contributions [en]</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.expertiza.ncsu.edu/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Cshimes"/>
	<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=Special:Contributions/Cshimes"/>
	<updated>2026-08-15T14:29:53Z</updated>
	<subtitle>User contributions</subtitle>
	<generator>MediaWiki 1.41.0</generator>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2024_-_E2471._Reimplement_logger&amp;diff=159787</id>
		<title>CSC/ECE 517 Fall 2024 - E2471. Reimplement logger</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2024_-_E2471._Reimplement_logger&amp;diff=159787"/>
		<updated>2024-11-26T15:00:59Z</updated>

		<summary type="html">&lt;p&gt;Cshimes: /* Tests Explained */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==E2471. Reimplement logger==&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===About Expertiza===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create new assignments and customize new or existing assignments. It also allows the instructor to create a list of topics the students can sign up for. Students can form teams in Expertiza to work on various projects and assignments. Students can also peer review other students' submissions. Expertiza supports submission across various document types, including the URLs and wiki pages. As the project has progressed, there has developed a need to reimplement the project using different frameworks. Our project specifically assists in this goal as it implements a logger for the [https://github.com/expertiza/reimplementation-back-end reimplemented backend]. This new backend utilizes Rails API to create a RESTful API that can be accessed by frontend implementations. The latest [https://github.com/expertiza/reimplementation-front-end frontend reimplementation] has used Typescript and React to create the UI. &lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The following tasks have been accomplished as part of this project:&lt;br /&gt;
&lt;br /&gt;
* Created an ExpertizaLogger to customize logging behavior in the new backend.&lt;br /&gt;
* Created special formats for the logging that is being performed to include the desired information. &lt;br /&gt;
* Created info, warn, error, fatal, and debug logging levels.&lt;br /&gt;
* Created hooks to log CRUD database transactions. &lt;br /&gt;
* Utilize hooks to automatically log all model CRUD operations. &lt;br /&gt;
&lt;br /&gt;
These tasks establish a uniform logging experience for all of the CRUD operations, and they provide the ability to log other specific details as desired manually. This ensures that we have a base implementation that complies with the database CRUD operation logging requirement while allowing developers to include manual logging such as error flows or other information that may be helpful for an administrator to consult. Moving forward, all ApplicationRecords will automatically log the CRUD operations, and developers can easily utilize &amp;quot;ExpertizaLogger.warn(message)&amp;quot; to log an info message, for example. &lt;br /&gt;
&lt;br /&gt;
===Implementation Details===&lt;br /&gt;
Our implementation primarily involved creating four new components: &lt;br /&gt;
&lt;br /&gt;
* Expertiza Logger class&lt;br /&gt;
* Expertiza Log Formatter class&lt;br /&gt;
* Logger Message class&lt;br /&gt;
* Logging concern&lt;br /&gt;
&lt;br /&gt;
These components are now explained in greater detail below. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===About Expertiza Logger===&lt;br /&gt;
This logger is responsible for providing the desired log levels in the Expertiza reimplemented backend. It specifically contains the info, warn, error, fatal, and debug logging levels. These logs are then stored in files named &amp;quot;expertiza_info.log&amp;quot;, &amp;quot;expertiza_warn.log&amp;quot;, etc. It utilizes the Expertiza Log Formatter, which is utilized to format all of the desired log messages.&lt;br /&gt;
&lt;br /&gt;
===About Expertiza Log Formatter===&lt;br /&gt;
This class is a log formatter to provide a uniform style that contains all of the information desired. This is a critical class, as it allows the logs to be effectively searched for the given information logged. It ensures that all logs are consistent and are also easily parsable. &lt;br /&gt;
&lt;br /&gt;
===About Logger Message===&lt;br /&gt;
This class is a simple model that provides the content for the message that is being formatted by Expertiza Logger. It includes such values as the Unity ID, a message, remote IP address, etc. This information is utilized when formatting the logs to ensure that this consistent information is presented and available for inspection without requiring additional developer effort. It makes it easy to modify the logger format because the information will remain consistent, while the Expertiza Log Formatter can adjust the output format easily for all subsequent logs without modifying log commands spread throughout the project. &lt;br /&gt;
&lt;br /&gt;
===About Logging Concern===&lt;br /&gt;
This concern was created as an easy way to ensure that critical events are logged by default in the application. In particular, our goal was to log the database CRUD events. This concern sets up the hooks necessary to call the log methods required to log these events. By including this concern in any model, it will automatically perform the desired CRUD logging. We have leveraged this combined with the model hierarchy of classes depending on ApplicationRecord to ensure logging compliance. That is, we have included the logging concern in ApplicationRecord, allowing any class that inherits from ApplicationRecord to benefit from the automatic logging configuration. This ensures that this architecture is sustainable in the future by ensuring that the desired CRUD operations will be logged without requiring additional developer configuration.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Testing from UI===&lt;br /&gt;
It is not possible to test and observe this behavior from the UI. This is intentional because users should not be able to access any of the runtime information that is being logged. This information could include users' personal information, etc. that only an admin should be able to inspect. These log files are created and are able to be inspected by an IT administrator, but should not be available for user inspection. &lt;br /&gt;
&lt;br /&gt;
If, however, the admin would like to test the implementation, they can interact with the backend using the frontend, Postman, etc. The actions they perform are logged and can then be inspected in the recorded logs.&lt;br /&gt;
&lt;br /&gt;
For example, here are a few test cases with respect to our code changes that can be tried:&lt;br /&gt;
1. Log in to the webpage. Inspecting the logs should show that the user's account information was retrieved from the database. &lt;br /&gt;
&lt;br /&gt;
2. Create a new assignment. Inspecting the logs will demonstrate that the desired information is persisted to the database. &lt;br /&gt;
&lt;br /&gt;
3. Edit the created assignment. Inspecting the logs will demonstrate that the newly updated information is persisted to the database. &lt;br /&gt;
&lt;br /&gt;
4. Delete the assignment. Inspecting the logs will reveal that the assignment was deleted.&lt;br /&gt;
&lt;br /&gt;
==Final Design Document==&lt;br /&gt;
&lt;br /&gt;
===Proposed Changes===&lt;br /&gt;
From observing the current state of the logging implementation, which includes most functionality from the original Expertiza, we have improved the logging for better observability into the system. To that end, we have implemented the following changes:&lt;br /&gt;
&lt;br /&gt;
====Writing more comprehensive automated tests and improving coverage====&lt;br /&gt;
We have written and executed automated tests to cover a range of logging scenarios. Tests on the CRUD operations of models now ensure the functionality of info-level logging. We've also added tests that check for logging at the other severity levels (warning, error, etc). These tests are stored as files in the &amp;lt;code&amp;gt;spec/logs&amp;lt;/code&amp;gt; directory. One example of a testing method is this one, which we've recently written:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RSpec.describe Api::V1::UsersController, type: :controller do&lt;br /&gt;
  let(:user) { build(:user, name: &amp;quot;Jane&amp;quot;, email: &amp;quot;jdoe@ncsu.edu&amp;quot;, full_name: &amp;quot;Jane Doe&amp;quot;) }&lt;br /&gt;
  let(:params) do { user: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Jane Doe&amp;quot;,&lt;br /&gt;
        &amp;quot;full_name&amp;quot;: &amp;quot;Jane Doe&amp;quot;,&lt;br /&gt;
        &amp;quot;email&amp;quot;: &amp;quot;jane.doe@example.com&amp;quot;,&lt;br /&gt;
        &amp;quot;role_id&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;institution_id&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;password&amp;quot;: &amp;quot;password&amp;quot;,&lt;br /&gt;
        &amp;quot;password_confirmation&amp;quot;: &amp;quot;password&amp;quot;   } }&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it &amp;quot;logs when user is created&amp;quot; do&lt;br /&gt;
    allow(Rails.logger).to receive(:info)&lt;br /&gt;
    expect(Rails.logger).to receive(:info)&lt;br /&gt;
&lt;br /&gt;
    post :create, params: params&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Enhancing error logging by capturing new cases====&lt;br /&gt;
Some functionality has changed between the old implementation and the reimplementation of the backend. For example, the reimplementation has different ways of performing error checking in some of the controller methods than the original implementation had. For these cases and others, we added logging to ensure that when a controller method fails, a detailed log message is produced and stored in the appropriate log file. &lt;br /&gt;
&lt;br /&gt;
====Correcting the use of the info log level for errors====&lt;br /&gt;
In the original backend implementation, the info severity level is used almost universally, even when logging errors. For example, in the original implementation of the bookmarks controller, the &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method logs errors that occur like so: &amp;lt;code&amp;gt;ExpertizaLogger.info LoggerMessage.new(controller_name, session[:user].name, $ERROR_INFO, request)&amp;lt;/code&amp;gt;. We have replaced these with the appropriate logging level, so that errors go to one file, and info to another. This expedites the debugging process for developers, as they will know where to look to find errors vs info.&lt;br /&gt;
&lt;br /&gt;
====Standardizing error messages to avoid mixed hardcoded strings and object outputs====&lt;br /&gt;
In the original backend implementation, sometimes the content of an error object was passed into logging messages, and sometimes hardcoded strings specific to the situation were. For example, in the original implementation of the student teams controller, the &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method uses hardcoded strings specifically indicating why the request failed - &amp;lt;code&amp;gt;ExpertizaLogger.info LoggerMessage.new(controller_name, session[:user].name, 'Team name missing while creating team', request)&amp;lt;/code&amp;gt;. However, in the bookmarks controller, the error info was logged like so: &amp;lt;code&amp;gt;ExpertizaLogger.info LoggerMessage.new(controller_name, session[:user].name, $ERROR_INFO, request)&amp;lt;/code&amp;gt;. We've increased the consistency across all logging messages to include detailed, context-specific error messages, as that is more informative to developers, and have added logging messages in that style everywhere they are relevant.&lt;br /&gt;
&lt;br /&gt;
====Ensuring consistent use of &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; (e.g., defaulting to session[:user].name unless context demands otherwise)====&lt;br /&gt;
Both implementations of logging use a &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; object to standardize information produced in logs. The &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; object takes, among other things, the unity id of the logger as a parameter. However, in the old backend, that parameter is sometimes passed in from the user's session like &amp;lt;code&amp;gt;session[:user].name&amp;lt;/code&amp;gt; and sometimes passed in through other means, such as &amp;lt;code&amp;gt;@participant.name&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;requested_user.name&amp;lt;/code&amp;gt;. We have standardized these in the reimplementation such that the user's session is used everywhere possible to ensure consistency.&lt;br /&gt;
&lt;br /&gt;
==Tests Explained==&lt;br /&gt;
This section will explain the tests we've written to varying levels of specificity. Where reasonable, we've omitted tests that are repetitive to reduce redundancy - for example, we only explain the info level logging tests in &amp;lt;code&amp;gt;spec/logs/expertiza_logger_spec.rb&amp;lt;/code&amp;gt;. While we have separate tests in that file for the other severity levels, they're very similar, and do not warrant separate explanation.&lt;br /&gt;
&lt;br /&gt;
===Expertiza Log Formatter Tests===&lt;br /&gt;
The Expertiza Log Formatter is designed to ensure consistent log formatting across various logging scenarios. The tests in &amp;lt;code&amp;gt;spec/logs/expertiza_log_formatter_spec.rb&amp;lt;/code&amp;gt; are designed to check this functionality. &lt;br /&gt;
&lt;br /&gt;
Before the tests, a few helpful variables are defined as such:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
let(:formatter) { ExpertizaLogFormatter.new }&lt;br /&gt;
let(:timestamp) { Time.now }&lt;br /&gt;
let(:severity) { 'INFO' }&lt;br /&gt;
let(:progname) { 'Expertiza' }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first two tests, included below, check that the log formatter can format messages correctly. The first test invokes the &amp;lt;code&amp;gt;call&amp;lt;/code&amp;gt; method on the formatter with info level severity, the current time as timestamp, 'Expertiza' as the program name, and a simple string as the message parameter. Given these simple parameters, we can easily check that the produced message, returned by the &amp;lt;code&amp;gt;call&amp;lt;/code&amp;gt; method, matches our expectations. The second test is very similar, but checks that a message with a newline produces a log without one. The &amp;lt;code&amp;gt;ExpertizaLogFormatter&amp;lt;/code&amp;gt; is designed to take all newlines and replace them with space characters, so that log files aren't unnecessarily messy.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when the message is a plain string' do&lt;br /&gt;
    let(:message) { 'Test message with more text' }&lt;br /&gt;
    it 'formats the message correctly' do&lt;br /&gt;
      formatted_message = formatter.call(severity, timestamp, progname, message)&lt;br /&gt;
      expect(formatted_message).to include(&amp;quot;TST=[#{timestamp}] SVT=[#{severity}] PNM=[#{progname}] OIP=[] RID=[] CTR=[] UID=[] MSG=[Test message with more text]&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
context 'when the message is a plain string with newline' do&lt;br /&gt;
    let(:message) { &amp;quot;Test message with newline\nto more text&amp;quot; }&lt;br /&gt;
    it 'formats the message correctly' do&lt;br /&gt;
      formatted_message = formatter.call(severity, timestamp, progname, message)&lt;br /&gt;
      expect(formatted_message).to include(&amp;quot;TST=[#{timestamp}] SVT=[#{severity}] PNM=[#{progname}] OIP=[] RID=[] CTR=[] UID=[] MSG=[Test message with newline to more text]&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The final two tests similarly check formatting, except instead of passing in a simple string, they instead pass in a &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; object. &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; is a class designed to hold more complex information than just a simple message. &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; objects can hold a reference to a 'generator' (typically the name of the controller the log comes from), the unity id of the generating user, a string message, and a request (made up of a remote ip address and a unique identifier/uuid). The first test here uses a &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; without a request, and ensures the resulting log contains the information from that object. The second test uses a &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; that does contain a request, and ensures the formatting and data integrity of the created log message similarly.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when the message is a LoggerMessage object' do&lt;br /&gt;
  let(:logger_message) do&lt;br /&gt;
    LoggerMessage.new('gen1', 'unityid1', 'Test message')&lt;br /&gt;
  end&lt;br /&gt;
  it 'formats the message correctly' do&lt;br /&gt;
    formatted_message = formatter.call(severity, timestamp, progname, logger_message)&lt;br /&gt;
    expect(formatted_message).to include(&amp;quot;TST=[#{timestamp}] SVT=[#{severity}] PNM=[#{progname}] OIP=[] RID=[] CTR=[gen1] UID=[unityid1] MSG=[Test message]&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
context 'when the message is a LoggerMessage object with request' do&lt;br /&gt;
  let(:logger_message) do&lt;br /&gt;
    LoggerMessage.new('gen1', 'unityid1', 'Test message', double(&amp;quot;request&amp;quot;, remote_ip: &amp;quot;192.168.1.1&amp;quot;, uuid: &amp;quot;12345&amp;quot;))&lt;br /&gt;
  end&lt;br /&gt;
  it 'formats the message correctly' do&lt;br /&gt;
    formatted_message = formatter.call(severity, timestamp, progname, logger_message)&lt;br /&gt;
    expect(formatted_message).to include(&amp;quot;TST=[#{timestamp}] SVT=[#{severity}] PNM=[#{progname}] OIP=[192.168.1.1] RID=[12345] CTR=[gen1] UID=[unityid1] MSG=[Test message]&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
===Expertiza Logger Tests===&lt;br /&gt;
The Expertiza Logger is designed to log information at varying severity levels, depending on which of its methods are called, while following standardized log formatting. To do so, it creates and stores one instance of Ruby's &amp;lt;code&amp;gt;Logger&amp;lt;/code&amp;gt; class for each severity level, and uses the aforementioned &amp;lt;code&amp;gt;ExpertizaLogFormatter&amp;lt;/code&amp;gt; to format incoming messages. Depending on the method called, &amp;lt;code&amp;gt;ExpertizaLogger&amp;lt;/code&amp;gt; logs to a file that corresponds to a specific logging level. The tests in &amp;lt;code&amp;gt;spec/logs/expertiza_logger_spec.rb&amp;lt;/code&amp;gt; are designed to check this functionality. &lt;br /&gt;
&lt;br /&gt;
Before the tests, a few helpful variables are defined as such, including a mocked instance of the &amp;lt;code&amp;gt;Logger&amp;lt;/code&amp;gt; class.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
let(:message) { 'Test message' }&lt;br /&gt;
let(:timestamp) { Time.now }&lt;br /&gt;
&lt;br /&gt;
# Create a mock logger instance&lt;br /&gt;
let(:mock_logger) { instance_double(Logger) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This test also uses a before block to enable the &amp;lt;code&amp;gt;Logger&amp;lt;/code&amp;gt; to receive a request for a new instance of itself and to return a mock logger, which can in turn receive various requests. This is important to avoid directly testing the &amp;lt;code&amp;gt;ExpertizaLogFormatter&amp;lt;/code&amp;gt;. The test is designed to rely on expected behavior from that class, rather than directly testing it, as that's outside the scope of these tests.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
before do&lt;br /&gt;
  allow(Logger).to receive(:new).and_return(mock_logger)&lt;br /&gt;
  allow(mock_logger).to receive(:formatter)&lt;br /&gt;
  allow(mock_logger).to receive(:formatter=).with(an_instance_of(ExpertizaLogFormatter))&lt;br /&gt;
  allow(mock_logger).to receive(:info)&lt;br /&gt;
  allow(mock_logger).to receive(:warn)&lt;br /&gt;
  allow(mock_logger).to receive(:error)&lt;br /&gt;
  allow(mock_logger).to receive(:fatal)&lt;br /&gt;
  allow(mock_logger).to receive(:debug)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then for each severity level, there is a test like this one. We're only including the info-level test here. The test calls the &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt; method of the &amp;lt;code&amp;gt;ExpertizaLogger&amp;lt;/code&amp;gt; class, which is expected to then call the &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; method on the &amp;lt;code&amp;gt;Logger&amp;lt;/code&amp;gt; class, passing in the appropriate log file for this severity level (&amp;lt;code&amp;gt;expertiza_info.log&amp;lt;/code&amp;gt;). The test expects that the &amp;lt;code&amp;gt;formatter&amp;lt;/code&amp;gt; attribute of this new &amp;lt;code&amp;gt;Logger&amp;lt;code&amp;gt; instance, referred to as &amp;lt;code&amp;gt;mock_logger&amp;lt;/code&amp;gt;, will be set equal to an instance of the &amp;lt;code&amp;gt;ExpertizaLogFormatter&amp;lt;/code&amp;gt; and that the &amp;lt;code&amp;gt;mock_logger&amp;lt;/code&amp;gt; receives a call to its &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt; method with the right message parameter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '.info' do&lt;br /&gt;
  it 'logs the message to the correct file with info severity' do&lt;br /&gt;
    ExpertizaLogger.info(message)&lt;br /&gt;
    expect(Logger).to have_received(:new).with(Rails.root.join('log', 'expertiza_info.log'))&lt;br /&gt;
    expect(mock_logger).to have_received(:formatter=).with(an_instance_of(ExpertizaLogFormatter))&lt;br /&gt;
    expect(mock_logger).to have_received(:info).with(message)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&lt;br /&gt;
#[https://github.com/expertiza/expertiza Expertiza on GitHub]&lt;br /&gt;
#[https://github.com/expertiza/reimplementation-front-end Reimplemented Frontend Github Project]&lt;br /&gt;
#[https://github.com/expertiza/reimplementation-back-end Reimplemented Backend GitHub Project]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end Reimplemented Backend GitHub Project Repository Fork]&lt;br /&gt;
#[http://expertiza.ncsu.edu/ The live Expertiza website]&lt;br /&gt;
#[https://drive.google.com/file/d/1JnMWG1d7P_yLQ_un_R7kMbTrBk5YoA87/view?usp=share_link Project demo link] &lt;br /&gt;
#[https://wiki.expertiza.ncsu.edu/index.php?title=Main_Page Expertiza project documentation wiki]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end/commit/aa84e46135d4f660c6a981f5d032cdf2a4b2f25e Initial logging commit]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end/commit/1e0ee7a0d7f6e6d48e9a82753ee0fa0afdf8440f Reimplement Expertiza Logger]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end/commit/ceee53b4d9ed4281ac2f0201873a40b90bceb039 Adding logging to ApplicationRecord]&lt;/div&gt;</summary>
		<author><name>Cshimes</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2024_-_E2471._Reimplement_logger&amp;diff=159786</id>
		<title>CSC/ECE 517 Fall 2024 - E2471. Reimplement logger</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2024_-_E2471._Reimplement_logger&amp;diff=159786"/>
		<updated>2024-11-26T15:00:24Z</updated>

		<summary type="html">&lt;p&gt;Cshimes: /* Tests Explained */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==E2471. Reimplement logger==&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===About Expertiza===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create new assignments and customize new or existing assignments. It also allows the instructor to create a list of topics the students can sign up for. Students can form teams in Expertiza to work on various projects and assignments. Students can also peer review other students' submissions. Expertiza supports submission across various document types, including the URLs and wiki pages. As the project has progressed, there has developed a need to reimplement the project using different frameworks. Our project specifically assists in this goal as it implements a logger for the [https://github.com/expertiza/reimplementation-back-end reimplemented backend]. This new backend utilizes Rails API to create a RESTful API that can be accessed by frontend implementations. The latest [https://github.com/expertiza/reimplementation-front-end frontend reimplementation] has used Typescript and React to create the UI. &lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The following tasks have been accomplished as part of this project:&lt;br /&gt;
&lt;br /&gt;
* Created an ExpertizaLogger to customize logging behavior in the new backend.&lt;br /&gt;
* Created special formats for the logging that is being performed to include the desired information. &lt;br /&gt;
* Created info, warn, error, fatal, and debug logging levels.&lt;br /&gt;
* Created hooks to log CRUD database transactions. &lt;br /&gt;
* Utilize hooks to automatically log all model CRUD operations. &lt;br /&gt;
&lt;br /&gt;
These tasks establish a uniform logging experience for all of the CRUD operations, and they provide the ability to log other specific details as desired manually. This ensures that we have a base implementation that complies with the database CRUD operation logging requirement while allowing developers to include manual logging such as error flows or other information that may be helpful for an administrator to consult. Moving forward, all ApplicationRecords will automatically log the CRUD operations, and developers can easily utilize &amp;quot;ExpertizaLogger.warn(message)&amp;quot; to log an info message, for example. &lt;br /&gt;
&lt;br /&gt;
===Implementation Details===&lt;br /&gt;
Our implementation primarily involved creating four new components: &lt;br /&gt;
&lt;br /&gt;
* Expertiza Logger class&lt;br /&gt;
* Expertiza Log Formatter class&lt;br /&gt;
* Logger Message class&lt;br /&gt;
* Logging concern&lt;br /&gt;
&lt;br /&gt;
These components are now explained in greater detail below. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===About Expertiza Logger===&lt;br /&gt;
This logger is responsible for providing the desired log levels in the Expertiza reimplemented backend. It specifically contains the info, warn, error, fatal, and debug logging levels. These logs are then stored in files named &amp;quot;expertiza_info.log&amp;quot;, &amp;quot;expertiza_warn.log&amp;quot;, etc. It utilizes the Expertiza Log Formatter, which is utilized to format all of the desired log messages.&lt;br /&gt;
&lt;br /&gt;
===About Expertiza Log Formatter===&lt;br /&gt;
This class is a log formatter to provide a uniform style that contains all of the information desired. This is a critical class, as it allows the logs to be effectively searched for the given information logged. It ensures that all logs are consistent and are also easily parsable. &lt;br /&gt;
&lt;br /&gt;
===About Logger Message===&lt;br /&gt;
This class is a simple model that provides the content for the message that is being formatted by Expertiza Logger. It includes such values as the Unity ID, a message, remote IP address, etc. This information is utilized when formatting the logs to ensure that this consistent information is presented and available for inspection without requiring additional developer effort. It makes it easy to modify the logger format because the information will remain consistent, while the Expertiza Log Formatter can adjust the output format easily for all subsequent logs without modifying log commands spread throughout the project. &lt;br /&gt;
&lt;br /&gt;
===About Logging Concern===&lt;br /&gt;
This concern was created as an easy way to ensure that critical events are logged by default in the application. In particular, our goal was to log the database CRUD events. This concern sets up the hooks necessary to call the log methods required to log these events. By including this concern in any model, it will automatically perform the desired CRUD logging. We have leveraged this combined with the model hierarchy of classes depending on ApplicationRecord to ensure logging compliance. That is, we have included the logging concern in ApplicationRecord, allowing any class that inherits from ApplicationRecord to benefit from the automatic logging configuration. This ensures that this architecture is sustainable in the future by ensuring that the desired CRUD operations will be logged without requiring additional developer configuration.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Testing from UI===&lt;br /&gt;
It is not possible to test and observe this behavior from the UI. This is intentional because users should not be able to access any of the runtime information that is being logged. This information could include users' personal information, etc. that only an admin should be able to inspect. These log files are created and are able to be inspected by an IT administrator, but should not be available for user inspection. &lt;br /&gt;
&lt;br /&gt;
If, however, the admin would like to test the implementation, they can interact with the backend using the frontend, Postman, etc. The actions they perform are logged and can then be inspected in the recorded logs.&lt;br /&gt;
&lt;br /&gt;
For example, here are a few test cases with respect to our code changes that can be tried:&lt;br /&gt;
1. Log in to the webpage. Inspecting the logs should show that the user's account information was retrieved from the database. &lt;br /&gt;
&lt;br /&gt;
2. Create a new assignment. Inspecting the logs will demonstrate that the desired information is persisted to the database. &lt;br /&gt;
&lt;br /&gt;
3. Edit the created assignment. Inspecting the logs will demonstrate that the newly updated information is persisted to the database. &lt;br /&gt;
&lt;br /&gt;
4. Delete the assignment. Inspecting the logs will reveal that the assignment was deleted.&lt;br /&gt;
&lt;br /&gt;
==Final Design Document==&lt;br /&gt;
&lt;br /&gt;
===Proposed Changes===&lt;br /&gt;
From observing the current state of the logging implementation, which includes most functionality from the original Expertiza, we have improved the logging for better observability into the system. To that end, we have implemented the following changes:&lt;br /&gt;
&lt;br /&gt;
====Writing more comprehensive automated tests and improving coverage====&lt;br /&gt;
We have written and executed automated tests to cover a range of logging scenarios. Tests on the CRUD operations of models now ensure the functionality of info-level logging. We've also added tests that check for logging at the other severity levels (warning, error, etc). These tests are stored as files in the &amp;lt;code&amp;gt;spec/logs&amp;lt;/code&amp;gt; directory. One example of a testing method is this one, which we've recently written:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RSpec.describe Api::V1::UsersController, type: :controller do&lt;br /&gt;
  let(:user) { build(:user, name: &amp;quot;Jane&amp;quot;, email: &amp;quot;jdoe@ncsu.edu&amp;quot;, full_name: &amp;quot;Jane Doe&amp;quot;) }&lt;br /&gt;
  let(:params) do { user: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Jane Doe&amp;quot;,&lt;br /&gt;
        &amp;quot;full_name&amp;quot;: &amp;quot;Jane Doe&amp;quot;,&lt;br /&gt;
        &amp;quot;email&amp;quot;: &amp;quot;jane.doe@example.com&amp;quot;,&lt;br /&gt;
        &amp;quot;role_id&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;institution_id&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;password&amp;quot;: &amp;quot;password&amp;quot;,&lt;br /&gt;
        &amp;quot;password_confirmation&amp;quot;: &amp;quot;password&amp;quot;   } }&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it &amp;quot;logs when user is created&amp;quot; do&lt;br /&gt;
    allow(Rails.logger).to receive(:info)&lt;br /&gt;
    expect(Rails.logger).to receive(:info)&lt;br /&gt;
&lt;br /&gt;
    post :create, params: params&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Enhancing error logging by capturing new cases====&lt;br /&gt;
Some functionality has changed between the old implementation and the reimplementation of the backend. For example, the reimplementation has different ways of performing error checking in some of the controller methods than the original implementation had. For these cases and others, we added logging to ensure that when a controller method fails, a detailed log message is produced and stored in the appropriate log file. &lt;br /&gt;
&lt;br /&gt;
====Correcting the use of the info log level for errors====&lt;br /&gt;
In the original backend implementation, the info severity level is used almost universally, even when logging errors. For example, in the original implementation of the bookmarks controller, the &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method logs errors that occur like so: &amp;lt;code&amp;gt;ExpertizaLogger.info LoggerMessage.new(controller_name, session[:user].name, $ERROR_INFO, request)&amp;lt;/code&amp;gt;. We have replaced these with the appropriate logging level, so that errors go to one file, and info to another. This expedites the debugging process for developers, as they will know where to look to find errors vs info.&lt;br /&gt;
&lt;br /&gt;
====Standardizing error messages to avoid mixed hardcoded strings and object outputs====&lt;br /&gt;
In the original backend implementation, sometimes the content of an error object was passed into logging messages, and sometimes hardcoded strings specific to the situation were. For example, in the original implementation of the student teams controller, the &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method uses hardcoded strings specifically indicating why the request failed - &amp;lt;code&amp;gt;ExpertizaLogger.info LoggerMessage.new(controller_name, session[:user].name, 'Team name missing while creating team', request)&amp;lt;/code&amp;gt;. However, in the bookmarks controller, the error info was logged like so: &amp;lt;code&amp;gt;ExpertizaLogger.info LoggerMessage.new(controller_name, session[:user].name, $ERROR_INFO, request)&amp;lt;/code&amp;gt;. We've increased the consistency across all logging messages to include detailed, context-specific error messages, as that is more informative to developers, and have added logging messages in that style everywhere they are relevant.&lt;br /&gt;
&lt;br /&gt;
====Ensuring consistent use of &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; (e.g., defaulting to session[:user].name unless context demands otherwise)====&lt;br /&gt;
Both implementations of logging use a &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; object to standardize information produced in logs. The &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; object takes, among other things, the unity id of the logger as a parameter. However, in the old backend, that parameter is sometimes passed in from the user's session like &amp;lt;code&amp;gt;session[:user].name&amp;lt;/code&amp;gt; and sometimes passed in through other means, such as &amp;lt;code&amp;gt;@participant.name&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;requested_user.name&amp;lt;/code&amp;gt;. We have standardized these in the reimplementation such that the user's session is used everywhere possible to ensure consistency.&lt;br /&gt;
&lt;br /&gt;
==Tests Explained==&lt;br /&gt;
This section will explain the tests we've written to varying levels of specificity. Where reasonable, we've omitted tests that are repetitive to reduce redundancy - for example, we only explain the info level logging tests in &amp;lt;code&amp;gt;spec/logs/expertiza_logger_spec.rb&amp;lt;/code&amp;gt;. While we have separate tests in that file for the other severity levels, they're very similar, and do not warrant separate explanation.&lt;br /&gt;
&lt;br /&gt;
===Expertiza Log Formatter Tests===&lt;br /&gt;
The Expertiza Log Formatter is designed to ensure consistent log formatting across various logging scenarios. The tests in &amp;lt;code&amp;gt;spec/logs/expertiza_log_formatter_spec.rb&amp;lt;/code&amp;gt; are designed to check this functionality. &lt;br /&gt;
&lt;br /&gt;
Before the tests, a few helpful variables are defined as such:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
let(:formatter) { ExpertizaLogFormatter.new }&lt;br /&gt;
let(:timestamp) { Time.now }&lt;br /&gt;
let(:severity) { 'INFO' }&lt;br /&gt;
let(:progname) { 'Expertiza' }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first two tests, included below, check that the log formatter can format messages correctly. The first test invokes the &amp;lt;code&amp;gt;call&amp;lt;/code&amp;gt; method on the formatter with info level severity, the current time as timestamp, 'Expertiza' as the program name, and a simple string as the message parameter. Given these simple parameters, we can easily check that the produced message, returned by the &amp;lt;code&amp;gt;call&amp;lt;/code&amp;gt; method, matches our expectations. The second test is very similar, but checks that a message with a newline produces a log without one. The &amp;lt;code&amp;gt;ExpertizaLogFormatter&amp;lt;/code&amp;gt; is designed to take all newlines and replace them with space characters, so that log files aren't unnecessarily messy.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when the message is a plain string' do&lt;br /&gt;
    let(:message) { 'Test message with more text' }&lt;br /&gt;
    it 'formats the message correctly' do&lt;br /&gt;
      formatted_message = formatter.call(severity, timestamp, progname, message)&lt;br /&gt;
      expect(formatted_message).to include(&amp;quot;TST=[#{timestamp}] SVT=[#{severity}] PNM=[#{progname}] OIP=[] RID=[] CTR=[] UID=[] MSG=[Test message with more text]&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
context 'when the message is a plain string with newline' do&lt;br /&gt;
    let(:message) { &amp;quot;Test message with newline\nto more text&amp;quot; }&lt;br /&gt;
    it 'formats the message correctly' do&lt;br /&gt;
      formatted_message = formatter.call(severity, timestamp, progname, message)&lt;br /&gt;
      expect(formatted_message).to include(&amp;quot;TST=[#{timestamp}] SVT=[#{severity}] PNM=[#{progname}] OIP=[] RID=[] CTR=[] UID=[] MSG=[Test message with newline to more text]&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The final two tests similarly check formatting, except instead of passing in a simple string, they instead pass in a &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; object. &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; is a class designed to hold more complex information than just a simple message. &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; objects can hold a reference to a 'generator' (typically the name of the controller the log comes from), the unity id of the generating user, a string message, and a request (made up of a remote ip address and a unique identifier/uuid). The first test here uses a &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; without a request, and ensures the resulting log contains the information from that object. The second test uses a &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; that does contain a request, and ensures the formatting and data integrity of the created log message similarly.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when the message is a LoggerMessage object' do&lt;br /&gt;
  let(:logger_message) do&lt;br /&gt;
    LoggerMessage.new('gen1', 'unityid1', 'Test message')&lt;br /&gt;
  end&lt;br /&gt;
  it 'formats the message correctly' do&lt;br /&gt;
    formatted_message = formatter.call(severity, timestamp, progname, logger_message)&lt;br /&gt;
    expect(formatted_message).to include(&amp;quot;TST=[#{timestamp}] SVT=[#{severity}] PNM=[#{progname}] OIP=[] RID=[] CTR=[gen1] UID=[unityid1] MSG=[Test message]&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
context 'when the message is a LoggerMessage object with request' do&lt;br /&gt;
  let(:logger_message) do&lt;br /&gt;
    LoggerMessage.new('gen1', 'unityid1', 'Test message', double(&amp;quot;request&amp;quot;, remote_ip: &amp;quot;192.168.1.1&amp;quot;, uuid: &amp;quot;12345&amp;quot;))&lt;br /&gt;
  end&lt;br /&gt;
  it 'formats the message correctly' do&lt;br /&gt;
    formatted_message = formatter.call(severity, timestamp, progname, logger_message)&lt;br /&gt;
    expect(formatted_message).to include(&amp;quot;TST=[#{timestamp}] SVT=[#{severity}] PNM=[#{progname}] OIP=[192.168.1.1] RID=[12345] CTR=[gen1] UID=[unityid1] MSG=[Test message]&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
===Expertiza Logger Tests===&lt;br /&gt;
The Expertiza Logger is designed to log information at varying severity levels, depending on which of its methods are called, while following standardized log formatting. To do so, it creates and stores one instance of Ruby's &amp;lt;code&amp;gt;Logger&amp;lt;/code&amp;gt; class for each severity level, and uses the aforementioned &amp;lt;code&amp;gt;ExpertizaLogFormatter&amp;lt;/code&amp;gt; to format incoming messages. Depending on the method called, &amp;lt;code&amp;gt;ExpertizaLogger&amp;lt;/code&amp;gt; logs to a file that corresponds to a specific logging level. The tests in &amp;lt;code&amp;gt;spec/logs/expertiza_logger_spec.rb&amp;lt;/code&amp;gt; are designed to check this functionality. &lt;br /&gt;
&lt;br /&gt;
Before the tests, a few helpful variables are defined as such, including a mocked instance of the &amp;lt;code&amp;gt;Logger&amp;lt;/code&amp;gt; class.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
let(:message) { 'Test message' }&lt;br /&gt;
let(:timestamp) { Time.now }&lt;br /&gt;
&lt;br /&gt;
# Create a mock logger instance&lt;br /&gt;
let(:mock_logger) { instance_double(Logger) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This test also uses a before block to enable the &amp;lt;code&amp;gt;Logger&amp;lt;/code&amp;gt; to receive a request for a new instance of itself and to return a mock logger, which can in turn receive various requests. This is important to avoid directly testing the &amp;lt;code&amp;gt;ExpertizaLogFormatter&amp;lt;/code&amp;gt;. The test is designed to rely on expected behavior from that class, rather than directly testing it, as that's outside the scope of these tests.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
before do&lt;br /&gt;
  allow(Logger).to receive(:new).and_return(mock_logger)&lt;br /&gt;
  allow(mock_logger).to receive(:formatter)&lt;br /&gt;
  allow(mock_logger).to receive(:formatter=).with(an_instance_of(ExpertizaLogFormatter))&lt;br /&gt;
  allow(mock_logger).to receive(:info)&lt;br /&gt;
  allow(mock_logger).to receive(:warn)&lt;br /&gt;
  allow(mock_logger).to receive(:error)&lt;br /&gt;
  allow(mock_logger).to receive(:fatal)&lt;br /&gt;
  allow(mock_logger).to receive(:debug)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then for each severity level, there is a test like this one. We're only including the info-level test here. The test calls the &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt; method of the &amp;lt;code&amp;gt;ExpertizaLogger&amp;lt;/code&amp;gt; class, which is expected to then call the &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; method on the &amp;lt;code&amp;gt;Logger&amp;lt;/code&amp;gt; class, passing in the appropriate log file for this severity level (&amp;lt;code&amp;gt;expertiza_info.log&amp;lt;/code&amp;gt;). The test expects that the &amp;lt;code&amp;gt;formatter&amp;lt;/code&amp;gt; attribute of this new &amp;lt;code&amp;gt;Logger&amp;lt;code&amp;gt; instance, referred to as &amp;lt;code&amp;gt;mock_logger&amp;lt;/code&amp;gt;, will be set equal to an instance of the &amp;lt;code&amp;gt;ExpertizaLogFormatter&amp;lt;/code&amp;gt; and that the &amp;lt;code&amp;gt;mock_logger&amp;lt;/code&amp;gt; receives a call to its &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt; method with the right message parameter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '.info' do&lt;br /&gt;
  it 'logs the message to the correct file with info severity' do&lt;br /&gt;
    ExpertizaLogger.info(message)&lt;br /&gt;
    expect(Logger).to have_received(:new).with(Rails.root.join('log', 'expertiza_info.log'))&lt;br /&gt;
    expect(mock_logger).to have_received(:formatter=).with(an_instance_of(ExpertizaLogFormatter))&lt;br /&gt;
    expect(mock_logger).to have_received(:info).with(message)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&lt;br /&gt;
#[https://github.com/expertiza/expertiza Expertiza on GitHub]&lt;br /&gt;
#[https://github.com/expertiza/reimplementation-front-end Reimplemented Frontend Github Project]&lt;br /&gt;
#[https://github.com/expertiza/reimplementation-back-end Reimplemented Backend GitHub Project]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end Reimplemented Backend GitHub Project Repository Fork]&lt;br /&gt;
#[http://expertiza.ncsu.edu/ The live Expertiza website]&lt;br /&gt;
#[https://drive.google.com/file/d/1JnMWG1d7P_yLQ_un_R7kMbTrBk5YoA87/view?usp=share_link Project demo link] &lt;br /&gt;
#[https://wiki.expertiza.ncsu.edu/index.php?title=Main_Page Expertiza project documentation wiki]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end/commit/aa84e46135d4f660c6a981f5d032cdf2a4b2f25e Initial logging commit]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end/commit/1e0ee7a0d7f6e6d48e9a82753ee0fa0afdf8440f Reimplement Expertiza Logger]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end/commit/ceee53b4d9ed4281ac2f0201873a40b90bceb039 Adding logging to ApplicationRecord]&lt;/div&gt;</summary>
		<author><name>Cshimes</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2024_-_E2471._Reimplement_logger&amp;diff=159785</id>
		<title>CSC/ECE 517 Fall 2024 - E2471. Reimplement logger</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2024_-_E2471._Reimplement_logger&amp;diff=159785"/>
		<updated>2024-11-26T15:00:05Z</updated>

		<summary type="html">&lt;p&gt;Cshimes: /* Expertiza Log Formatter Tests */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==E2471. Reimplement logger==&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===About Expertiza===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create new assignments and customize new or existing assignments. It also allows the instructor to create a list of topics the students can sign up for. Students can form teams in Expertiza to work on various projects and assignments. Students can also peer review other students' submissions. Expertiza supports submission across various document types, including the URLs and wiki pages. As the project has progressed, there has developed a need to reimplement the project using different frameworks. Our project specifically assists in this goal as it implements a logger for the [https://github.com/expertiza/reimplementation-back-end reimplemented backend]. This new backend utilizes Rails API to create a RESTful API that can be accessed by frontend implementations. The latest [https://github.com/expertiza/reimplementation-front-end frontend reimplementation] has used Typescript and React to create the UI. &lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The following tasks have been accomplished as part of this project:&lt;br /&gt;
&lt;br /&gt;
* Created an ExpertizaLogger to customize logging behavior in the new backend.&lt;br /&gt;
* Created special formats for the logging that is being performed to include the desired information. &lt;br /&gt;
* Created info, warn, error, fatal, and debug logging levels.&lt;br /&gt;
* Created hooks to log CRUD database transactions. &lt;br /&gt;
* Utilize hooks to automatically log all model CRUD operations. &lt;br /&gt;
&lt;br /&gt;
These tasks establish a uniform logging experience for all of the CRUD operations, and they provide the ability to log other specific details as desired manually. This ensures that we have a base implementation that complies with the database CRUD operation logging requirement while allowing developers to include manual logging such as error flows or other information that may be helpful for an administrator to consult. Moving forward, all ApplicationRecords will automatically log the CRUD operations, and developers can easily utilize &amp;quot;ExpertizaLogger.warn(message)&amp;quot; to log an info message, for example. &lt;br /&gt;
&lt;br /&gt;
===Implementation Details===&lt;br /&gt;
Our implementation primarily involved creating four new components: &lt;br /&gt;
&lt;br /&gt;
* Expertiza Logger class&lt;br /&gt;
* Expertiza Log Formatter class&lt;br /&gt;
* Logger Message class&lt;br /&gt;
* Logging concern&lt;br /&gt;
&lt;br /&gt;
These components are now explained in greater detail below. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===About Expertiza Logger===&lt;br /&gt;
This logger is responsible for providing the desired log levels in the Expertiza reimplemented backend. It specifically contains the info, warn, error, fatal, and debug logging levels. These logs are then stored in files named &amp;quot;expertiza_info.log&amp;quot;, &amp;quot;expertiza_warn.log&amp;quot;, etc. It utilizes the Expertiza Log Formatter, which is utilized to format all of the desired log messages.&lt;br /&gt;
&lt;br /&gt;
===About Expertiza Log Formatter===&lt;br /&gt;
This class is a log formatter to provide a uniform style that contains all of the information desired. This is a critical class, as it allows the logs to be effectively searched for the given information logged. It ensures that all logs are consistent and are also easily parsable. &lt;br /&gt;
&lt;br /&gt;
===About Logger Message===&lt;br /&gt;
This class is a simple model that provides the content for the message that is being formatted by Expertiza Logger. It includes such values as the Unity ID, a message, remote IP address, etc. This information is utilized when formatting the logs to ensure that this consistent information is presented and available for inspection without requiring additional developer effort. It makes it easy to modify the logger format because the information will remain consistent, while the Expertiza Log Formatter can adjust the output format easily for all subsequent logs without modifying log commands spread throughout the project. &lt;br /&gt;
&lt;br /&gt;
===About Logging Concern===&lt;br /&gt;
This concern was created as an easy way to ensure that critical events are logged by default in the application. In particular, our goal was to log the database CRUD events. This concern sets up the hooks necessary to call the log methods required to log these events. By including this concern in any model, it will automatically perform the desired CRUD logging. We have leveraged this combined with the model hierarchy of classes depending on ApplicationRecord to ensure logging compliance. That is, we have included the logging concern in ApplicationRecord, allowing any class that inherits from ApplicationRecord to benefit from the automatic logging configuration. This ensures that this architecture is sustainable in the future by ensuring that the desired CRUD operations will be logged without requiring additional developer configuration.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Testing from UI===&lt;br /&gt;
It is not possible to test and observe this behavior from the UI. This is intentional because users should not be able to access any of the runtime information that is being logged. This information could include users' personal information, etc. that only an admin should be able to inspect. These log files are created and are able to be inspected by an IT administrator, but should not be available for user inspection. &lt;br /&gt;
&lt;br /&gt;
If, however, the admin would like to test the implementation, they can interact with the backend using the frontend, Postman, etc. The actions they perform are logged and can then be inspected in the recorded logs.&lt;br /&gt;
&lt;br /&gt;
For example, here are a few test cases with respect to our code changes that can be tried:&lt;br /&gt;
1. Log in to the webpage. Inspecting the logs should show that the user's account information was retrieved from the database. &lt;br /&gt;
&lt;br /&gt;
2. Create a new assignment. Inspecting the logs will demonstrate that the desired information is persisted to the database. &lt;br /&gt;
&lt;br /&gt;
3. Edit the created assignment. Inspecting the logs will demonstrate that the newly updated information is persisted to the database. &lt;br /&gt;
&lt;br /&gt;
4. Delete the assignment. Inspecting the logs will reveal that the assignment was deleted.&lt;br /&gt;
&lt;br /&gt;
==Final Design Document==&lt;br /&gt;
&lt;br /&gt;
===Proposed Changes===&lt;br /&gt;
From observing the current state of the logging implementation, which includes most functionality from the original Expertiza, we have improved the logging for better observability into the system. To that end, we have implemented the following changes:&lt;br /&gt;
&lt;br /&gt;
====Writing more comprehensive automated tests and improving coverage====&lt;br /&gt;
We have written and executed automated tests to cover a range of logging scenarios. Tests on the CRUD operations of models now ensure the functionality of info-level logging. We've also added tests that check for logging at the other severity levels (warning, error, etc). These tests are stored as files in the &amp;lt;code&amp;gt;spec/logs&amp;lt;/code&amp;gt; directory. One example of a testing method is this one, which we've recently written:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RSpec.describe Api::V1::UsersController, type: :controller do&lt;br /&gt;
  let(:user) { build(:user, name: &amp;quot;Jane&amp;quot;, email: &amp;quot;jdoe@ncsu.edu&amp;quot;, full_name: &amp;quot;Jane Doe&amp;quot;) }&lt;br /&gt;
  let(:params) do { user: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Jane Doe&amp;quot;,&lt;br /&gt;
        &amp;quot;full_name&amp;quot;: &amp;quot;Jane Doe&amp;quot;,&lt;br /&gt;
        &amp;quot;email&amp;quot;: &amp;quot;jane.doe@example.com&amp;quot;,&lt;br /&gt;
        &amp;quot;role_id&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;institution_id&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;password&amp;quot;: &amp;quot;password&amp;quot;,&lt;br /&gt;
        &amp;quot;password_confirmation&amp;quot;: &amp;quot;password&amp;quot;   } }&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it &amp;quot;logs when user is created&amp;quot; do&lt;br /&gt;
    allow(Rails.logger).to receive(:info)&lt;br /&gt;
    expect(Rails.logger).to receive(:info)&lt;br /&gt;
&lt;br /&gt;
    post :create, params: params&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Enhancing error logging by capturing new cases====&lt;br /&gt;
Some functionality has changed between the old implementation and the reimplementation of the backend. For example, the reimplementation has different ways of performing error checking in some of the controller methods than the original implementation had. For these cases and others, we added logging to ensure that when a controller method fails, a detailed log message is produced and stored in the appropriate log file. &lt;br /&gt;
&lt;br /&gt;
====Correcting the use of the info log level for errors====&lt;br /&gt;
In the original backend implementation, the info severity level is used almost universally, even when logging errors. For example, in the original implementation of the bookmarks controller, the &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method logs errors that occur like so: &amp;lt;code&amp;gt;ExpertizaLogger.info LoggerMessage.new(controller_name, session[:user].name, $ERROR_INFO, request)&amp;lt;/code&amp;gt;. We have replaced these with the appropriate logging level, so that errors go to one file, and info to another. This expedites the debugging process for developers, as they will know where to look to find errors vs info.&lt;br /&gt;
&lt;br /&gt;
====Standardizing error messages to avoid mixed hardcoded strings and object outputs====&lt;br /&gt;
In the original backend implementation, sometimes the content of an error object was passed into logging messages, and sometimes hardcoded strings specific to the situation were. For example, in the original implementation of the student teams controller, the &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method uses hardcoded strings specifically indicating why the request failed - &amp;lt;code&amp;gt;ExpertizaLogger.info LoggerMessage.new(controller_name, session[:user].name, 'Team name missing while creating team', request)&amp;lt;/code&amp;gt;. However, in the bookmarks controller, the error info was logged like so: &amp;lt;code&amp;gt;ExpertizaLogger.info LoggerMessage.new(controller_name, session[:user].name, $ERROR_INFO, request)&amp;lt;/code&amp;gt;. We've increased the consistency across all logging messages to include detailed, context-specific error messages, as that is more informative to developers, and have added logging messages in that style everywhere they are relevant.&lt;br /&gt;
&lt;br /&gt;
====Ensuring consistent use of &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; (e.g., defaulting to session[:user].name unless context demands otherwise)====&lt;br /&gt;
Both implementations of logging use a &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; object to standardize information produced in logs. The &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; object takes, among other things, the unity id of the logger as a parameter. However, in the old backend, that parameter is sometimes passed in from the user's session like &amp;lt;code&amp;gt;session[:user].name&amp;lt;/code&amp;gt; and sometimes passed in through other means, such as &amp;lt;code&amp;gt;@participant.name&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;requested_user.name&amp;lt;/code&amp;gt;. We have standardized these in the reimplementation such that the user's session is used everywhere possible to ensure consistency.&lt;br /&gt;
&lt;br /&gt;
==Tests Explained==&lt;br /&gt;
This section will explain the tests we've written to varying levels of specificity. Where reasonable, we've omitted tests that are repetitive to reduce redundancy - for example, we only explain the info level logging tests in &amp;lt;code&amp;gt;spec/logs/expertiza_logger_spec.rb&amp;lt;/code&amp;gt;. While we have separate tests in that file for the other severity levels, they're very similar, and do not warrant separate explanation.&lt;br /&gt;
&lt;br /&gt;
===Expertiza Log Formatter Tests===&lt;br /&gt;
The Expertiza Log Formatter is designed to ensure consistent log formatting across various logging scenarios. The tests in &amp;lt;code&amp;gt;spec/logs/expertiza_log_formatter_spec.rb&amp;lt;/code&amp;gt; are designed to check this functionality. &lt;br /&gt;
&lt;br /&gt;
Before the tests, a few helpful variables are defined as such:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
let(:formatter) { ExpertizaLogFormatter.new }&lt;br /&gt;
let(:timestamp) { Time.now }&lt;br /&gt;
let(:severity) { 'INFO' }&lt;br /&gt;
let(:progname) { 'Expertiza' }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first two tests, included below, check that the log formatter can format messages correctly. The first test invokes the &amp;lt;code&amp;gt;call&amp;lt;/code&amp;gt; method on the formatter with info level severity, the current time as timestamp, 'Expertiza' as the program name, and a simple string as the message parameter. Given these simple parameters, we can easily check that the produced message, returned by the &amp;lt;code&amp;gt;call&amp;lt;/code&amp;gt; method, matches our expectations. The second test is very similar, but checks that a message with a newline produces a log without one. The &amp;lt;code&amp;gt;ExpertizaLogFormatter&amp;lt;/code&amp;gt; is designed to take all newlines and replace them with space characters, so that log files aren't unnecessarily messy.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when the message is a plain string' do&lt;br /&gt;
    let(:message) { 'Test message with more text' }&lt;br /&gt;
    it 'formats the message correctly' do&lt;br /&gt;
      formatted_message = formatter.call(severity, timestamp, progname, message)&lt;br /&gt;
      expect(formatted_message).to include(&amp;quot;TST=[#{timestamp}] SVT=[#{severity}] PNM=[#{progname}] OIP=[] RID=[] CTR=[] UID=[] MSG=[Test message with more text]&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
context 'when the message is a plain string with newline' do&lt;br /&gt;
    let(:message) { &amp;quot;Test message with newline\nto more text&amp;quot; }&lt;br /&gt;
    it 'formats the message correctly' do&lt;br /&gt;
      formatted_message = formatter.call(severity, timestamp, progname, message)&lt;br /&gt;
      expect(formatted_message).to include(&amp;quot;TST=[#{timestamp}] SVT=[#{severity}] PNM=[#{progname}] OIP=[] RID=[] CTR=[] UID=[] MSG=[Test message with newline to more text]&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The final two tests similarly check formatting, except instead of passing in a simple string, they instead pass in a &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; object. &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; is a class designed to hold more complex information than just a simple message. &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; objects can hold a reference to a 'generator' (typically the name of the controller the log comes from), the unity id of the generating user, a string message, and a request (made up of a remote ip address and a unique identifier/uuid). The first test here uses a &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; without a request, and ensures the resulting log contains the information from that object. The second test uses a &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; that does contain a request, and ensures the formatting and data integrity of the created log message similarly.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when the message is a LoggerMessage object' do&lt;br /&gt;
  let(:logger_message) do&lt;br /&gt;
    LoggerMessage.new('gen1', 'unityid1', 'Test message')&lt;br /&gt;
  end&lt;br /&gt;
  it 'formats the message correctly' do&lt;br /&gt;
    formatted_message = formatter.call(severity, timestamp, progname, logger_message)&lt;br /&gt;
    expect(formatted_message).to include(&amp;quot;TST=[#{timestamp}] SVT=[#{severity}] PNM=[#{progname}] OIP=[] RID=[] CTR=[gen1] UID=[unityid1] MSG=[Test message]&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
context 'when the message is a LoggerMessage object with request' do&lt;br /&gt;
  let(:logger_message) do&lt;br /&gt;
    LoggerMessage.new('gen1', 'unityid1', 'Test message', double(&amp;quot;request&amp;quot;, remote_ip: &amp;quot;192.168.1.1&amp;quot;, uuid: &amp;quot;12345&amp;quot;))&lt;br /&gt;
  end&lt;br /&gt;
  it 'formats the message correctly' do&lt;br /&gt;
    formatted_message = formatter.call(severity, timestamp, progname, logger_message)&lt;br /&gt;
    expect(formatted_message).to include(&amp;quot;TST=[#{timestamp}] SVT=[#{severity}] PNM=[#{progname}] OIP=[192.168.1.1] RID=[12345] CTR=[gen1] UID=[unityid1] MSG=[Test message]&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&lt;br /&gt;
#[https://github.com/expertiza/expertiza Expertiza on GitHub]&lt;br /&gt;
#[https://github.com/expertiza/reimplementation-front-end Reimplemented Frontend Github Project]&lt;br /&gt;
#[https://github.com/expertiza/reimplementation-back-end Reimplemented Backend GitHub Project]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end Reimplemented Backend GitHub Project Repository Fork]&lt;br /&gt;
#[http://expertiza.ncsu.edu/ The live Expertiza website]&lt;br /&gt;
#[https://drive.google.com/file/d/1JnMWG1d7P_yLQ_un_R7kMbTrBk5YoA87/view?usp=share_link Project demo link] &lt;br /&gt;
#[https://wiki.expertiza.ncsu.edu/index.php?title=Main_Page Expertiza project documentation wiki]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end/commit/aa84e46135d4f660c6a981f5d032cdf2a4b2f25e Initial logging commit]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end/commit/1e0ee7a0d7f6e6d48e9a82753ee0fa0afdf8440f Reimplement Expertiza Logger]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end/commit/ceee53b4d9ed4281ac2f0201873a40b90bceb039 Adding logging to ApplicationRecord]&lt;/div&gt;</summary>
		<author><name>Cshimes</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2024_-_E2471._Reimplement_logger&amp;diff=159784</id>
		<title>CSC/ECE 517 Fall 2024 - E2471. Reimplement logger</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2024_-_E2471._Reimplement_logger&amp;diff=159784"/>
		<updated>2024-11-26T14:58:38Z</updated>

		<summary type="html">&lt;p&gt;Cshimes: /* Tests Explained */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==E2471. Reimplement logger==&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===About Expertiza===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create new assignments and customize new or existing assignments. It also allows the instructor to create a list of topics the students can sign up for. Students can form teams in Expertiza to work on various projects and assignments. Students can also peer review other students' submissions. Expertiza supports submission across various document types, including the URLs and wiki pages. As the project has progressed, there has developed a need to reimplement the project using different frameworks. Our project specifically assists in this goal as it implements a logger for the [https://github.com/expertiza/reimplementation-back-end reimplemented backend]. This new backend utilizes Rails API to create a RESTful API that can be accessed by frontend implementations. The latest [https://github.com/expertiza/reimplementation-front-end frontend reimplementation] has used Typescript and React to create the UI. &lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The following tasks have been accomplished as part of this project:&lt;br /&gt;
&lt;br /&gt;
* Created an ExpertizaLogger to customize logging behavior in the new backend.&lt;br /&gt;
* Created special formats for the logging that is being performed to include the desired information. &lt;br /&gt;
* Created info, warn, error, fatal, and debug logging levels.&lt;br /&gt;
* Created hooks to log CRUD database transactions. &lt;br /&gt;
* Utilize hooks to automatically log all model CRUD operations. &lt;br /&gt;
&lt;br /&gt;
These tasks establish a uniform logging experience for all of the CRUD operations, and they provide the ability to log other specific details as desired manually. This ensures that we have a base implementation that complies with the database CRUD operation logging requirement while allowing developers to include manual logging such as error flows or other information that may be helpful for an administrator to consult. Moving forward, all ApplicationRecords will automatically log the CRUD operations, and developers can easily utilize &amp;quot;ExpertizaLogger.warn(message)&amp;quot; to log an info message, for example. &lt;br /&gt;
&lt;br /&gt;
===Implementation Details===&lt;br /&gt;
Our implementation primarily involved creating four new components: &lt;br /&gt;
&lt;br /&gt;
* Expertiza Logger class&lt;br /&gt;
* Expertiza Log Formatter class&lt;br /&gt;
* Logger Message class&lt;br /&gt;
* Logging concern&lt;br /&gt;
&lt;br /&gt;
These components are now explained in greater detail below. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===About Expertiza Logger===&lt;br /&gt;
This logger is responsible for providing the desired log levels in the Expertiza reimplemented backend. It specifically contains the info, warn, error, fatal, and debug logging levels. These logs are then stored in files named &amp;quot;expertiza_info.log&amp;quot;, &amp;quot;expertiza_warn.log&amp;quot;, etc. It utilizes the Expertiza Log Formatter, which is utilized to format all of the desired log messages.&lt;br /&gt;
&lt;br /&gt;
===About Expertiza Log Formatter===&lt;br /&gt;
This class is a log formatter to provide a uniform style that contains all of the information desired. This is a critical class, as it allows the logs to be effectively searched for the given information logged. It ensures that all logs are consistent and are also easily parsable. &lt;br /&gt;
&lt;br /&gt;
===About Logger Message===&lt;br /&gt;
This class is a simple model that provides the content for the message that is being formatted by Expertiza Logger. It includes such values as the Unity ID, a message, remote IP address, etc. This information is utilized when formatting the logs to ensure that this consistent information is presented and available for inspection without requiring additional developer effort. It makes it easy to modify the logger format because the information will remain consistent, while the Expertiza Log Formatter can adjust the output format easily for all subsequent logs without modifying log commands spread throughout the project. &lt;br /&gt;
&lt;br /&gt;
===About Logging Concern===&lt;br /&gt;
This concern was created as an easy way to ensure that critical events are logged by default in the application. In particular, our goal was to log the database CRUD events. This concern sets up the hooks necessary to call the log methods required to log these events. By including this concern in any model, it will automatically perform the desired CRUD logging. We have leveraged this combined with the model hierarchy of classes depending on ApplicationRecord to ensure logging compliance. That is, we have included the logging concern in ApplicationRecord, allowing any class that inherits from ApplicationRecord to benefit from the automatic logging configuration. This ensures that this architecture is sustainable in the future by ensuring that the desired CRUD operations will be logged without requiring additional developer configuration.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Testing from UI===&lt;br /&gt;
It is not possible to test and observe this behavior from the UI. This is intentional because users should not be able to access any of the runtime information that is being logged. This information could include users' personal information, etc. that only an admin should be able to inspect. These log files are created and are able to be inspected by an IT administrator, but should not be available for user inspection. &lt;br /&gt;
&lt;br /&gt;
If, however, the admin would like to test the implementation, they can interact with the backend using the frontend, Postman, etc. The actions they perform are logged and can then be inspected in the recorded logs.&lt;br /&gt;
&lt;br /&gt;
For example, here are a few test cases with respect to our code changes that can be tried:&lt;br /&gt;
1. Log in to the webpage. Inspecting the logs should show that the user's account information was retrieved from the database. &lt;br /&gt;
&lt;br /&gt;
2. Create a new assignment. Inspecting the logs will demonstrate that the desired information is persisted to the database. &lt;br /&gt;
&lt;br /&gt;
3. Edit the created assignment. Inspecting the logs will demonstrate that the newly updated information is persisted to the database. &lt;br /&gt;
&lt;br /&gt;
4. Delete the assignment. Inspecting the logs will reveal that the assignment was deleted.&lt;br /&gt;
&lt;br /&gt;
==Final Design Document==&lt;br /&gt;
&lt;br /&gt;
===Proposed Changes===&lt;br /&gt;
From observing the current state of the logging implementation, which includes most functionality from the original Expertiza, we have improved the logging for better observability into the system. To that end, we have implemented the following changes:&lt;br /&gt;
&lt;br /&gt;
====Writing more comprehensive automated tests and improving coverage====&lt;br /&gt;
We have written and executed automated tests to cover a range of logging scenarios. Tests on the CRUD operations of models now ensure the functionality of info-level logging. We've also added tests that check for logging at the other severity levels (warning, error, etc). These tests are stored as files in the &amp;lt;code&amp;gt;spec/logs&amp;lt;/code&amp;gt; directory. One example of a testing method is this one, which we've recently written:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RSpec.describe Api::V1::UsersController, type: :controller do&lt;br /&gt;
  let(:user) { build(:user, name: &amp;quot;Jane&amp;quot;, email: &amp;quot;jdoe@ncsu.edu&amp;quot;, full_name: &amp;quot;Jane Doe&amp;quot;) }&lt;br /&gt;
  let(:params) do { user: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Jane Doe&amp;quot;,&lt;br /&gt;
        &amp;quot;full_name&amp;quot;: &amp;quot;Jane Doe&amp;quot;,&lt;br /&gt;
        &amp;quot;email&amp;quot;: &amp;quot;jane.doe@example.com&amp;quot;,&lt;br /&gt;
        &amp;quot;role_id&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;institution_id&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;password&amp;quot;: &amp;quot;password&amp;quot;,&lt;br /&gt;
        &amp;quot;password_confirmation&amp;quot;: &amp;quot;password&amp;quot;   } }&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it &amp;quot;logs when user is created&amp;quot; do&lt;br /&gt;
    allow(Rails.logger).to receive(:info)&lt;br /&gt;
    expect(Rails.logger).to receive(:info)&lt;br /&gt;
&lt;br /&gt;
    post :create, params: params&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Enhancing error logging by capturing new cases====&lt;br /&gt;
Some functionality has changed between the old implementation and the reimplementation of the backend. For example, the reimplementation has different ways of performing error checking in some of the controller methods than the original implementation had. For these cases and others, we added logging to ensure that when a controller method fails, a detailed log message is produced and stored in the appropriate log file. &lt;br /&gt;
&lt;br /&gt;
====Correcting the use of the info log level for errors====&lt;br /&gt;
In the original backend implementation, the info severity level is used almost universally, even when logging errors. For example, in the original implementation of the bookmarks controller, the &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method logs errors that occur like so: &amp;lt;code&amp;gt;ExpertizaLogger.info LoggerMessage.new(controller_name, session[:user].name, $ERROR_INFO, request)&amp;lt;/code&amp;gt;. We have replaced these with the appropriate logging level, so that errors go to one file, and info to another. This expedites the debugging process for developers, as they will know where to look to find errors vs info.&lt;br /&gt;
&lt;br /&gt;
====Standardizing error messages to avoid mixed hardcoded strings and object outputs====&lt;br /&gt;
In the original backend implementation, sometimes the content of an error object was passed into logging messages, and sometimes hardcoded strings specific to the situation were. For example, in the original implementation of the student teams controller, the &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method uses hardcoded strings specifically indicating why the request failed - &amp;lt;code&amp;gt;ExpertizaLogger.info LoggerMessage.new(controller_name, session[:user].name, 'Team name missing while creating team', request)&amp;lt;/code&amp;gt;. However, in the bookmarks controller, the error info was logged like so: &amp;lt;code&amp;gt;ExpertizaLogger.info LoggerMessage.new(controller_name, session[:user].name, $ERROR_INFO, request)&amp;lt;/code&amp;gt;. We've increased the consistency across all logging messages to include detailed, context-specific error messages, as that is more informative to developers, and have added logging messages in that style everywhere they are relevant.&lt;br /&gt;
&lt;br /&gt;
====Ensuring consistent use of &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; (e.g., defaulting to session[:user].name unless context demands otherwise)====&lt;br /&gt;
Both implementations of logging use a &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; object to standardize information produced in logs. The &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; object takes, among other things, the unity id of the logger as a parameter. However, in the old backend, that parameter is sometimes passed in from the user's session like &amp;lt;code&amp;gt;session[:user].name&amp;lt;/code&amp;gt; and sometimes passed in through other means, such as &amp;lt;code&amp;gt;@participant.name&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;requested_user.name&amp;lt;/code&amp;gt;. We have standardized these in the reimplementation such that the user's session is used everywhere possible to ensure consistency.&lt;br /&gt;
&lt;br /&gt;
==Tests Explained==&lt;br /&gt;
This section will explain the tests we've written to varying levels of specificity. Where reasonable, we've omitted tests that are repetitive to reduce redundancy - for example, we only explain the info level logging tests in &amp;lt;code&amp;gt;spec/logs/expertiza_logger_spec.rb&amp;lt;/code&amp;gt;. While we have separate tests in that file for the other severity levels, they're very similar, and do not warrant separate explanation.&lt;br /&gt;
&lt;br /&gt;
===Expertiza Log Formatter Tests===&lt;br /&gt;
The Expertiza Log Formatter is designed to ensure consistent log formatting across various logging scenarios. The tests in &amp;lt;code&amp;gt;spec/logs/expertiza_log_formatter_spec.rb&amp;lt;/code&amp;gt; are designed to check this functionality. &lt;br /&gt;
&lt;br /&gt;
Before the tests, a few helpful variables are defined as such:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
let(:formatter) { ExpertizaLogFormatter.new }&lt;br /&gt;
let(:timestamp) { Time.now }&lt;br /&gt;
let(:severity) { 'INFO' }&lt;br /&gt;
let(:progname) { 'Expertiza' }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first two tests, included below, check that the log formatter can format messages correctly. The first test invokes the &amp;lt;code&amp;gt;call&amp;lt;/code&amp;gt; method on the formatter with info level severity, the current time as timestamp, 'Expertiza' as the program name, and a simple string as the message parameter. Given these simple parameters, we can easily check that the produced message, returned by the &amp;lt;code&amp;gt;call&amp;lt;/code&amp;gt; method, matches our expectations. The second test is very similar, but checks that a message with a newline produces a log without one. The &amp;lt;code&amp;gt;ExpertizaLogFormatter&amp;lt;/code&amp;gt; is designed to take all newlines and replace them with space characters, so that log files aren't unnecessarily messy.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when the message is a plain string' do&lt;br /&gt;
    let(:message) { 'Test message with more text' }&lt;br /&gt;
    it 'formats the message correctly' do&lt;br /&gt;
      formatted_message = formatter.call(severity, timestamp, progname, message)&lt;br /&gt;
      expect(formatted_message).to include(&amp;quot;TST=[#{timestamp}] SVT=[#{severity}] PNM=[#{progname}] OIP=[] RID=[] CTR=[] UID=[] MSG=[Test message with more text]&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
context 'when the message is a plain string with newline' do&lt;br /&gt;
    let(:message) { &amp;quot;Test message with newline\nto more text&amp;quot; }&lt;br /&gt;
    it 'formats the message correctly' do&lt;br /&gt;
      formatted_message = formatter.call(severity, timestamp, progname, message)&lt;br /&gt;
      expect(formatted_message).to include(&amp;quot;TST=[#{timestamp}] SVT=[#{severity}] PNM=[#{progname}] OIP=[] RID=[] CTR=[] UID=[] MSG=[Test message with newline to more text]&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The final two tests similarly check formatting, except instead of passing in a simple string, they instead pass in a &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; object. &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; is a class designed to hold more complex information than just a simple message. &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; objects can hold a reference to a 'generator' (typically the name of the controller the log comes from), the unity id of the generating user, a string message, and a request (made up of a remote ip address and a unique identifier/uuid). The first test here uses a &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; without a request, and ensures the resulting log contains the information from that object. The second test uses a &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; that does contain a request, and ensures the formatting and data integrity of the created log message similarly.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when the message is a LoggerMessage object' do&lt;br /&gt;
  let(:logger_message) do&lt;br /&gt;
    LoggerMessage.new('gen1', 'unityid1', 'Test message')&lt;br /&gt;
  end&lt;br /&gt;
  it 'formats the message correctly' do&lt;br /&gt;
    formatted_message = formatter.call(severity, timestamp, progname, logger_message)&lt;br /&gt;
    expect(formatted_message).to include(&amp;quot;TST=[#{timestamp}] SVT=[#{severity}] PNM=[#{progname}] OIP=[] RID=[] CTR=[gen1] UID=[unityid1] MSG=[Test message]&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
context 'when the message is a LoggerMessage object with request' do&lt;br /&gt;
  let(:logger_message) do&lt;br /&gt;
    LoggerMessage.new('gen1', 'unityid1', 'Test message', double(&amp;quot;request&amp;quot;, remote_ip: &amp;quot;192.168.1.1&amp;quot;, uuid: &amp;quot;12345&amp;quot;))&lt;br /&gt;
  end&lt;br /&gt;
  it 'formats the message correctly' do&lt;br /&gt;
    formatted_message = formatter.call(severity, timestamp, progname, logger_message)&lt;br /&gt;
    expect(formatted_message).to include(&amp;quot;TST=[#{timestamp}] SVT=[#{severity}] PNM=[#{progname}] OIP=[192.168.1.1] RID=[12345] CTR=[gen1] UID=[unityid1] MSG=[Test message]&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
===Expertiza Logger Tests===&lt;br /&gt;
The Expertiza Logger is designed to log information at varying severity levels, depending on which of its methods are called, while following standardized log formatting. To do so, it creates and stores one instance of Ruby's &amp;lt;code&amp;gt;Logger&amp;lt;/code&amp;gt; class for each severity level, and uses the aforementioned &amp;lt;code&amp;gt;ExpertizaLogFormatter&amp;lt;/code&amp;gt; to format incoming messages. Depending on the method called, &amp;lt;code&amp;gt;ExpertizaLogger&amp;lt;/code&amp;gt; logs to a file that corresponds to a specific logging level. The tests in &amp;lt;code&amp;gt;spec/logs/expertiza_logger_spec.rb&amp;lt;/code&amp;gt; are designed to check this functionality. &lt;br /&gt;
&lt;br /&gt;
Before the tests, a few helpful variables are defined as such, including a mocked instance of the &amp;lt;code&amp;gt;Logger&amp;lt;/code&amp;gt; class.&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
let(:message) { 'Test message' }&lt;br /&gt;
let(:timestamp) { Time.now }&lt;br /&gt;
&lt;br /&gt;
# Create a mock logger instance&lt;br /&gt;
let(:mock_logger) { instance_double(Logger) }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This test also uses a before block to enable the &amp;lt;code&amp;gt;Logger&amp;lt;/code&amp;gt; to receive a request for a new instance of itself and to return a mock logger, which can in turn receive various requests. This is important to avoid directly testing the &amp;lt;code&amp;gt;ExpertizaLogFormatter&amp;lt;/code&amp;gt;. The test is designed to rely on expected behavior from that class, rather than directly testing it, as that's outside the scope of these tests.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
before do&lt;br /&gt;
  allow(Logger).to receive(:new).and_return(mock_logger)&lt;br /&gt;
  allow(mock_logger).to receive(:formatter)&lt;br /&gt;
  allow(mock_logger).to receive(:formatter=).with(an_instance_of(ExpertizaLogFormatter))&lt;br /&gt;
  allow(mock_logger).to receive(:info)&lt;br /&gt;
  allow(mock_logger).to receive(:warn)&lt;br /&gt;
  allow(mock_logger).to receive(:error)&lt;br /&gt;
  allow(mock_logger).to receive(:fatal)&lt;br /&gt;
  allow(mock_logger).to receive(:debug)&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Then for each severity level, there is a test like this one. We're only including the info-level test here. The test calls the &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt; method of the &amp;lt;code&amp;gt;ExpertizaLogger&amp;lt;/code&amp;gt; class, which is expected to then call the &amp;lt;code&amp;gt;new&amp;lt;/code&amp;gt; method on the &amp;lt;code&amp;gt;Logger&amp;lt;/code&amp;gt; class, passing in the appropriate log file for this severity level (&amp;lt;code&amp;gt;expertiza_info.log&amp;lt;/code&amp;gt;). The test expects that the &amp;lt;code&amp;gt;formatter&amp;lt;/code&amp;gt; attribute of this new &amp;lt;code&amp;gt;Logger&amp;lt;code&amp;gt; instance, referred to as &amp;lt;code&amp;gt;mock_logger&amp;lt;/code&amp;gt;, will be set equal to an instance of the &amp;lt;code&amp;gt;ExpertizaLogFormatter&amp;lt;/code&amp;gt; and that the &amp;lt;code&amp;gt;mock_logger&amp;lt;/code&amp;gt; receives a call to its &amp;lt;code&amp;gt;info&amp;lt;/code&amp;gt; method with the right message parameter.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
describe '.info' do&lt;br /&gt;
  it 'logs the message to the correct file with info severity' do&lt;br /&gt;
    ExpertizaLogger.info(message)&lt;br /&gt;
    expect(Logger).to have_received(:new).with(Rails.root.join('log', 'expertiza_info.log'))&lt;br /&gt;
    expect(mock_logger).to have_received(:formatter=).with(an_instance_of(ExpertizaLogFormatter))&lt;br /&gt;
    expect(mock_logger).to have_received(:info).with(message)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&lt;br /&gt;
#[https://github.com/expertiza/expertiza Expertiza on GitHub]&lt;br /&gt;
#[https://github.com/expertiza/reimplementation-front-end Reimplemented Frontend Github Project]&lt;br /&gt;
#[https://github.com/expertiza/reimplementation-back-end Reimplemented Backend GitHub Project]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end Reimplemented Backend GitHub Project Repository Fork]&lt;br /&gt;
#[http://expertiza.ncsu.edu/ The live Expertiza website]&lt;br /&gt;
#[https://drive.google.com/file/d/1JnMWG1d7P_yLQ_un_R7kMbTrBk5YoA87/view?usp=share_link Project demo link] &lt;br /&gt;
#[https://wiki.expertiza.ncsu.edu/index.php?title=Main_Page Expertiza project documentation wiki]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end/commit/aa84e46135d4f660c6a981f5d032cdf2a4b2f25e Initial logging commit]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end/commit/1e0ee7a0d7f6e6d48e9a82753ee0fa0afdf8440f Reimplement Expertiza Logger]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end/commit/ceee53b4d9ed4281ac2f0201873a40b90bceb039 Adding logging to ApplicationRecord]&lt;/div&gt;</summary>
		<author><name>Cshimes</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2024_-_E2471._Reimplement_logger&amp;diff=159783</id>
		<title>CSC/ECE 517 Fall 2024 - E2471. Reimplement logger</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2024_-_E2471._Reimplement_logger&amp;diff=159783"/>
		<updated>2024-11-26T14:38:02Z</updated>

		<summary type="html">&lt;p&gt;Cshimes: /* Final Design Document */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==E2471. Reimplement logger==&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===About Expertiza===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create new assignments and customize new or existing assignments. It also allows the instructor to create a list of topics the students can sign up for. Students can form teams in Expertiza to work on various projects and assignments. Students can also peer review other students' submissions. Expertiza supports submission across various document types, including the URLs and wiki pages. As the project has progressed, there has developed a need to reimplement the project using different frameworks. Our project specifically assists in this goal as it implements a logger for the [https://github.com/expertiza/reimplementation-back-end reimplemented backend]. This new backend utilizes Rails API to create a RESTful API that can be accessed by frontend implementations. The latest [https://github.com/expertiza/reimplementation-front-end frontend reimplementation] has used Typescript and React to create the UI. &lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The following tasks have been accomplished as part of this project:&lt;br /&gt;
&lt;br /&gt;
* Created an ExpertizaLogger to customize logging behavior in the new backend.&lt;br /&gt;
* Created special formats for the logging that is being performed to include the desired information. &lt;br /&gt;
* Created info, warn, error, fatal, and debug logging levels.&lt;br /&gt;
* Created hooks to log CRUD database transactions. &lt;br /&gt;
* Utilize hooks to automatically log all model CRUD operations. &lt;br /&gt;
&lt;br /&gt;
These tasks establish a uniform logging experience for all of the CRUD operations, and they provide the ability to log other specific details as desired manually. This ensures that we have a base implementation that complies with the database CRUD operation logging requirement while allowing developers to include manual logging such as error flows or other information that may be helpful for an administrator to consult. Moving forward, all ApplicationRecords will automatically log the CRUD operations, and developers can easily utilize &amp;quot;ExpertizaLogger.warn(message)&amp;quot; to log an info message, for example. &lt;br /&gt;
&lt;br /&gt;
===Implementation Details===&lt;br /&gt;
Our implementation primarily involved creating four new components: &lt;br /&gt;
&lt;br /&gt;
* Expertiza Logger class&lt;br /&gt;
* Expertiza Log Formatter class&lt;br /&gt;
* Logger Message class&lt;br /&gt;
* Logging concern&lt;br /&gt;
&lt;br /&gt;
These components are now explained in greater detail below. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===About Expertiza Logger===&lt;br /&gt;
This logger is responsible for providing the desired log levels in the Expertiza reimplemented backend. It specifically contains the info, warn, error, fatal, and debug logging levels. These logs are then stored in files named &amp;quot;expertiza_info.log&amp;quot;, &amp;quot;expertiza_warn.log&amp;quot;, etc. It utilizes the Expertiza Log Formatter, which is utilized to format all of the desired log messages.&lt;br /&gt;
&lt;br /&gt;
===About Expertiza Log Formatter===&lt;br /&gt;
This class is a log formatter to provide a uniform style that contains all of the information desired. This is a critical class, as it allows the logs to be effectively searched for the given information logged. It ensures that all logs are consistent and are also easily parsable. &lt;br /&gt;
&lt;br /&gt;
===About Logger Message===&lt;br /&gt;
This class is a simple model that provides the content for the message that is being formatted by Expertiza Logger. It includes such values as the Unity ID, a message, remote IP address, etc. This information is utilized when formatting the logs to ensure that this consistent information is presented and available for inspection without requiring additional developer effort. It makes it easy to modify the logger format because the information will remain consistent, while the Expertiza Log Formatter can adjust the output format easily for all subsequent logs without modifying log commands spread throughout the project. &lt;br /&gt;
&lt;br /&gt;
===About Logging Concern===&lt;br /&gt;
This concern was created as an easy way to ensure that critical events are logged by default in the application. In particular, our goal was to log the database CRUD events. This concern sets up the hooks necessary to call the log methods required to log these events. By including this concern in any model, it will automatically perform the desired CRUD logging. We have leveraged this combined with the model hierarchy of classes depending on ApplicationRecord to ensure logging compliance. That is, we have included the logging concern in ApplicationRecord, allowing any class that inherits from ApplicationRecord to benefit from the automatic logging configuration. This ensures that this architecture is sustainable in the future by ensuring that the desired CRUD operations will be logged without requiring additional developer configuration.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Testing from UI===&lt;br /&gt;
It is not possible to test and observe this behavior from the UI. This is intentional because users should not be able to access any of the runtime information that is being logged. This information could include users' personal information, etc. that only an admin should be able to inspect. These log files are created and are able to be inspected by an IT administrator, but should not be available for user inspection. &lt;br /&gt;
&lt;br /&gt;
If, however, the admin would like to test the implementation, they can interact with the backend using the frontend, Postman, etc. The actions they perform are logged and can then be inspected in the recorded logs.&lt;br /&gt;
&lt;br /&gt;
For example, here are a few test cases with respect to our code changes that can be tried:&lt;br /&gt;
1. Log in to the webpage. Inspecting the logs should show that the user's account information was retrieved from the database. &lt;br /&gt;
&lt;br /&gt;
2. Create a new assignment. Inspecting the logs will demonstrate that the desired information is persisted to the database. &lt;br /&gt;
&lt;br /&gt;
3. Edit the created assignment. Inspecting the logs will demonstrate that the newly updated information is persisted to the database. &lt;br /&gt;
&lt;br /&gt;
4. Delete the assignment. Inspecting the logs will reveal that the assignment was deleted.&lt;br /&gt;
&lt;br /&gt;
==Final Design Document==&lt;br /&gt;
&lt;br /&gt;
===Proposed Changes===&lt;br /&gt;
From observing the current state of the logging implementation, which includes most functionality from the original Expertiza, we have improved the logging for better observability into the system. To that end, we have implemented the following changes:&lt;br /&gt;
&lt;br /&gt;
====Writing more comprehensive automated tests and improving coverage====&lt;br /&gt;
We have written and executed automated tests to cover a range of logging scenarios. Tests on the CRUD operations of models now ensure the functionality of info-level logging. We've also added tests that check for logging at the other severity levels (warning, error, etc). These tests are stored as files in the &amp;lt;code&amp;gt;spec/logs&amp;lt;/code&amp;gt; directory. One example of a testing method is this one, which we've recently written:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RSpec.describe Api::V1::UsersController, type: :controller do&lt;br /&gt;
  let(:user) { build(:user, name: &amp;quot;Jane&amp;quot;, email: &amp;quot;jdoe@ncsu.edu&amp;quot;, full_name: &amp;quot;Jane Doe&amp;quot;) }&lt;br /&gt;
  let(:params) do { user: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Jane Doe&amp;quot;,&lt;br /&gt;
        &amp;quot;full_name&amp;quot;: &amp;quot;Jane Doe&amp;quot;,&lt;br /&gt;
        &amp;quot;email&amp;quot;: &amp;quot;jane.doe@example.com&amp;quot;,&lt;br /&gt;
        &amp;quot;role_id&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;institution_id&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;password&amp;quot;: &amp;quot;password&amp;quot;,&lt;br /&gt;
        &amp;quot;password_confirmation&amp;quot;: &amp;quot;password&amp;quot;   } }&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it &amp;quot;logs when user is created&amp;quot; do&lt;br /&gt;
    allow(Rails.logger).to receive(:info)&lt;br /&gt;
    expect(Rails.logger).to receive(:info)&lt;br /&gt;
&lt;br /&gt;
    post :create, params: params&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Enhancing error logging by capturing new cases====&lt;br /&gt;
Some functionality has changed between the old implementation and the reimplementation of the backend. For example, the reimplementation has different ways of performing error checking in some of the controller methods than the original implementation had. For these cases and others, we added logging to ensure that when a controller method fails, a detailed log message is produced and stored in the appropriate log file. &lt;br /&gt;
&lt;br /&gt;
====Correcting the use of the info log level for errors====&lt;br /&gt;
In the original backend implementation, the info severity level is used almost universally, even when logging errors. For example, in the original implementation of the bookmarks controller, the &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method logs errors that occur like so: &amp;lt;code&amp;gt;ExpertizaLogger.info LoggerMessage.new(controller_name, session[:user].name, $ERROR_INFO, request)&amp;lt;/code&amp;gt;. We have replaced these with the appropriate logging level, so that errors go to one file, and info to another. This expedites the debugging process for developers, as they will know where to look to find errors vs info.&lt;br /&gt;
&lt;br /&gt;
====Standardizing error messages to avoid mixed hardcoded strings and object outputs====&lt;br /&gt;
In the original backend implementation, sometimes the content of an error object was passed into logging messages, and sometimes hardcoded strings specific to the situation were. For example, in the original implementation of the student teams controller, the &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method uses hardcoded strings specifically indicating why the request failed - &amp;lt;code&amp;gt;ExpertizaLogger.info LoggerMessage.new(controller_name, session[:user].name, 'Team name missing while creating team', request)&amp;lt;/code&amp;gt;. However, in the bookmarks controller, the error info was logged like so: &amp;lt;code&amp;gt;ExpertizaLogger.info LoggerMessage.new(controller_name, session[:user].name, $ERROR_INFO, request)&amp;lt;/code&amp;gt;. We've increased the consistency across all logging messages to include detailed, context-specific error messages, as that is more informative to developers, and have added logging messages in that style everywhere they are relevant.&lt;br /&gt;
&lt;br /&gt;
====Ensuring consistent use of &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; (e.g., defaulting to session[:user].name unless context demands otherwise)====&lt;br /&gt;
Both implementations of logging use a &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; object to standardize information produced in logs. The &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; object takes, among other things, the unity id of the logger as a parameter. However, in the old backend, that parameter is sometimes passed in from the user's session like &amp;lt;code&amp;gt;session[:user].name&amp;lt;/code&amp;gt; and sometimes passed in through other means, such as &amp;lt;code&amp;gt;@participant.name&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;requested_user.name&amp;lt;/code&amp;gt;. We have standardized these in the reimplementation such that the user's session is used everywhere possible to ensure consistency.&lt;br /&gt;
&lt;br /&gt;
==Tests Explained==&lt;br /&gt;
This section will explain the tests we've written to varying levels of specificity. Where reasonable, we've omitted tests that are repetitive to reduce redundancy - for example, we only explain the info level logging tests in &amp;lt;code&amp;gt;spec/logs/expertiza_logger_spec.rb&amp;lt;/code&amp;gt;. While we have separate tests in that file for the other severity levels, they're very similar, and do not warrant separate explanation.&lt;br /&gt;
&lt;br /&gt;
===Expertiza Log Formatter Tests===&lt;br /&gt;
The Expertiza Log Formatter is designed to ensure consistent log formatting across various logging scenarios. The tests in &amp;lt;code&amp;gt;spec/logs/expertiza_log_formatter_spec.rb&amp;lt;/code&amp;gt; are designed to check this functionality. &lt;br /&gt;
&lt;br /&gt;
Before the tests, a few helpful variables are defined as such:&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
let(:formatter) { ExpertizaLogFormatter.new }&lt;br /&gt;
let(:timestamp) { Time.now }&lt;br /&gt;
let(:severity) { 'INFO' }&lt;br /&gt;
let(:progname) { 'Expertiza' }&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The first two tests, included below, check that the log formatter can format messages correctly. The first test invokes the &amp;lt;code&amp;gt;call&amp;lt;/code&amp;gt; method on the formatter with info level severity, the current time as timestamp, 'Expertiza' as the program name, and a simple string as the message parameter. Given these simple parameters, we can easily check that the produced message, returned by the &amp;lt;code&amp;gt;call&amp;lt;/code&amp;gt; method, matches our expectations. The second test is very similar, but checks that a message with a newline produces a log without one. The &amp;lt;code&amp;gt;ExpertizaLogFormatter&amp;lt;/code&amp;gt; is designed to take all newlines and replace them with space characters, so that log files aren't unnecessarily messy.&lt;br /&gt;
 &lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when the message is a plain string' do&lt;br /&gt;
    let(:message) { 'Test message with more text' }&lt;br /&gt;
    it 'formats the message correctly' do&lt;br /&gt;
      formatted_message = formatter.call(severity, timestamp, progname, message)&lt;br /&gt;
      expect(formatted_message).to include(&amp;quot;TST=[#{timestamp}] SVT=[#{severity}] PNM=[#{progname}] OIP=[] RID=[] CTR=[] UID=[] MSG=[Test message with more text]&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
context 'when the message is a plain string with newline' do&lt;br /&gt;
    let(:message) { &amp;quot;Test message with newline\nto more text&amp;quot; }&lt;br /&gt;
    it 'formats the message correctly' do&lt;br /&gt;
      formatted_message = formatter.call(severity, timestamp, progname, message)&lt;br /&gt;
      expect(formatted_message).to include(&amp;quot;TST=[#{timestamp}] SVT=[#{severity}] PNM=[#{progname}] OIP=[] RID=[] CTR=[] UID=[] MSG=[Test message with newline to more text]&amp;quot;)&lt;br /&gt;
    end&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
The final two tests similarly check formatting, except instead of passing in a simple string, they instead pass in a &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; object. &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; is a class designed to hold more complex information than just a simple message. &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; objects can hold a reference to a 'generator' (typically the name of the controller the log comes from), the unity id of the generating user, a string message, and a request (made up of a remote ip address and a unique identifier/uuid). The first test here uses a &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; without a request, and ensures the resulting log contains the information from that object. The second test uses a &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; that does contain a request, and ensures the formatting and data integrity of the created log message similarly.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
context 'when the message is a LoggerMessage object' do&lt;br /&gt;
  let(:logger_message) do&lt;br /&gt;
    LoggerMessage.new('gen1', 'unityid1', 'Test message')&lt;br /&gt;
  end&lt;br /&gt;
  it 'formats the message correctly' do&lt;br /&gt;
    formatted_message = formatter.call(severity, timestamp, progname, logger_message)&lt;br /&gt;
    expect(formatted_message).to include(&amp;quot;TST=[#{timestamp}] SVT=[#{severity}] PNM=[#{progname}] OIP=[] RID=[] CTR=[gen1] UID=[unityid1] MSG=[Test message]&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
context 'when the message is a LoggerMessage object with request' do&lt;br /&gt;
  let(:logger_message) do&lt;br /&gt;
    LoggerMessage.new('gen1', 'unityid1', 'Test message', double(&amp;quot;request&amp;quot;, remote_ip: &amp;quot;192.168.1.1&amp;quot;, uuid: &amp;quot;12345&amp;quot;))&lt;br /&gt;
  end&lt;br /&gt;
  it 'formats the message correctly' do&lt;br /&gt;
    formatted_message = formatter.call(severity, timestamp, progname, logger_message)&lt;br /&gt;
    expect(formatted_message).to include(&amp;quot;TST=[#{timestamp}] SVT=[#{severity}] PNM=[#{progname}] OIP=[192.168.1.1] RID=[12345] CTR=[gen1] UID=[unityid1] MSG=[Test message]&amp;quot;)&lt;br /&gt;
  end&lt;br /&gt;
end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==References==&lt;br /&gt;
&lt;br /&gt;
#[https://github.com/expertiza/expertiza Expertiza on GitHub]&lt;br /&gt;
#[https://github.com/expertiza/reimplementation-front-end Reimplemented Frontend Github Project]&lt;br /&gt;
#[https://github.com/expertiza/reimplementation-back-end Reimplemented Backend GitHub Project]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end Reimplemented Backend GitHub Project Repository Fork]&lt;br /&gt;
#[http://expertiza.ncsu.edu/ The live Expertiza website]&lt;br /&gt;
#[https://drive.google.com/file/d/1JnMWG1d7P_yLQ_un_R7kMbTrBk5YoA87/view?usp=share_link Project demo link] &lt;br /&gt;
#[https://wiki.expertiza.ncsu.edu/index.php?title=Main_Page Expertiza project documentation wiki]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end/commit/aa84e46135d4f660c6a981f5d032cdf2a4b2f25e Initial logging commit]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end/commit/1e0ee7a0d7f6e6d48e9a82753ee0fa0afdf8440f Reimplement Expertiza Logger]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end/commit/ceee53b4d9ed4281ac2f0201873a40b90bceb039 Adding logging to ApplicationRecord]&lt;/div&gt;</summary>
		<author><name>Cshimes</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2024_-_E2471._Reimplement_logger&amp;diff=159782</id>
		<title>CSC/ECE 517 Fall 2024 - E2471. Reimplement logger</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2024_-_E2471._Reimplement_logger&amp;diff=159782"/>
		<updated>2024-11-26T14:19:55Z</updated>

		<summary type="html">&lt;p&gt;Cshimes: /* Final Design Document */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==E2471. Reimplement logger==&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===About Expertiza===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create new assignments and customize new or existing assignments. It also allows the instructor to create a list of topics the students can sign up for. Students can form teams in Expertiza to work on various projects and assignments. Students can also peer review other students' submissions. Expertiza supports submission across various document types, including the URLs and wiki pages. As the project has progressed, there has developed a need to reimplement the project using different frameworks. Our project specifically assists in this goal as it implements a logger for the [https://github.com/expertiza/reimplementation-back-end reimplemented backend]. This new backend utilizes Rails API to create a RESTful API that can be accessed by frontend implementations. The latest [https://github.com/expertiza/reimplementation-front-end frontend reimplementation] has used Typescript and React to create the UI. &lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The following tasks have been accomplished as part of this project:&lt;br /&gt;
&lt;br /&gt;
* Created an ExpertizaLogger to customize logging behavior in the new backend.&lt;br /&gt;
* Created special formats for the logging that is being performed to include the desired information. &lt;br /&gt;
* Created info, warn, error, fatal, and debug logging levels.&lt;br /&gt;
* Created hooks to log CRUD database transactions. &lt;br /&gt;
* Utilize hooks to automatically log all model CRUD operations. &lt;br /&gt;
&lt;br /&gt;
These tasks establish a uniform logging experience for all of the CRUD operations, and they provide the ability to log other specific details as desired manually. This ensures that we have a base implementation that complies with the database CRUD operation logging requirement while allowing developers to include manual logging such as error flows or other information that may be helpful for an administrator to consult. Moving forward, all ApplicationRecords will automatically log the CRUD operations, and developers can easily utilize &amp;quot;ExpertizaLogger.warn(message)&amp;quot; to log an info message, for example. &lt;br /&gt;
&lt;br /&gt;
===Implementation Details===&lt;br /&gt;
Our implementation primarily involved creating four new components: &lt;br /&gt;
&lt;br /&gt;
* Expertiza Logger class&lt;br /&gt;
* Expertiza Log Formatter class&lt;br /&gt;
* Logger Message class&lt;br /&gt;
* Logging concern&lt;br /&gt;
&lt;br /&gt;
These components are now explained in greater detail below. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===About Expertiza Logger===&lt;br /&gt;
This logger is responsible for providing the desired log levels in the Expertiza reimplemented backend. It specifically contains the info, warn, error, fatal, and debug logging levels. These logs are then stored in files named &amp;quot;expertiza_info.log&amp;quot;, &amp;quot;expertiza_warn.log&amp;quot;, etc. It utilizes the Expertiza Log Formatter, which is utilized to format all of the desired log messages.&lt;br /&gt;
&lt;br /&gt;
===About Expertiza Log Formatter===&lt;br /&gt;
This class is a log formatter to provide a uniform style that contains all of the information desired. This is a critical class, as it allows the logs to be effectively searched for the given information logged. It ensures that all logs are consistent and are also easily parsable. &lt;br /&gt;
&lt;br /&gt;
===About Logger Message===&lt;br /&gt;
This class is a simple model that provides the content for the message that is being formatted by Expertiza Logger. It includes such values as the Unity ID, a message, remote IP address, etc. This information is utilized when formatting the logs to ensure that this consistent information is presented and available for inspection without requiring additional developer effort. It makes it easy to modify the logger format because the information will remain consistent, while the Expertiza Log Formatter can adjust the output format easily for all subsequent logs without modifying log commands spread throughout the project. &lt;br /&gt;
&lt;br /&gt;
===About Logging Concern===&lt;br /&gt;
This concern was created as an easy way to ensure that critical events are logged by default in the application. In particular, our goal was to log the database CRUD events. This concern sets up the hooks necessary to call the log methods required to log these events. By including this concern in any model, it will automatically perform the desired CRUD logging. We have leveraged this combined with the model hierarchy of classes depending on ApplicationRecord to ensure logging compliance. That is, we have included the logging concern in ApplicationRecord, allowing any class that inherits from ApplicationRecord to benefit from the automatic logging configuration. This ensures that this architecture is sustainable in the future by ensuring that the desired CRUD operations will be logged without requiring additional developer configuration.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Testing from UI===&lt;br /&gt;
It is not possible to test and observe this behavior from the UI. This is intentional because users should not be able to access any of the runtime information that is being logged. This information could include users' personal information, etc. that only an admin should be able to inspect. These log files are created and are able to be inspected by an IT administrator, but should not be available for user inspection. &lt;br /&gt;
&lt;br /&gt;
If, however, the admin would like to test the implementation, they can interact with the backend using the frontend, Postman, etc. The actions they perform are logged and can then be inspected in the recorded logs.&lt;br /&gt;
&lt;br /&gt;
For example, here are a few test cases with respect to our code changes that can be tried:&lt;br /&gt;
1. Log in to the webpage. Inspecting the logs should show that the user's account information was retrieved from the database. &lt;br /&gt;
&lt;br /&gt;
2. Create a new assignment. Inspecting the logs will demonstrate that the desired information is persisted to the database. &lt;br /&gt;
&lt;br /&gt;
3. Edit the created assignment. Inspecting the logs will demonstrate that the newly updated information is persisted to the database. &lt;br /&gt;
&lt;br /&gt;
4. Delete the assignment. Inspecting the logs will reveal that the assignment was deleted.&lt;br /&gt;
&lt;br /&gt;
==Final Design Document==&lt;br /&gt;
&lt;br /&gt;
===Proposed Changes===&lt;br /&gt;
From observing the current state of the logging implementation, which includes most functionality from the original Expertiza, we have improved the logging for better observability into the system. To that end, we have implemented the following changes:&lt;br /&gt;
&lt;br /&gt;
====Writing more comprehensive automated tests and improving coverage====&lt;br /&gt;
We have written and executed automated tests to cover a range of logging scenarios. Tests on the CRUD operations of models now ensure the functionality of info-level logging. We've also added tests that check for logging at the other severity levels (warning, error, etc). These tests are stored as files in the &amp;lt;code&amp;gt;spec/logs&amp;lt;/code&amp;gt; directory. One example of a testing method is this one, which we've recently written:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RSpec.describe Api::V1::UsersController, type: :controller do&lt;br /&gt;
  let(:user) { build(:user, name: &amp;quot;Jane&amp;quot;, email: &amp;quot;jdoe@ncsu.edu&amp;quot;, full_name: &amp;quot;Jane Doe&amp;quot;) }&lt;br /&gt;
  let(:params) do { user: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Jane Doe&amp;quot;,&lt;br /&gt;
        &amp;quot;full_name&amp;quot;: &amp;quot;Jane Doe&amp;quot;,&lt;br /&gt;
        &amp;quot;email&amp;quot;: &amp;quot;jane.doe@example.com&amp;quot;,&lt;br /&gt;
        &amp;quot;role_id&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;institution_id&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;password&amp;quot;: &amp;quot;password&amp;quot;,&lt;br /&gt;
        &amp;quot;password_confirmation&amp;quot;: &amp;quot;password&amp;quot;   } }&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it &amp;quot;logs when user is created&amp;quot; do&lt;br /&gt;
    allow(Rails.logger).to receive(:info)&lt;br /&gt;
    expect(Rails.logger).to receive(:info)&lt;br /&gt;
&lt;br /&gt;
    post :create, params: params&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Enhancing error logging by capturing new cases====&lt;br /&gt;
Some functionality has changed between the old implementation and the reimplementation of the backend. For example, the reimplementation has different ways of performing error checking in some of the controller methods than the original implementation had. For these cases and others, we added logging to ensure that when a controller method fails, a detailed log message is produced and stored in the appropriate log file. &lt;br /&gt;
&lt;br /&gt;
====Correcting the use of the info log level for errors====&lt;br /&gt;
In the original backend implementation, the info severity level is used almost universally, even when logging errors. For example, in the original implementation of the bookmarks controller, the &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method logs errors that occur like so: &amp;lt;code&amp;gt;ExpertizaLogger.info LoggerMessage.new(controller_name, session[:user].name, $ERROR_INFO, request)&amp;lt;/code&amp;gt;. We have replaced these with the appropriate logging level, so that errors go to one file, and info to another. This expedites the debugging process for developers, as they will know where to look to find errors vs info.&lt;br /&gt;
&lt;br /&gt;
====Standardizing error messages to avoid mixed hardcoded strings and object outputs====&lt;br /&gt;
In the original backend implementation, sometimes the content of an error object was passed into logging messages, and sometimes hardcoded strings specific to the situation were. For example, in the original implementation of the student teams controller, the &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method uses hardcoded strings specifically indicating why the request failed - &amp;lt;code&amp;gt;ExpertizaLogger.info LoggerMessage.new(controller_name, session[:user].name, 'Team name missing while creating team', request)&amp;lt;/code&amp;gt;. However, in the bookmarks controller, the error info was logged like so: &amp;lt;code&amp;gt;ExpertizaLogger.info LoggerMessage.new(controller_name, session[:user].name, $ERROR_INFO, request)&amp;lt;/code&amp;gt;. We've increased the consistency across all logging messages to include detailed, context-specific error messages, as that is more informative to developers, and have added logging messages in that style everywhere they are relevant.&lt;br /&gt;
&lt;br /&gt;
====Ensuring consistent use of &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; (e.g., defaulting to session[:user].name unless context demands otherwise)====&lt;br /&gt;
Both implementations of logging use a &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; object to standardize information produced in logs. The &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; object takes, among other things, the unity id of the logger as a parameter. However, in the old backend, that parameter is sometimes passed in from the user's session like &amp;lt;code&amp;gt;session[:user].name&amp;lt;/code&amp;gt; and sometimes passed in through other means, such as &amp;lt;code&amp;gt;@participant.name&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;requested_user.name&amp;lt;/code&amp;gt;. We have standardized these in the reimplementation such that the user's session is used everywhere possible to ensure consistency.&lt;br /&gt;
&lt;br /&gt;
===References===&lt;br /&gt;
&lt;br /&gt;
#[https://github.com/expertiza/expertiza Expertiza on GitHub]&lt;br /&gt;
#[https://github.com/expertiza/reimplementation-front-end Reimplemented Frontend Github Project]&lt;br /&gt;
#[https://github.com/expertiza/reimplementation-back-end Reimplemented Backend GitHub Project]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end Reimplemented Backend GitHub Project Repository Fork]&lt;br /&gt;
#[http://expertiza.ncsu.edu/ The live Expertiza website]&lt;br /&gt;
#[https://drive.google.com/file/d/1JnMWG1d7P_yLQ_un_R7kMbTrBk5YoA87/view?usp=share_link Project demo link] &lt;br /&gt;
#[https://wiki.expertiza.ncsu.edu/index.php?title=Main_Page Expertiza project documentation wiki]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end/commit/aa84e46135d4f660c6a981f5d032cdf2a4b2f25e Initial logging commit]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end/commit/1e0ee7a0d7f6e6d48e9a82753ee0fa0afdf8440f Reimplement Expertiza Logger]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end/commit/ceee53b4d9ed4281ac2f0201873a40b90bceb039 Adding logging to ApplicationRecord]&lt;/div&gt;</summary>
		<author><name>Cshimes</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2024_-_E2471._Reimplement_logger&amp;diff=159781</id>
		<title>CSC/ECE 517 Fall 2024 - E2471. Reimplement logger</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2024_-_E2471._Reimplement_logger&amp;diff=159781"/>
		<updated>2024-11-26T14:09:50Z</updated>

		<summary type="html">&lt;p&gt;Cshimes: /* Final Design Document */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==E2471. Reimplement logger==&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===About Expertiza===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create new assignments and customize new or existing assignments. It also allows the instructor to create a list of topics the students can sign up for. Students can form teams in Expertiza to work on various projects and assignments. Students can also peer review other students' submissions. Expertiza supports submission across various document types, including the URLs and wiki pages. As the project has progressed, there has developed a need to reimplement the project using different frameworks. Our project specifically assists in this goal as it implements a logger for the [https://github.com/expertiza/reimplementation-back-end reimplemented backend]. This new backend utilizes Rails API to create a RESTful API that can be accessed by frontend implementations. The latest [https://github.com/expertiza/reimplementation-front-end frontend reimplementation] has used Typescript and React to create the UI. &lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The following tasks have been accomplished as part of this project:&lt;br /&gt;
&lt;br /&gt;
* Created an ExpertizaLogger to customize logging behavior in the new backend.&lt;br /&gt;
* Created special formats for the logging that is being performed to include the desired information. &lt;br /&gt;
* Created info, warn, error, fatal, and debug logging levels.&lt;br /&gt;
* Created hooks to log CRUD database transactions. &lt;br /&gt;
* Utilize hooks to automatically log all model CRUD operations. &lt;br /&gt;
&lt;br /&gt;
These tasks establish a uniform logging experience for all of the CRUD operations, and they provide the ability to log other specific details as desired manually. This ensures that we have a base implementation that complies with the database CRUD operation logging requirement while allowing developers to include manual logging such as error flows or other information that may be helpful for an administrator to consult. Moving forward, all ApplicationRecords will automatically log the CRUD operations, and developers can easily utilize &amp;quot;ExpertizaLogger.warn(message)&amp;quot; to log an info message, for example. &lt;br /&gt;
&lt;br /&gt;
===Implementation Details===&lt;br /&gt;
Our implementation primarily involved creating four new components: &lt;br /&gt;
&lt;br /&gt;
* Expertiza Logger class&lt;br /&gt;
* Expertiza Log Formatter class&lt;br /&gt;
* Logger Message class&lt;br /&gt;
* Logging concern&lt;br /&gt;
&lt;br /&gt;
These components are now explained in greater detail below. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===About Expertiza Logger===&lt;br /&gt;
This logger is responsible for providing the desired log levels in the Expertiza reimplemented backend. It specifically contains the info, warn, error, fatal, and debug logging levels. These logs are then stored in files named &amp;quot;expertiza_info.log&amp;quot;, &amp;quot;expertiza_warn.log&amp;quot;, etc. It utilizes the Expertiza Log Formatter, which is utilized to format all of the desired log messages.&lt;br /&gt;
&lt;br /&gt;
===About Expertiza Log Formatter===&lt;br /&gt;
This class is a log formatter to provide a uniform style that contains all of the information desired. This is a critical class, as it allows the logs to be effectively searched for the given information logged. It ensures that all logs are consistent and are also easily parsable. &lt;br /&gt;
&lt;br /&gt;
===About Logger Message===&lt;br /&gt;
This class is a simple model that provides the content for the message that is being formatted by Expertiza Logger. It includes such values as the Unity ID, a message, remote IP address, etc. This information is utilized when formatting the logs to ensure that this consistent information is presented and available for inspection without requiring additional developer effort. It makes it easy to modify the logger format because the information will remain consistent, while the Expertiza Log Formatter can adjust the output format easily for all subsequent logs without modifying log commands spread throughout the project. &lt;br /&gt;
&lt;br /&gt;
===About Logging Concern===&lt;br /&gt;
This concern was created as an easy way to ensure that critical events are logged by default in the application. In particular, our goal was to log the database CRUD events. This concern sets up the hooks necessary to call the log methods required to log these events. By including this concern in any model, it will automatically perform the desired CRUD logging. We have leveraged this combined with the model hierarchy of classes depending on ApplicationRecord to ensure logging compliance. That is, we have included the logging concern in ApplicationRecord, allowing any class that inherits from ApplicationRecord to benefit from the automatic logging configuration. This ensures that this architecture is sustainable in the future by ensuring that the desired CRUD operations will be logged without requiring additional developer configuration.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Testing from UI===&lt;br /&gt;
It is not possible to test and observe this behavior from the UI. This is intentional because users should not be able to access any of the runtime information that is being logged. This information could include users' personal information, etc. that only an admin should be able to inspect. These log files are created and are able to be inspected by an IT administrator, but should not be available for user inspection. &lt;br /&gt;
&lt;br /&gt;
If, however, the admin would like to test the implementation, they can interact with the backend using the frontend, Postman, etc. The actions they perform are logged and can then be inspected in the recorded logs.&lt;br /&gt;
&lt;br /&gt;
For example, here are a few test cases with respect to our code changes that can be tried:&lt;br /&gt;
1. Log in to the webpage. Inspecting the logs should show that the user's account information was retrieved from the database. &lt;br /&gt;
&lt;br /&gt;
2. Create a new assignment. Inspecting the logs will demonstrate that the desired information is persisted to the database. &lt;br /&gt;
&lt;br /&gt;
3. Edit the created assignment. Inspecting the logs will demonstrate that the newly updated information is persisted to the database. &lt;br /&gt;
&lt;br /&gt;
4. Delete the assignment. Inspecting the logs will reveal that the assignment was deleted.&lt;br /&gt;
&lt;br /&gt;
==Final Design Document==&lt;br /&gt;
&lt;br /&gt;
===Proposed Changes===&lt;br /&gt;
From observing the current state of the logging implementation, which includes most functionality from the original Expertiza, we believe we can improve the logging for better observability into the system. To that end, we propose the following changes:&lt;br /&gt;
&lt;br /&gt;
====Writing more comprehensive automated tests and improving coverage====&lt;br /&gt;
We've already created some basic automated tests and gotten them to run, but we want to add more to cover more cases. For example, we currently have some tests on the CRUD operations of models to test info-level logging. We'll add tests that check for logging at the other severity levels (warning, error, etc) as well. This will touch files in the &amp;lt;code&amp;gt;spec/logs&amp;lt;/code&amp;gt; directory. One example of a testing method is this one, which we've recently written:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RSpec.describe Api::V1::UsersController, type: :controller do&lt;br /&gt;
  let(:user) { build(:user, name: &amp;quot;Jane&amp;quot;, email: &amp;quot;jdoe@ncsu.edu&amp;quot;, full_name: &amp;quot;Jane Doe&amp;quot;) }&lt;br /&gt;
  let(:params) do { user: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Jane Doe&amp;quot;,&lt;br /&gt;
        &amp;quot;full_name&amp;quot;: &amp;quot;Jane Doe&amp;quot;,&lt;br /&gt;
        &amp;quot;email&amp;quot;: &amp;quot;jane.doe@example.com&amp;quot;,&lt;br /&gt;
        &amp;quot;role_id&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;institution_id&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;password&amp;quot;: &amp;quot;password&amp;quot;,&lt;br /&gt;
        &amp;quot;password_confirmation&amp;quot;: &amp;quot;password&amp;quot;   } }&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it &amp;quot;logs when user is created&amp;quot; do&lt;br /&gt;
    allow(Rails.logger).to receive(:info)&lt;br /&gt;
    expect(Rails.logger).to receive(:info)&lt;br /&gt;
&lt;br /&gt;
    post :create, params: params&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Enhancing error logging by capturing new cases====&lt;br /&gt;
Some functionality has changed between the old implementation and the reimplementation of the backend. For example, the reimplementation has different ways of performing error checking in some of the controller methods than the original implementation had. For these cases and others, we will add logging to ensure that when a controller method fails, a detailed log message is produced and stored in the appropriate log file. &lt;br /&gt;
&lt;br /&gt;
====Correcting the use of the info log level for errors====&lt;br /&gt;
In the original backend implementation, the info severity level is used almost universally, even when logging errors. For example, in the original implementation of the bookmarks controller, the &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method logs errors that occur like so: &amp;lt;code&amp;gt;ExpertizaLogger.info LoggerMessage.new(controller_name, session[:user].name, $ERROR_INFO, request)&amp;lt;/code&amp;gt;. Our intention is to replace these with the appropriate logging level, so that errors go to one file, and info to another. This will expedite the debugging process for developers, as they will know where to look to find errors vs info.&lt;br /&gt;
&lt;br /&gt;
====Standardizing error messages to avoid mixed hardcoded strings and object outputs====&lt;br /&gt;
In the original backend implementation, sometimes the content of an error object was passed into logging messages, and sometimes hardcoded strings specific to the situation were. For example, in the original implementation of the student teams controller, the &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method uses hardcoded strings specifically indicating why the request failed - &amp;lt;code&amp;gt;ExpertizaLogger.info LoggerMessage.new(controller_name, session[:user].name, 'Team name missing while creating team', request)&amp;lt;/code&amp;gt;. However, in the bookmarks controller, the error info was logged like so: &amp;lt;code&amp;gt;ExpertizaLogger.info LoggerMessage.new(controller_name, session[:user].name, $ERROR_INFO, request)&amp;lt;/code&amp;gt;. We aim for consistency across all logging messages, and will therefore choose one of two routes, whichever is more informative to developers, and add logging messages for that everywhere.&lt;br /&gt;
&lt;br /&gt;
====Ensuring consistent use of &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; (e.g., defaulting to session[:user].name unless context demands otherwise)====&lt;br /&gt;
Both implementations of logging use a &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; object to standardize information produced in logs. The &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; object takes, among other things, the unity id of the logger as a parameter. However, that parameter is sometimes passed in from the user's session like &amp;lt;code&amp;gt;session[:user].name&amp;lt;/code&amp;gt; and sometimes passed in through other means, such as &amp;lt;code&amp;gt;@participant.name&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;requested_user.name&amp;lt;/code&amp;gt;. We aim to analyze these use cases and, where possible, standardize them in the reimplementation. We believe the user's session should be used everywhere if possible to ensure consistency.&lt;br /&gt;
&lt;br /&gt;
===References===&lt;br /&gt;
&lt;br /&gt;
#[https://github.com/expertiza/expertiza Expertiza on GitHub]&lt;br /&gt;
#[https://github.com/expertiza/reimplementation-front-end Reimplemented Frontend Github Project]&lt;br /&gt;
#[https://github.com/expertiza/reimplementation-back-end Reimplemented Backend GitHub Project]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end Reimplemented Backend GitHub Project Repository Fork]&lt;br /&gt;
#[http://expertiza.ncsu.edu/ The live Expertiza website]&lt;br /&gt;
#[https://drive.google.com/file/d/1JnMWG1d7P_yLQ_un_R7kMbTrBk5YoA87/view?usp=share_link Project demo link] &lt;br /&gt;
#[https://wiki.expertiza.ncsu.edu/index.php?title=Main_Page Expertiza project documentation wiki]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end/commit/aa84e46135d4f660c6a981f5d032cdf2a4b2f25e Initial logging commit]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end/commit/1e0ee7a0d7f6e6d48e9a82753ee0fa0afdf8440f Reimplement Expertiza Logger]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end/commit/ceee53b4d9ed4281ac2f0201873a40b90bceb039 Adding logging to ApplicationRecord]&lt;/div&gt;</summary>
		<author><name>Cshimes</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2024_-_E2471._Reimplement_logger&amp;diff=159780</id>
		<title>CSC/ECE 517 Fall 2024 - E2471. Reimplement logger</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2024_-_E2471._Reimplement_logger&amp;diff=159780"/>
		<updated>2024-11-25T20:19:11Z</updated>

		<summary type="html">&lt;p&gt;Cshimes: /* E2471. Reimplement logger */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==E2471. Reimplement logger==&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===About Expertiza===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create new assignments and customize new or existing assignments. It also allows the instructor to create a list of topics the students can sign up for. Students can form teams in Expertiza to work on various projects and assignments. Students can also peer review other students' submissions. Expertiza supports submission across various document types, including the URLs and wiki pages. As the project has progressed, there has developed a need to reimplement the project using different frameworks. Our project specifically assists in this goal as it implements a logger for the [https://github.com/expertiza/reimplementation-back-end reimplemented backend]. This new backend utilizes Rails API to create a RESTful API that can be accessed by frontend implementations. The latest [https://github.com/expertiza/reimplementation-front-end frontend reimplementation] has used Typescript and React to create the UI. &lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The following tasks have been accomplished as part of this project:&lt;br /&gt;
&lt;br /&gt;
* Created an ExpertizaLogger to customize logging behavior in the new backend.&lt;br /&gt;
* Created special formats for the logging that is being performed to include the desired information. &lt;br /&gt;
* Created info, warn, error, fatal, and debug logging levels.&lt;br /&gt;
* Created hooks to log CRUD database transactions. &lt;br /&gt;
* Utilize hooks to automatically log all model CRUD operations. &lt;br /&gt;
&lt;br /&gt;
These tasks establish a uniform logging experience for all of the CRUD operations, and they provide the ability to log other specific details as desired manually. This ensures that we have a base implementation that complies with the database CRUD operation logging requirement while allowing developers to include manual logging such as error flows or other information that may be helpful for an administrator to consult. Moving forward, all ApplicationRecords will automatically log the CRUD operations, and developers can easily utilize &amp;quot;ExpertizaLogger.warn(message)&amp;quot; to log an info message, for example. &lt;br /&gt;
&lt;br /&gt;
===Implementation Details===&lt;br /&gt;
Our implementation primarily involved creating four new components: &lt;br /&gt;
&lt;br /&gt;
* Expertiza Logger class&lt;br /&gt;
* Expertiza Log Formatter class&lt;br /&gt;
* Logger Message class&lt;br /&gt;
* Logging concern&lt;br /&gt;
&lt;br /&gt;
These components are now explained in greater detail below. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===About Expertiza Logger===&lt;br /&gt;
This logger is responsible for providing the desired log levels in the Expertiza reimplemented backend. It specifically contains the info, warn, error, fatal, and debug logging levels. These logs are then stored in files named &amp;quot;expertiza_info.log&amp;quot;, &amp;quot;expertiza_warn.log&amp;quot;, etc. It utilizes the Expertiza Log Formatter, which is utilized to format all of the desired log messages.&lt;br /&gt;
&lt;br /&gt;
===About Expertiza Log Formatter===&lt;br /&gt;
This class is a log formatter to provide a uniform style that contains all of the information desired. This is a critical class, as it allows the logs to be effectively searched for the given information logged. It ensures that all logs are consistent and are also easily parsable. &lt;br /&gt;
&lt;br /&gt;
===About Logger Message===&lt;br /&gt;
This class is a simple model that provides the content for the message that is being formatted by Expertiza Logger. It includes such values as the Unity ID, a message, remote IP address, etc. This information is utilized when formatting the logs to ensure that this consistent information is presented and available for inspection without requiring additional developer effort. It makes it easy to modify the logger format because the information will remain consistent, while the Expertiza Log Formatter can adjust the output format easily for all subsequent logs without modifying log commands spread throughout the project. &lt;br /&gt;
&lt;br /&gt;
===About Logging Concern===&lt;br /&gt;
This concern was created as an easy way to ensure that critical events are logged by default in the application. In particular, our goal was to log the database CRUD events. This concern sets up the hooks necessary to call the log methods required to log these events. By including this concern in any model, it will automatically perform the desired CRUD logging. We have leveraged this combined with the model hierarchy of classes depending on ApplicationRecord to ensure logging compliance. That is, we have included the logging concern in ApplicationRecord, allowing any class that inherits from ApplicationRecord to benefit from the automatic logging configuration. This ensures that this architecture is sustainable in the future by ensuring that the desired CRUD operations will be logged without requiring additional developer configuration.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Testing from UI===&lt;br /&gt;
It is not possible to test and observe this behavior from the UI. This is intentional because users should not be able to access any of the runtime information that is being logged. This information could include users' personal information, etc. that only an admin should be able to inspect. These log files are created and are able to be inspected by an IT administrator, but should not be available for user inspection. &lt;br /&gt;
&lt;br /&gt;
If, however, the admin would like to test the implementation, they can interact with the backend using the frontend, Postman, etc. The actions they perform are logged and can then be inspected in the recorded logs.&lt;br /&gt;
&lt;br /&gt;
For example, here are a few test cases with respect to our code changes that can be tried:&lt;br /&gt;
1. Log in to the webpage. Inspecting the logs should show that the user's account information was retrieved from the database. &lt;br /&gt;
&lt;br /&gt;
2. Create a new assignment. Inspecting the logs will demonstrate that the desired information is persisted to the database. &lt;br /&gt;
&lt;br /&gt;
3. Edit the created assignment. Inspecting the logs will demonstrate that the newly updated information is persisted to the database. &lt;br /&gt;
&lt;br /&gt;
4. Delete the assignment. Inspecting the logs will reveal that the assignment was deleted.&lt;br /&gt;
&lt;br /&gt;
==Final Design Document==&lt;br /&gt;
&lt;br /&gt;
===Proposed Changes===&lt;br /&gt;
From observing the current state of the logging implementation, which includes most functionality from the original Expertiza, we believe we can improve the logging for better observability into the system. To that end, we propose the following changes:&lt;br /&gt;
&lt;br /&gt;
====Writing more comprehensive automated tests and improving coverage====&lt;br /&gt;
We've already created some basic automated tests and gotten them to run, but we want to add more to cover more cases. For example, we currently have some tests on the CRUD operations of models to test info-level logging. We'll add tests that check for logging at the other severity levels (warning, error, etc) as well. This will touch files in the &amp;lt;code&amp;gt;spec/logs&amp;lt;/code&amp;gt; directory. One example of a testing method is this one, which we've recently written:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RSpec.describe Api::V1::UsersController, type: :controller do&lt;br /&gt;
  let(:user) { build(:user, name: &amp;quot;Jane&amp;quot;, email: &amp;quot;jdoe@ncsu.edu&amp;quot;, full_name: &amp;quot;Jane Doe&amp;quot;) }&lt;br /&gt;
  let(:params) do { user: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Jane Doe&amp;quot;,&lt;br /&gt;
        &amp;quot;full_name&amp;quot;: &amp;quot;Jane Doe&amp;quot;,&lt;br /&gt;
        &amp;quot;email&amp;quot;: &amp;quot;jane.doe@example.com&amp;quot;,&lt;br /&gt;
        &amp;quot;role_id&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;institution_id&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;password&amp;quot;: &amp;quot;password&amp;quot;,&lt;br /&gt;
        &amp;quot;password_confirmation&amp;quot;: &amp;quot;password&amp;quot;   } }&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it &amp;quot;logs when user is created&amp;quot; do&lt;br /&gt;
    allow(Rails.logger).to receive(:info)&lt;br /&gt;
    expect(Rails.logger).to receive(:info)&lt;br /&gt;
&lt;br /&gt;
    post :create, params: params&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Enhancing error logging by capturing new cases====&lt;br /&gt;
Some functionality has changed between the old implementation and the reimplementation of the backend. For example, the reimplementation has different ways of performing error checking in some of the controller methods than the original implementation had. For these cases and others, we will add logging to ensure that when a controller method fails, a detailed log message is produced and stored in the appropriate log file. &lt;br /&gt;
&lt;br /&gt;
====Correcting the use of the info log level for errors====&lt;br /&gt;
In the original backend implementation, the info severity level is used almost universally, even when logging errors. For example, in the original implementation of the bookmarks controller, the &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method logs errors that occur like so: &amp;lt;code&amp;gt;ExpertizaLogger.info LoggerMessage.new(controller_name, session[:user].name, $ERROR_INFO, request)&amp;lt;/code&amp;gt;. Our intention is to replace these with the appropriate logging level, so that errors go to one file, and info to another. This will expedite the debugging process for developers, as they will know where to look to find errors vs info.&lt;br /&gt;
&lt;br /&gt;
====Standardizing error messages to avoid mixed hardcoded strings and object outputs====&lt;br /&gt;
In the original backend implementation, sometimes the content of an error object was passed into logging messages, and sometimes hardcoded strings specific to the situation were. For example, in the original implementation of the student teams controller, the &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method uses hardcoded strings specifically indicating why the request failed - &amp;lt;code&amp;gt;ExpertizaLogger.info LoggerMessage.new(controller_name, session[:user].name, 'Team name missing while creating team', request)&amp;lt;/code&amp;gt;. However, in the bookmarks controller, the error info was logged like so: &amp;lt;code&amp;gt;ExpertizaLogger.info LoggerMessage.new(controller_name, session[:user].name, $ERROR_INFO, request)&amp;lt;/code&amp;gt;. We aim for consistency across all logging messages, and will therefore choose one of two routes, whichever is more informative to developers, and add logging messages for that everywhere.&lt;br /&gt;
&lt;br /&gt;
====Ensuring consistent use of &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; (e.g., defaulting to session[:user].name unless context demands otherwise)====&lt;br /&gt;
Both implementations of logging use a &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; object to standardize information produced in logs. The &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; object takes, among other things, the unity id of the logger as a parameter. However, that parameter is sometimes passed in from the user's session like &amp;lt;code&amp;gt;session[:user].name&amp;lt;/code&amp;gt; and sometimes passed in through other means, such as &amp;lt;code&amp;gt;@participant.name&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;requested_user.name&amp;lt;/code&amp;gt;. We aim to analyze these use cases and, where possible, standardize them in the reimplementation. We believe the user's session should be used everywhere if possible to ensure consistency.&lt;br /&gt;
&lt;br /&gt;
===Plan of Work===&lt;br /&gt;
We plan to approach the work in the following order:&lt;br /&gt;
&lt;br /&gt;
====Comb through every controller and model file, and each method within those files====&lt;br /&gt;
Add logging where relevant for creation, destruction, etc. Add logging for errors. For those files and methods which exist, but are unimplemented, we will develop a boilerplate statement to add to them, pointing future developers to references so they understand how best to add logging when they do implement the code.&lt;br /&gt;
&lt;br /&gt;
====Standardize log severity levels across the application====&lt;br /&gt;
Review current log levels used in the reimplementation to ensure that appropriate severity levels (info, warning, error, etc.) are applied based on the context. For instance, success messages should use info level, whereas failures or issues in expected behavior should use warning or error levels as appropriate.&lt;br /&gt;
&lt;br /&gt;
====Refactor existing logging to use &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; consistently====&lt;br /&gt;
Identify instances where the unity id parameter of &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; is passed in inconsistently. We will refactor the code to ensure that &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; is applied uniformly across the application, defaulting to &amp;lt;code&amp;gt;session[:user].name&amp;lt;/code&amp;gt; for the unity ID unless context requires another source.&lt;br /&gt;
&lt;br /&gt;
====Implement automated tests for all logging behavior====&lt;br /&gt;
We will create comprehensive automated tests for each logging action to verify that logs are generated as expected and with the correct severity level. Tests will cover different CRUD actions, error handling scenarios, and edge cases. We will likely place these tests in the spec/logs directory.&lt;br /&gt;
&lt;br /&gt;
====Document the logging strategy and guidelines for future developers====&lt;br /&gt;
In this wiki, add a section detailing the logging strategy, including the severity levels used, when to apply specific log levels, and examples of correctly formatted log messages. This documentation will help ensure that future contributors can easily understand and follow the logging conventions.&lt;br /&gt;
&lt;br /&gt;
====Conduct code review and team walkthrough of the logging updates====&lt;br /&gt;
Once the changes are implemented, we’ll hold a final code review to catch any inconsistencies or errors. At this point, we'll discuss and make any final adjustments. &lt;br /&gt;
&lt;br /&gt;
====Perform final testing after deploying our application to VCL or similar hosting====&lt;br /&gt;
After implementing and testing the updates locally, we’ll deploy the app, with its frontend, and conduct end-to-end tests (e.g., doing something in the frontend and checking that the appropriate log file is updated as expected). This phase will help us identify any unforeseen issues in the logging setup and confirm that log messages are correctly output and stored.&lt;br /&gt;
&lt;br /&gt;
===References===&lt;br /&gt;
&lt;br /&gt;
#[https://github.com/expertiza/expertiza Expertiza on GitHub]&lt;br /&gt;
#[https://github.com/expertiza/reimplementation-front-end Reimplemented Frontend Github Project]&lt;br /&gt;
#[https://github.com/expertiza/reimplementation-back-end Reimplemented Backend GitHub Project]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end Reimplemented Backend GitHub Project Repository Fork]&lt;br /&gt;
#[http://expertiza.ncsu.edu/ The live Expertiza website]&lt;br /&gt;
#[https://drive.google.com/file/d/1JnMWG1d7P_yLQ_un_R7kMbTrBk5YoA87/view?usp=share_link Project demo link] &lt;br /&gt;
#[https://wiki.expertiza.ncsu.edu/index.php?title=Main_Page Expertiza project documentation wiki]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end/commit/aa84e46135d4f660c6a981f5d032cdf2a4b2f25e Initial logging commit]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end/commit/1e0ee7a0d7f6e6d48e9a82753ee0fa0afdf8440f Reimplement Expertiza Logger]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end/commit/ceee53b4d9ed4281ac2f0201873a40b90bceb039 Adding logging to ApplicationRecord]&lt;/div&gt;</summary>
		<author><name>Cshimes</name></author>
	</entry>
	<entry>
		<id>https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2024_-_E2471._Reimplement_logger&amp;diff=158837</id>
		<title>CSC/ECE 517 Fall 2024 - E2471. Reimplement logger</title>
		<link rel="alternate" type="text/html" href="https://wiki.expertiza.ncsu.edu/index.php?title=CSC/ECE_517_Fall_2024_-_E2471._Reimplement_logger&amp;diff=158837"/>
		<updated>2024-11-11T14:58:56Z</updated>

		<summary type="html">&lt;p&gt;Cshimes: /* E2471. Reimplement logger */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;==E2471. Reimplement logger==&lt;br /&gt;
&lt;br /&gt;
This page provides a description of the Expertiza based OSS project. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
__TOC__&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===About Expertiza===&lt;br /&gt;
&lt;br /&gt;
[http://expertiza.ncsu.edu/ Expertiza] is an open source project based on [http://rubyonrails.org/ Ruby on Rails] framework. Expertiza allows the instructor to create new assignments and customize new or existing assignments. It also allows the instructor to create a list of topics the students can sign up for. Students can form teams in Expertiza to work on various projects and assignments. Students can also peer review other students' submissions. Expertiza supports submission across various document types, including the URLs and wiki pages. As the project has progressed, there has developed a need to reimplement the project using different frameworks. Our project specifically assists in this goal as it implements a logger for the [https://github.com/expertiza/reimplementation-back-end reimplemented backend]. This new backend utilizes Rails API to create a RESTful API that can be accessed by frontend implementations. The latest [https://github.com/expertiza/reimplementation-front-end frontend reimplementation] has used Typescript and React to create the UI. &lt;br /&gt;
&lt;br /&gt;
===Problem Statement===&lt;br /&gt;
The following tasks were accomplished in this project:&lt;br /&gt;
&lt;br /&gt;
* Created an ExpertizaLogger to customize logging behavior in the new backend.&lt;br /&gt;
* Created special formats for the logging that is being performed to include the desired information. &lt;br /&gt;
* Created info, warn, error, fatal, and debug logging levels.&lt;br /&gt;
* Created hooks to log CRUD database transactions. &lt;br /&gt;
* Utilize hooks to automatically log all model CRUD operations. &lt;br /&gt;
&lt;br /&gt;
These tasks establish a uniform logging experience for all of the CRUD operations, and they provide the ability to log other specific details as desired manually. This ensures that we have a base implementation that complies with the database CRUD operation logging requirement while allowing developers to include manual logging such as error flows or other information that may be helpful for an administrator to consult. Moving forward, all ApplicationRecords will automatically log the CRUD operations, and developers can easily utilize &amp;quot;ExpertizaLogger.warn(message)&amp;quot; to log an info message, for example. &lt;br /&gt;
&lt;br /&gt;
===Implementation Details===&lt;br /&gt;
Our implementation primarily involved creating four new components: &lt;br /&gt;
&lt;br /&gt;
* Expertiza Logger class&lt;br /&gt;
* Expertiza Log Formatter class&lt;br /&gt;
* Logger Message class&lt;br /&gt;
* Logging concern&lt;br /&gt;
&lt;br /&gt;
These components are now explained in greater detail below. &lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===About Expertiza Logger===&lt;br /&gt;
This logger is responsible for providing the desired log levels in the Expertize reimplemented backend. It specifically contains the info, warn, error, fatal, and debug logging levels. These logs are then stored in files named &amp;quot;expertiza_info.log&amp;quot;, &amp;quot;expertiza_warn.log&amp;quot;, etc. It utilizes the Expertiza Log Formatter, which is utilized to format all of the desired log messages. &lt;br /&gt;
&lt;br /&gt;
===About Expertiza Log Formatter===&lt;br /&gt;
This class is a log formatter to provide a uniform style that contains all of the information desired. This is a critical class, as it allows the logs to be effectively searched for the given information logged. It ensures that all logs will be consistent and are also easily parsable. &lt;br /&gt;
&lt;br /&gt;
===About Logger Message===&lt;br /&gt;
This class is a simple model intended to provide the content for the message that is being formatted by Expertiza Logger. It includes such values as the Unity ID, a message, remote IP address, etc. This information can then be utilized when formatting the logs to ensure that this consistent information is presented and available for inspection without requiring additional developer effort. It allows any desired updates to the logger format to be easily modified because the information will remain consistent, while the Expertiza Log Formatter can adjust the output format easily for all subsequent logs without modifying log commands spread throughout the project. &lt;br /&gt;
&lt;br /&gt;
===About Logging Concern===&lt;br /&gt;
This concern was created as an easy way to ensure that critical events are logged by default in the application. In particular, our goal was to log the database CRUD events. This concern sets up the hooks necessary to call the log methods required to log these events. By including this concern in any model, it will automatically perform the desired CRUD logging. We have leveraged this combined with the model hierarchy of classes depending on ApplicationRecord to ensure logging compliance. That is, we have included the logging concern in ApplicationRecord, allowing any class that inherits from ApplicationRecord to benefit from the automatic logging configuration. This ensures that this architecture is sustainable in the future by ensuring that the desired CRUD operations will be logged without requiring additional developer configuration.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Testing from UI===&lt;br /&gt;
It is not possible to test and observe this behavior from the UI. This is intentional because users should not be able to access any of the runtime information that is being logged. This information could include users' personal information, etc. that only an admin should be able to inspect. These log files should be created and able to be inspected by an IT administrator, but it should not be available for user inspection. &lt;br /&gt;
&lt;br /&gt;
If, however, the admin would like to test the implementation, they can interact with the backend using the frontend, Postman, etc. The actions they perform should be logged and can then be inspected in the recorded logs.&lt;br /&gt;
&lt;br /&gt;
For example, here are a few test cases with respect to our code changes that can be tried:&lt;br /&gt;
1. Log in to the webpage. Inspecting the logs should show that the user's account information was retrieved from the database. &lt;br /&gt;
&lt;br /&gt;
2. Create a new assignment. Inspecting the logs will demonstrate that the desired information is persisted to the database. &lt;br /&gt;
&lt;br /&gt;
3. Edit the created assignment. Inspecting the logs will demonstrate that the newly updated information is persisted to the database. &lt;br /&gt;
&lt;br /&gt;
4. Delete the assignment. Inspecting the logs will reveal that the assignment was deleted. &lt;br /&gt;
&lt;br /&gt;
==Final Design Document==&lt;br /&gt;
&lt;br /&gt;
===Proposed Changes===&lt;br /&gt;
From observing the current state of the logging implementation, which includes most functionality from the original Expertiza, we believe we can improve the logging for better observability into the system. To that end, we propose the following changes:&lt;br /&gt;
&lt;br /&gt;
====Writing more comprehensive automated tests and improving coverage====&lt;br /&gt;
We've already created some basic automated tests and gotten them to run, but we want to add more to cover more cases. For example, we currently have some tests on the CRUD operations of models to test info-level logging. We'll add tests that check for logging at the other severity levels (warning, error, etc) as well. This will touch files in the &amp;lt;code&amp;gt;spec/logs&amp;lt;/code&amp;gt; directory. One example of a testing method is this one, which we've recently written:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
RSpec.describe Api::V1::UsersController, type: :controller do&lt;br /&gt;
  let(:user) { build(:user, name: &amp;quot;Jane&amp;quot;, email: &amp;quot;jdoe@ncsu.edu&amp;quot;, full_name: &amp;quot;Jane Doe&amp;quot;) }&lt;br /&gt;
  let(:params) do { user: {&lt;br /&gt;
        &amp;quot;name&amp;quot;: &amp;quot;Jane Doe&amp;quot;,&lt;br /&gt;
        &amp;quot;full_name&amp;quot;: &amp;quot;Jane Doe&amp;quot;,&lt;br /&gt;
        &amp;quot;email&amp;quot;: &amp;quot;jane.doe@example.com&amp;quot;,&lt;br /&gt;
        &amp;quot;role_id&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;institution_id&amp;quot;: 1,&lt;br /&gt;
        &amp;quot;password&amp;quot;: &amp;quot;password&amp;quot;,&lt;br /&gt;
        &amp;quot;password_confirmation&amp;quot;: &amp;quot;password&amp;quot;   } }&lt;br /&gt;
  end&lt;br /&gt;
&lt;br /&gt;
  it &amp;quot;logs when user is created&amp;quot; do&lt;br /&gt;
    allow(Rails.logger).to receive(:info)&lt;br /&gt;
    expect(Rails.logger).to receive(:info)&lt;br /&gt;
&lt;br /&gt;
    post :create, params: params&lt;br /&gt;
  end&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
====Enhancing error logging by capturing new cases====&lt;br /&gt;
Some functionality has changed between the old implementation and the reimplementation of the backend. For example, the reimplementation has different ways of performing error checking in some of the controller methods than the original implementation had. For these cases and others, we will add logging to ensure that when a controller method fails, a detailed log message is produced and stored in the appropriate log file. &lt;br /&gt;
&lt;br /&gt;
====Correcting the use of the info log level for errors====&lt;br /&gt;
In the original backend implementation, the info severity level is used almost universally, even when logging errors. For example, in the original implementation of the bookmarks controller, the &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method logs errors that occur like so: &amp;lt;code&amp;gt;ExpertizaLogger.info LoggerMessage.new(controller_name, session[:user].name, $ERROR_INFO, request)&amp;lt;/code&amp;gt;. Our intention is to replace these with the appropriate logging level, so that errors go to one file, and info to another. This will expedite the debugging process for developers, as they will know where to look to find errors vs info.&lt;br /&gt;
&lt;br /&gt;
====Standardizing error messages to avoid mixed hardcoded strings and object outputs====&lt;br /&gt;
In the original backend implementation, sometimes the content of an error object was passed into logging messages, and sometimes hardcoded strings specific to the situation were. For example, in the original implementation of the student teams controller, the &amp;lt;code&amp;gt;create&amp;lt;/code&amp;gt; method uses hardcoded strings specifically indicating why the request failed - &amp;lt;code&amp;gt;ExpertizaLogger.info LoggerMessage.new(controller_name, session[:user].name, 'Team name missing while creating team', request)&amp;lt;/code&amp;gt;. However, in the bookmarks controller, the error info was logged like so: &amp;lt;code&amp;gt;ExpertizaLogger.info LoggerMessage.new(controller_name, session[:user].name, $ERROR_INFO, request)&amp;lt;/code&amp;gt;. We aim for consistency across all logging messages, and will therefore choose one of two routes, whichever is more informative to developers, and add logging messages for that everywhere.&lt;br /&gt;
&lt;br /&gt;
====Ensuring consistent use of &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; (e.g., defaulting to session[:user].name unless context demands otherwise)====&lt;br /&gt;
Both implementations of logging use a &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; object to standardize information produced in logs. The &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; object takes, among other things, the unity id of the logger as a parameter. However, that parameter is sometimes passed in from the user's session like &amp;lt;code&amp;gt;session[:user].name&amp;lt;/code&amp;gt; and sometimes passed in through other means, such as &amp;lt;code&amp;gt;@participant.name&amp;lt;/code&amp;gt; or &amp;lt;code&amp;gt;requested_user.name&amp;lt;/code&amp;gt;. We aim to analyze these use cases and, where possible, standardize them in the reimplementation. We believe the user's session should be used everywhere if possible to ensure consistency.&lt;br /&gt;
&lt;br /&gt;
===Plan of Work===&lt;br /&gt;
We plan to approach the work in the following order:&lt;br /&gt;
&lt;br /&gt;
====Comb through every controller and model file, and each method within those files====&lt;br /&gt;
Add logging where relevant for creation, destruction, etc. Add logging for errors. For those files and methods which exist, but are unimplemented, we will develop a boilerplate statement to add to them, pointing future developers to references so they understand how best to add logging when they do implement the code.&lt;br /&gt;
&lt;br /&gt;
====Standardize log severity levels across the application====&lt;br /&gt;
Review current log levels used in the reimplementation to ensure that appropriate severity levels (info, warning, error, etc.) are applied based on the context. For instance, success messages should use info level, whereas failures or issues in expected behavior should use warning or error levels as appropriate.&lt;br /&gt;
&lt;br /&gt;
====Refactor existing logging to use &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; consistently====&lt;br /&gt;
Identify instances where the unity id parameter of &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; is passed in inconsistently. We will refactor the code to ensure that &amp;lt;code&amp;gt;LoggerMessage&amp;lt;/code&amp;gt; is applied uniformly across the application, defaulting to &amp;lt;code&amp;gt;session[:user].name&amp;lt;/code&amp;gt; for the unity ID unless context requires another source.&lt;br /&gt;
&lt;br /&gt;
====Implement automated tests for all logging behavior====&lt;br /&gt;
We will create comprehensive automated tests for each logging action to verify that logs are generated as expected and with the correct severity level. Tests will cover different CRUD actions, error handling scenarios, and edge cases. We will likely place these tests in the spec/logs directory.&lt;br /&gt;
&lt;br /&gt;
====Document the logging strategy and guidelines for future developers====&lt;br /&gt;
In this wiki, add a section detailing the logging strategy, including the severity levels used, when to apply specific log levels, and examples of correctly formatted log messages. This documentation will help ensure that future contributors can easily understand and follow the logging conventions.&lt;br /&gt;
&lt;br /&gt;
====Conduct code review and team walkthrough of the logging updates====&lt;br /&gt;
Once the changes are implemented, we’ll hold a final code review to catch any inconsistencies or errors. At this point, we'll discuss and make any final adjustments. &lt;br /&gt;
&lt;br /&gt;
====Perform final testing after deploying our application to VCL or similar hosting====&lt;br /&gt;
After implementing and testing the updates locally, we’ll deploy the app, with its frontend, and conduct end-to-end tests (e.g., doing something in the frontend and checking that the appropriate log file is updated as expected). This phase will help us identify any unforeseen issues in the logging setup and confirm that log messages are correctly output and stored.&lt;br /&gt;
&lt;br /&gt;
===References===&lt;br /&gt;
&lt;br /&gt;
#[https://github.com/expertiza/expertiza Expertiza on GitHub]&lt;br /&gt;
#[https://github.com/expertiza/reimplementation-front-end Reimplemented Frontend Github Project]&lt;br /&gt;
#[https://github.com/expertiza/reimplementation-back-end Reimplemented Backend GitHub Project]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end Reimplemented Backend GitHub Project Repository Fork]&lt;br /&gt;
#[http://expertiza.ncsu.edu/ The live Expertiza website]&lt;br /&gt;
#[https://drive.google.com/file/d/1JnMWG1d7P_yLQ_un_R7kMbTrBk5YoA87/view?usp=share_link Project demo link] &lt;br /&gt;
#[https://wiki.expertiza.ncsu.edu/index.php?title=Main_Page Expertiza project documentation wiki]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end/commit/aa84e46135d4f660c6a981f5d032cdf2a4b2f25e Initial logging commit]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end/commit/1e0ee7a0d7f6e6d48e9a82753ee0fa0afdf8440f Reimplement Expertiza Logger]&lt;br /&gt;
#[https://github.com/camhimes/reimplementation-back-end/commit/ceee53b4d9ed4281ac2f0201873a40b90bceb039 Adding logging to ApplicationRecord]&lt;/div&gt;</summary>
		<author><name>Cshimes</name></author>
	</entry>
</feed>