{ "cells": [ { "cell_type": "raw", "metadata": { "raw_mimetype": "text/restructuredtext" }, "source": [ ".. _introduction:\n", "\n", "|\n", "|\n", "\n", "Download This Notebook: :download:`Introduction.ipynb`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Introduction\n", "\n", "This tutorial is intended to provide a brief overview to the core functionality of pylogfile, quickly covering the main concepts behind the package." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Making a LogPile\n", "\n", "First we'll import pylogfile and create a new `LogPile` object. This is the class used to represent a collection of `LogEntry`s, each of which represent a single log message. " ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "from pylogfile.base import *\n", "\n", "log = LogPile()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we can make some entries in the log." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[33m[\u001b[90mDEBUG\u001b[33m]\u001b[37m\u001b[49m This is a debug message. \u001b[90m| 2024-09-14 13:14:29.699969\u001b[0m\u001b[0m\n", "\u001b[33m[\u001b[91mERROR\u001b[33m]\u001b[37m\u001b[49m This is an error message. \u001b[90m| 2024-09-14 13:14:29.699969\u001b[0m\u001b[0m\n", "\u001b[33m[\u001b[32mINFO\u001b[33m]\u001b[37m\u001b[49m This is a log message. \u001b[90m| 2024-09-14 13:14:29.699969\u001b[0m\n", "\t \u001b[90mThis is where we can add a ton ofextra details. This is hidden by default, but still saved with the logs.You can also set details to be shown by default using the code below:\u001b[0m\n" ] } ], "source": [ "# By calling lowdebug(), debug(), info(), warning(), error(), critcal() we can\n", "# make logs at different levels. \n", "log.info(\"This is an info message.\")\n", "log.error(\"This is an error message.\")\n", "\n", "# Sometimes you want to include additional info, but might not want it to \n", "# clutter up the standard output. By including this as the `detail` string, we\n", "# can later choose if we want to display or hide these verbose detail strings.\n", "log.info(\"This is a log message.\", detail=f\"This is where we can add a ton of\"\\\n", "\t\"extra details. This is hidden by default, but still saved with the logs.\"\\\n", "\t\"You can also set details to be shown by default using the code below:\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Configuring the Output Format\n", "\n", "We can change various aspects of how `LogPile` handles new logs. First, lets see\n", "how to configure it to print details to the standard output." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[33m[\u001b[32mINFO\u001b[33m]\u001b[37m\u001b[49m We just set `show_detail` to `True`. \u001b[90m| 2024-09-14 13:16:48.398201\u001b[0m\n", "\t \u001b[90mThis is the detail string.\u001b[0m\n" ] } ], "source": [ "# Tell LogPile to display detail strings\n", "log.str_format.show_detail = True\n", "log.info(\"We just set `show_detail` to `True`.\", detail=\"This is the detail string.\")\n", "\n", "#TODO: We can also add an example modifying the colors and showing markdown" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also change what colors are printed for the various components of logs. These color formatting rules can be adjusted by log level, making it easier to see what types of log messages are coming it at a glance. This is done by modifing the attributes inside a `LogFormat` class.\n", "\n", "Lets change the main color from white to something a little easier to read on, like blue." ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[33m[\u001b[32mINFO\u001b[33m]\u001b[34m The messages should now print in blue! \u001b[90m| 2024-09-14 13:31:04.141281\u001b[0m\u001b[0m\n" ] } ], "source": [ "log.str_format.default_color['main'] = Fore.BLUE\n", "\n", "log.info(\"The messages should now print in blue!\")\n", "\n", "# Let's reset it back to white\n", "log.str_format.default_color['main'] = Fore.WHITE" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also turn off color all together if desired" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[INFO] The messages will now be colorless | 2024-09-14 13:31:01.654739\u001b[0m\u001b[0m\n" ] } ], "source": [ "log.str_format.use_color = False\n", "\n", "log.info(\"The messages will now be colorless\")\n", "\n", "# Let's turn color back on \n", "log.str_format.use_color = True" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Pylogfile Markdown\n", "\n", "Pylogfile uses a unique flavor of markdown to enable quick color changes to be applied in log messages. This is done by wrapping the phase whose color you want to change in `>` and `<`. Doing so will change the color to `bold`, one of five colors (`main`, `bold`, `quiet`, `alt`, and `label`) defined in pylogfile's `LogFormat` class." ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[33m[\u001b[32mINFO\u001b[33m]\u001b[37m Let's demonstrate \u001b[94mbold\u001b[37m text. \u001b[90m| 2024-09-14 13:43:12.190188\u001b[0m\u001b[0m\n", "\u001b[33m[\u001b[32mINFO\u001b[33m]\u001b[37m Pi = \u001b[94m3.1415926535\u001b[37m. \u001b[90m| 2024-09-14 13:43:12.191155\u001b[0m\u001b[0m\n" ] } ], "source": [ "log.info(f\"Let's demonstrate >bold< text.\")\n", "\n", "# This gets really handy when emphasizing data in a log!\n", "pi = 3.1415926535\n", "log.info(f\"Pi = >{pi}<.\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can change to any other color using `>:n` where 'n' is an 'n'-code, as listed below:\n", "\t\n", "\t- `1` or `m`: Main\n", "\t- `2` or `b`: Bold\n", "\t- `3` or `q`: Quiet\n", "\t- `4` or `a`: Alt\n", "\t- `5` or `l`: Label\n", "\n", "For example, `>:q` would switch the color to `quiet`." ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[33m[\u001b[32mINFO\u001b[33m]\u001b[37m Text type \u001b[94mbold\u001b[37m. Can also use \u001b[94mbold\u001b[37m. \u001b[90m| 2024-09-14 13:34:42.265260\u001b[0m\u001b[0m\n", "\u001b[33m[\u001b[32mINFO\u001b[33m]\u001b[37m Text type \u001b[90mquiet\u001b[37m. Can also use \u001b[90mquiet\u001b[37m. \u001b[90m| 2024-09-14 13:34:42.267012\u001b[0m\u001b[0m\n", "\u001b[33m[\u001b[32mINFO\u001b[33m]\u001b[37m Text type \u001b[33malt\u001b[37m. Can also use \u001b[33malt\u001b[37m. \u001b[90m| 2024-09-14 13:34:42.267012\u001b[0m\u001b[0m\n", "\u001b[33m[\u001b[32mINFO\u001b[33m]\u001b[37m Text type \u001b[32mlabel\u001b[37m. Can also use \u001b[32mlabel\u001b[37m. \u001b[90m| 2024-09-14 13:34:42.267012\u001b[0m\u001b[0m\n" ] } ], "source": [ "log.info(f\"Text type >:bbold<. Can also use >:2bold<.\")\n", "log.info(f\"Text type >:qquiet<. Can also use >:3quiet<.\")\n", "log.info(f\"Text type >:aalt<. Can also use >:4alt<.\")\n", "log.info(f\"Text type >:llabel<. Can also use >:5label<.\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The text color can also be permanently changed, meaning `<` will not revert back to the standard color, `main`, and will instead revert back to whatever color you change to. Making a permanent change is done by using `>>`." ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[33m[\u001b[32mINFO\u001b[33m]\u001b[37m Permanently change to \u001b[90m quiet \u001b[37m Show main \u001b[90m Now \u001b[94mbold\u001b[90m and back to quiet. \u001b[90m| 2024-09-14 13:40:22.715705\u001b[0m\u001b[0m\n", "\u001b[33m[\u001b[32mINFO\u001b[33m]\u001b[37m New log resets back to main. \u001b[90m| 2024-09-14 13:40:22.717597\u001b[0m\u001b[0m\n" ] } ], "source": [ "\n", "log.info(\"Permanently change to >>:q quiet >:1 Show main < Now >bold< and back to quiet.\")\n", "log.info(\"New log resets back to main.\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you want to type '>' without changing colors, escape it with a backslash like so:" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[33m[\u001b[32mINFO\u001b[33m]\u001b[37m Backslash escapes color change sequences. >no color change< \u001b[90m| 2024-09-14 13:36:11.020682\u001b[0m\u001b[0m\n", "\u001b[33m[\u001b[32mINFO\u001b[33m]\u001b[37m >>:3no color change< \u001b[90m| 2024-09-14 13:36:11.020682\u001b[0m\u001b[0m\n" ] } ], "source": [ "log.info(f\"Backslash escapes color change sequences. \\\\>no color change\\\\<\")\n", "log.info(f\"\\\\>\\\\>:3no color change\\\\<\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Logging Levels\n", "\n", "Pylogfile defines six logging levels by defualt, `LOWDEBUG`, `DEBUG`, `INFO`, `WARNING`, `ERROR`, and `CRITICAL`, listed in ascending order. Only logs above a set level will be printed to the standard output (although all logs, regardless of level, are stored in the `LogPile` object). Notice below that only logs above the set logging level are displayed. This level in `INFO` by default." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[33m[\u001b[90mDEBUG\u001b[33m]\u001b[37m\u001b[49m This is a debug message \u001b[90m| 2024-09-14 13:20:08.672204\u001b[0m\u001b[0m\n", "\u001b[33m[\u001b[32mINFO\u001b[33m]\u001b[37m\u001b[49m This is an info message \u001b[90m| 2024-09-14 13:20:08.673997\u001b[0m\u001b[0m\n", "\u001b[33m[\u001b[33mWARNING\u001b[33m]\u001b[37m\u001b[49m This is a warning message \u001b[90m| 2024-09-14 13:20:08.673997\u001b[0m\u001b[0m\n", "\u001b[33m[\u001b[91mERROR\u001b[33m]\u001b[37m\u001b[49m This is a error message \u001b[90m| 2024-09-14 13:20:08.673997\u001b[0m\u001b[0m\n", "\u001b[33m[\u001b[31mCRITICAL\u001b[33m]\u001b[37m\u001b[49m This is a critical message \u001b[90m| 2024-09-14 13:20:08.673997\u001b[0m\u001b[0m\n" ] } ], "source": [ "# Tell LogPile to display detail strings\n", "log.lowdebug(\"This is a lowdebug message\")\n", "log.debug(\"This is a debug message\")\n", "log.info(\"This is an info message\")\n", "log.warning(\"This is a warning message\")\n", "log.error(\"This is a error message\")\n", "log.critical(\"This is a critical message\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can change this using `set_terminal_level()`. Lets change it to `DEBUG`." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\u001b[33m[\u001b[90mDEBUG\u001b[33m]\u001b[37m\u001b[49m Changing terminal level to DEBUG. \u001b[90m| 2024-09-14 13:21:38.489549\u001b[0m\u001b[0m\n" ] } ], "source": [ "# Change the terminal display level to DEBUG\n", "log.set_terminal_level(\"DEBUG\")\n", "\n", "log.debug(\"Changing terminal level to DEBUG.\")\n", "log.lowdebug(\"So lowdebug messages still will not be displayed.\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## How it Works\n", "\n", "Lets look at the inside of a `LogEntry` to see why pylogfile is so handy.\n", "\n", "* `LogEntry.level` : This is an integer describing the logging level\n", "* `LogEntry.message` : Primary log message\n", "* `LogEntry.detail` : Secondary log message, intended to allow additional verbose information to be added and displayed only if needed.\n", "* `LogEntry.timestamp` : datetime object automatically created when the `LogEntry` was made." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Saving to Disk\n", "\n", "Once we're done logging, we can save the log as a JSON or HDF file. The key advantage of using these formats rather than simply saving a text file, is that they preserve the attributes of the `LogEntry` objects. This enables the log file to be quickly read and sorted, searched or filtered later on. Furthermore, HDF is a binary format, making the log file much smaller on disk." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "# Save the log to an HDF file. HDF is an awesome binary format that has lots of advantages\n", "# compared to JSON. For most user's we'd recommend saving your logs as HDF files.\n", "log.save_hdf(\"example.log.hdf\")\n", "\n", "# If you want to keep your logs in plain text, you can save to JSON files without losing\n", "# the object structure of the LogEntries. It'll just be larger on disk and slower to \n", "# read and write than HDF.\n", "log.save_json(\"example.log.json\")\n", "\n", "\n", "# If you're really a masochist you could save it as a .txt too :)" ] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.10.4" } }, "nbformat": 4, "nbformat_minor": 1 }