#! /usr/bin/env python3 """ MyLog's goal is to add functionality to the logging module making it as easy for me to use as print. Logging should be automatically used on every scrpt. The logging module is very easy to use. So, a wrapper isn't necessary. However, I don't want to relearn logging on the rare occasions when I am writing python code. I'd prefer if everyone of my logfiles looked and behaved the same and I never have to spend any time on logging. I had a way to handle logging but it wasn't pythonic and it didn't use the logging module. So, I am using logging and trying to make the module more pythonic. Turn Debug on by setting level to DEBUG Modules or Tools that must be installed for script to work: None References: Logging Cookbook: https://doc.bccnsoft.com/docs/python-3.6.8-docs-html/howto/logging-cookbook.html#logging-cookbook Logging Cookbook: https://docs.python.org/3/howto/logging-cookbook.html How To Logging: https://doc.bccnsoft.com/docs/python-3.6.8-docs-html/howto/logging.html#logging-advanced-tutorial Python Logging: https://realpython.com/python-logging-source-code/ Loggly: https://www.loggly.com/use-cases/python-syslog-how-to-set-up-and-troubleshoot/ Loguru: https://pythonrepo.com/repo/Delgan-loguru-python-generating-and-working-with-logs I found Loguru when I was almost done with my version, both have similar goals My Guidelines for pythonic code: https://sites.google.com/site/cartwrightraspberrypiprojects/home/footer/pythonic """ ############################# <- 80 Characters -> ############################## # # This style of commenting is called a garden bed and it is frowned upon by # those who know python. But, I like it. I use a garden bed at the top to track # my to do list as I work on the code, and then mark the completed To Dos. # # Within the code, To Dos include a comment with ???, which makes it easy for # me to find # # Once the To Do list is more-or-less complete, I move the completed items into # comments, docstrings or help within the code. Next, I remove the completed # items. # # To Do List: # # Do later or not at all (I am tired of working on this): # g) add arguments from multiple scripts # use: https://www.doc.ic.ac.uk/~nuric/coding/argparse-with-multiple-files-to-handle-config$ # # Won't Do: # k) are there any standard security features that can be added to logging # (e.g., don't print passwords, usernames) - It can be done, but it # requires a regexp to exclude each type of personal informaton to exclude # l) identify commands to use with arguments - this isn't really required # # Completed: # # To use logrotate, with install instructions and config rather than using # python: # https://serverfault.com/questions/352942/equivalent-of-logrotate-on-osx # ############################# <- 80 Characters -> ############################## # Built-in Python3 Modules import sys import logging import logging.handlers import argparse import os # Modules that must be installed (pip3) # My Modules (from github) # Global Veriables (FirstUpper or CapWord) # Global Constants (ALL CAPS) # Classes class MyLog: """ I want logging to be stupidly simple to use. So, I have no excuse to use print instead of logging. """ # LevelDict['INFO'] returns logging.INFO LevelDict = {"INFO": logging.INFO, "WARNING": logging.WARNING, "ERROR": logging.ERROR, "DEBUG": logging.DEBUG, "CRITICAL": logging.CRITICAL, "NOTSET": logging.NOTSET, } def __init__(self): """ MyLog() creates an object for the class, but may or may not do anything """ # instance variables self.Logger = logging.getLogger("MyLog") # pylint complains if these aren't defined in __init__ # I was using self.setProperties() # I could disable W0201, but I think this is a valuable check # insstance variables self.setLevel("INFO") # It might be reasonable to change size, filename and count to protected # variables, and only change with a setter. I left these as accessible # outside the the class to ease changing on reading in command line # arguments. # # Changes only take effect after a call to openOutput. self.Size = 500000 self.Count = 7 # change filename self.Filename = "default.log" self.consoleHandler = "" # private instance variables # these should be access using logger.varName because things need to be # set up or torn down when they change. I could have done these as # protected variables. self.__Output = "BOTHUSR" # the next two lines are the main reason for the MyLog modulet, use it # on everything! I always want log messages date and tiem stamped, which # is accomplished using asctime self.fileFormatter = logging.Formatter('%(asctime)s: [%(levelname)s] %(filename)s:%(funcName)s:%(lineno)d \"%(message)s\"') self.consoleFormatter = logging.Formatter('%(message)s') # get only the script name - actually gets the name of ths file and not the script # self.Script = __file__.rsplit("/", 1)[1].split('.')[0] f = sys.argv[0] if f.find("/") != -1: self.Script = f.rsplit("/", 1)[1].split('.')[0] else: self.Script = f.split('.')[0] # if imported as a module, then open the output using defaults if self.Script != "mylog": self.openOutput() def setProperties(self, count=7, filename="default.log", level="INFO", output="BOTHUSR", size=500000): """ Set one or all properties for MyLog: count = number of backups to keep (default = 7) filename = log file and path (depends on output setting) level = types of messages to output to log file,such as, INFO or DEBUG (default = INFO) output = send to CONSOLE, SYS file, USR file, or both BOTHUSR, BOTHSYS size = size of backup file before log rotate (default = 500000) Use openOutput if satisfied with defaults """ self.Count = count self.Filename = filename self.setLevel(level) self.Size = size self.__Output = output self.openOutput() def setOutput(self, output): """ change where logging is sent """ self.__Output = output self.openOutput() def getOutput(self): """ returns Output, mosytly for testing """ return self.__Output def openOutput(self): """ Opens the output (may be overridden by other settngs): SYS = /var/log/