Updated README.md
Completed a README file containing a description of what the project is and how it works. Along with examples on how to use the library, reasons to use the project, and how it compares to built-in libraries.
This commit is contained in:
parent
f22e6ea554
commit
8ca27b5f81
206
README.md
206
README.md
|
|
@ -0,0 +1,206 @@
|
|||
# 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.
|
||||
|
||||
```py
|
||||
import clog
|
||||
|
||||
logger = Logger()
|
||||
logger.printLog("Hello, Word!")
|
||||
# NOTE: 'printLog' is a static method of 'Logger'
|
||||
```
|
||||
or
|
||||
```py
|
||||
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.
|
||||
|
||||
```py
|
||||
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.
|
||||
|
||||
```py
|
||||
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
|
||||
Loading…
Reference in New Issue
Block a user