clog - logging as simple as putting on a shoe.
Go to file
Ethan Smith-Coss 4334be6cb7
Update 'README.md'
Added logo to README file

Signed-off-by: Ethan Smith-Coss <ethan.sc@closedless.xyz>
2022-05-13 16:14:41 +01:00
assets Added logos to assets 2022-05-13 16:12:36 +01:00
clog Updated _logger.py 2022-05-12 14:03:28 +01:00
testing Added pytest testing module 2022-05-12 13:49:32 +01:00
.coveragerc Added .coveragerc 2022-05-12 13:48:52 +01:00
.gitignore Updated .gitignore 2022-05-12 13:45:07 +01:00
conftest.py Added conftest.py for pytest 2022-05-12 13:46:11 +01:00
LICENCE.txt Update 'LICENCE.txt' 2022-05-12 23:04:42 +01:00
pyproject.toml Updated pyproject.toml 2022-05-04 21:24:28 +01:00
README.md Update 'README.md' 2022-05-13 16:14:41 +01:00
requirements-dev.txt Added requirements-dev.txt 2022-05-04 00:18:43 +01:00
setup.cfg Updated setup.cfg 2022-05-12 13:43:55 +01:00
setup.py Updated automation build scripts 2022-05-04 21:24:47 +01:00
tox.ini Updated automation build scripts 2022-05-04 21:24:47 +01:00

clog logo

CLog ClosedLess Logger

Logging as simple as putting on a shoe.

What is CLog?

Clog (stylised as 'CLog') is a basic Python logging module which builds on top of the built-in print function to provide richer outputs for general information and debugging, to a display console, or in-depth output written to a dedicated file.

Logging should be simple, and effective. That's why Clog is designed to do what it does best, as simply and effectively for developers, without adding an abundance of features. Logging can be performed simply by invoking pseudolog methods with a message to be written out to a file (and written to console using the .withConsole() method), or as advanced as calling the printLog method with additional parameters found in the built-in print function.

It can be difficult to identify what text is debug information, warnings or errors, from the remaining output. With this, Clog implements terminal highlighting depending on the level which logging information is written at. Any level which is identified as DEBUG or higher, is also written to the STDERR pipe.

"CLog" officially stands for, 'ClosedLess Logger'. But it may be colloqually known as some of the following:

  • Cohesive Logging.
  • Console Logging, and more.
  • 'Clog' (noun) - a shoe with a thick wooden sole.

How Does it Work?

As described, Clog merely acts as a wrapper over the built-in print function and does not use system-level standard PIPE write operations directly. With this, Clog exposes all keyword optional parameters of the print function, so output can be modified respectfully to the print function.

Clog is a Singleton+Factory pattern class. This means that once the class has been constructed by a user, another instance invoked will simply return the defined, currently existing instance. Using a Singleton pattern allows for the integrity of a class' state. Something like the defined logging output file cannot ever be changed after the instance is initially constructed. This in turn means that every instance created for the logging system will never be out-of-sync from any other instance created. It is a Factory pattern since the class' state can be modified and returned from an invoked method.

The core wrapper responsible for invoking the print function with specified optional parameters, is a private helper method called __printLog__ of the Logger class. All other methods defined in the class, in some way, call this helper wrapper method.

Given a TextIOWrapper object (or of similar with the SupportsWrite type), a print function can write directly to that object when passed as the file= parameter. This introduces the printLog2File method, which is similar to the printLog method; however, printLog2File is appropriate for handling strings as pathspecs, in addition to TextIOWrapper objects.

It may come to reason to allow for printLog to handle this ability as well, which would make printLog2File redundant. Well, printLog2File has a lot of dedicated functionality specifically for writing to a file, which would otherwise make printLog bulky and confusing. For example, printLog2File allows for timestamped messages, simple stacktraces to identify what method invoked a log call, and to ensure that ANSI escape codes (used for terminal highlighting) are not written to file, and a lot more.

The use of pseudolog methods can make logging very simple and short, but with the ability to not only write to file, but also to the console, lazily. A pseudolog (or, Logger pseudonyms) method is a type of Logger method which implies a defined level of logging. There are three pseudologs: debug, warn, and error. Each of these methods are decorated with the classmethod decorator to allow for the defined Singleton instance to be modified and return itself after being invoked. From this, the .withConsole() method may be invoked directly after calling a pseudolog, or later if the returned instance from the pseudolog is stored. This is why pseudologs are considered lazy since the call to write to console can be performed later as the information is stored by the class' state.

But be careful! Pseudologs invoked with .withConsole() will write the last-most message written to the file, to the console, meaning if another pseudolog is invoked, the class state is changed, and the previous message stored will be lost.

How to Use CLog

Clog is very simple to use in any project you wish to start making use of logging systems within your code base. Simply import the package, or bring the Logger class into scope directly.

import clog

logger = Logger()
logger.printLog("Hello, Word!")
# NOTE: 'printLog' is a static method of 'Logger'

or

import clog
# or: from clog import Logger

clog.Logger.printLog("Hello, World!")
# or Logger.printLog(...) if brought into scope

Logging based on success of code

The following is an example whereby similar behaviour can be found using the built-in print(..., end="") to prevent a newline character from being printed. The following printLog call afterwards will print the message and a newline character. This allows for acknowledgement of a process about to perform a given task, with a success statement attached to the end of the line.

import os
import sys
import clog

logger = Logger(out_f="my_log_file.txt") # custom file path
my_file = "some_important_file.txt"

logger.printLog("Checking if file exists...", end="")
logger.printLog2File(f"Ensuring that file is present: {my_file}")

if not os.path.exists(my_file):
	logger.printLog2File("File could not be found in the current",
		"working directory. Exiting (1)...")
	logger.printLog("failed.")
	sys.exit(1)

logger.printLog("ok.")
logger.printLog2File("File was successfully found.")

Logging with pseudologs

Sometimes it's conventient to write one message, and have it logged both to a file, and the terminal. By using a pseudolog method, logging is guaranteed to be written to file, and optionally the same message can be sent to the terminal with highlighting and identical formatting using the .withConsole() method.

import clog

# pseudologs require accessing an instance
logger = Logger()

logger.debug("Checking integrity of operations...").withConsole()
if 1 + 1 == 2:
	logger.debug("Mathematics is not broken.").withConsole()
else:
	logger.error("Mathematics is broken!!").withConsole()

Why Use CLog and not Another Library

It's difficult to justify a dependence into your project, especially when you can either perform that dependence yourself, or use a different method to solve the problem. However, here are some reasons to consider using Clog yourself:

  • CLog provides you with the basic logging tools out of the box.
  • Additional features, such as control over logging elevation and colouring of text.
  • CLog uses built-in functions and no external dependences (ex. testing/dev).
  • There is guarantee over where information is logged to, and correctly.
  • It's simple and effective to use (well documented).
  • Guarantees backwards compatibility to version 3.6 and sooner.
  • CLog is completely open-source under the GNU GPLv3 or later. You can inspect the code base at will, and completely integrate the code base into your project (with respect to the defined licence agreement).

Comparison Between clog and logging

You might be wondering which is better: using a library that makes your code dependent on the maintanence and upkeep of an external library; or, using a built-in library that comes with the installation. Well it depends on the use-case and preferences, but here are some overviews between both libraries:

  • logging is built-in, whereas clog is a dependency.
  • logging provides the ability to have multiple logging instances. clog is a Singleton pattern, which can be re-instantiated if desired.
  • logging has basic and advanced features depending on how much you want to get out of a logging utility. clog just works as its intended.
  • Basic output from logging is simple, but ugly. clog provides a clear indication of log elevation using terminal hightlighting, as well as conforming to defined standards, such as ISO 8601 timestamps in log files out-of-the-box.
  • logging requires configuration to get more advanced behaviour. clog provides majority of this behaviour without configuration, and further configuration can be performed when logging.
  • logging provides "handlers" for separate stream and file outputs. clog handles this under-the-hood, but allows for changing between stream and file pipes where applicable. clog can also do both at the same time if desired.
  • Tracebacks can be essential to debugging problems, and both libraries provide a traceback. logging provides this functionality during an exception being raised. clog provides a basic traceback with every messaged written to a log file (unless disabled on write), stating where the call was made to log.
  • logging provides handlers to write to more than just streams and files. It can write to sockets, emails, OS event systems, and more. clog only handles stream and file writes; however, if print() can write to it, so can clog.

These are just some key comparisons between both libraries, and whether or not each point is advantageous for one library or the other depends on the developer's use-case it does not mean one is objectively better than the other. Which library is used depends on the use-case, but both could be used.

Licence

This project is licensed under the GNU GPLv3 or later licence agreement, which hereby states that this software does not come with warranty or liability.

For more, please consult the LICENCE.txt file.

Author

Ethan Smith-Coss (ethan.sc@closedless.xyz)

Copyright (C) 2022-23