The goal is to complete a Flask tutorial where it is used logging.handler.SMTPHandler to send logs to SMTP debugging server from Python.
The Python server is run under windows cli, open a new windows CLI as admin and run:
python -m smtpd -n -c DebuggingServer localhost:1025
To test it the following code should work:
import logging
import sys
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
smtpHandler = logging.handlers.SMTPHandler(
mailhost = ("localhost",8025),
fromaddr = "alerts#localhost",
toaddrs = "geo555#localhost",
subject = "alert!"
)
smtpHandler.setLevel(logging.DEBUG)
logger.debug("here is the test logging for u.")
Have tried so far and no message is appearing in the debuggingserver:
https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-vii-error-handling
Does not send any output to debugging server.
How can I send an email using python logging's SMTPHandler and SSL is not explicitly using the debugging server and it did not work.
What can be a very simple example that can do this, otherwise using debugging to file which also works.
Cheers.
I think you missed to add the stmpHandler to the logger: logger.addHandler(smtpHandler)
Below is a full working code:
import logging
import logging.handlers
import sys
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
sender = "emailuser#localhost"
pwd = "pass123"
smtpHandler = logging.handlers.SMTPHandler(
mailhost=("localhost", 25),
fromaddr="noreply#example.com",
toaddrs="user#email.com",
subject="alert!",
credentials=(sender, pwd),
)
smtpHandler.setLevel(logging.DEBUG)
# add this line
logger.addHandler(smtpHandler)
logger.debug("here is the test logging for u.")
Related
I have a simple script that I run as an exe file on Windows. However, when I am developing the script, I run it from the command line and use the logging module to output debug info to a log file. I would like to turn off the generation of the log file for my production code. How would I go about doing that?
This is the logging config I have setup now:
import logging
...
logging.basicConfig(filename='file.log',
filemode="w",
level=logging.DEBUG,
format="%(asctime)s: %(name)s - %(levelname)s - %(message)s",
datefmt='%d-%b-%y %H:%M:%S',
)
...
logging.debug("Debug message")
If you don't mind the generation of an empty log file for production, you can simply increase the threshold of logging to a level above logging.DEBUG, such as logging.INFO, so that messages logged with logging.debug won't get output to the log file:
logging.basicConfig(filename='file.log', # creates an empty file.log
filemode="w",
level=logging.INFO,
format="%(asctime)s: %(name)s - %(levelname)s - %(message)s",
datefmt='%d-%b-%y %H:%M:%S',
)
logging.debug("Debug message") # nothing would happen
logging.info("FYI") # logs 'FYI'
If you don't want logging to function at all, an easy approach is to override logging with a Mock object:
import logging
from unittest.mock import Mock
environment = 'production'
if environment == 'production':
logging = Mock()
...
logging.basicConfig(...) # nothing would happen
logging.debug(...) # nothing would happen
I've created a method that logs to my syslog server and am using 'logging.Formatter' to format the message. However, it seems that Formatter is adding additional text to my syslog message and I am unsure of how to get rid of it.
Here's the method located in logger.py:
import logging
import logging.handlers
import os
def sendLog(msg):
address = "192.168.1.200"
port = 514
syslogger = logging.getLogger("app_processing LEVEL='{}'".format(os.environ['ENV']))
syslogger.setLevel(logging.DEBUG)
# f = ContextFilter()
# syslogger.addFilter(f)
handler = logging.handlers.SysLogHandler(address=(address, port))
formatter = logging.Formatter("%(asctime)s %(name)s %(message)s", datefmt='%m/%d/%Y %H:%M:%S')
handler.setFormatter(formatter)
syslogger.addHandler(handler)
syslogger.debug(msg)
And I'm calling it from other modules with:
logger.sendLog("FUNCTION='get_inventory_db' MESSAGE='Retrieving inventory information'")
Yet, when it's logged to the server the result is:
2017-10-20 14:48:35 -04:00 192.168.1.101 192.168.1.101 user.debug 10/20/2017 18:48:35 app_processing LEVEL='development' FUNCTION='get_inventory_db' MESSAGE='Retrieving inventory information'
Note the 2017-10-20 14:48:35 -04:00 192.168.1.101 192.168.1.101 user.debug that shows before what should be the start of the syslog message.
I'm expecting output like:
10/20/2017 18:48:35 app_processing LEVEL='development' FUNCTION='get_inventory_db' MESSAGE='Retrieving inventory information'
Am I not using the Formatter correctly?
You do everything completely correct with the formatters & logging library.
The mentioned prefix has nothing to do with the python's logging library. The whole line starting with "10/20/2017 18:48:35 ………" is being sent by python to the syslog.
Whatever is added on top of that, is the syslog's configuration, and should be investigated there, on the syslog's server side. It cannot be controlled from the app and its logging.
The only way you can "fix" these lines is by removing any datetimes from your own log formats, and rely on the syslog's proper prefix.
Currently am using python logging to log messages to a log file and to console (if --verbose).
How can I configure logging to also record messages into an array/list?
Figured this out after posting.
Used a Stream to a string.
Here is snippet of the code, not including the stdout Stream and the normal logger file handle:
import io
import logging
logger = logging.getLogger()
errors = io.StringIO()
formatter = logging.Formatter('%(asctime)s - %(module)s.%(funcName)s() - %(levelname)s - %(message)s',"%Y-%m-%d %H:%M:%S")
eh = logging.StreamHandler(errors)
eh.setFormatter(formatter)
logger.addHandler(eh)
logger.error("This is a test error message")
contents=errors.getvalue()
print("error string=>{}".format(contents))
errors.close()
I am working in linux and the process rsyslogd is listening to port 514.
The following code can't write into /var/log/syslog.
Is anybody know what is the problem?
import logging
import logging.handlers
root_logger = logging.getLogger()
root_logger.setLevel(config.get_value("log_level"))
syslog_hdlr = SysLogHandler(address='/dev/log', facility=SysLogHandler.LOG_DAEMON)
syslog_hdlr.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(name)s: %(levelname)s %(message)s')
syslog_hdlr.setFormatter(formatter)
root_logger.addHandler(syslog_hdlr)
logger = logging.getLogger("imapcd.daemon")
logger.debug('test')
This code works fine in my system if I make some changes:
import logging.handlers as sh
syslog_hdlr = sh.SysLogHandler(address='/dev/log', facility=sh.SysLogHandler.LOG_DAEMON)
and
root_logger.setLevel(logging.DEBUG)
So check the logging level you are getting from config is not more restrictive than DEBUG (ex: if it is set to INFO no debug messages are printed).
If you still don't see anything on syslog try to use the syslog module and see if you get anything from there:
import syslog
syslog.syslog(syslog.LOG_ERR, "MY MESSAGE")
When I run this on my mac:
import logging.handlers
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
syslog_address = '/var/run/syslog'
logger.addHandler(logging.handlers.SysLogHandler(syslog_address))
logger.error("What the crap?")
It shows up like this in the syslog:
Oct 18 19:02:06 nick Unknown[4294967295] <Error>: What the crap?
Why is it Unknown? Shouldn't it be smart enough to name itself after the script's name?
I think the APP-NAME (which indicates the source) is an optional component in the syslog header. The latest version of SysLogHandler (for Python 3.3) includes support for an APP-NAME (called ident as per the C syslog API), but it's not available in earlier versions. See this Python issue.
If you prepend your script name to all messages, you will get the desired effect. For example,
logger.error('foo: What\'s up?')
will display e.g.
19/10/2011 13:51:17 foo[2147483647] What's up?
in the log.
To get what you need, you should add a formatter to the handler so you don't have to manually format every message yourself.
import logging.handlers
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
syslog_address = '/var/run/syslog'
handler = logging.handlers.SysLogHandler(syslog_address)
# create the formatter
formatter = logging.Formatter('%(name)s: [%(levelname)s] %(message)s')
# plug this formatter into your handler(s)
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.error("What the crap?")
You should now find that you see entries in syslog as you'd expect:
Jul 4 14:34:40 ip-127-0-0-1 script_name.py: [ERROR] What the crap?
It can be found all list which word matches what in the list you can find at this link
If you need more you can have a look further example:
from logging.handlers import SysLogHandler
import logging
def log(self, severity=logging.DEBUG, message=None):
"""
Log utility for system wide logging needs
#param severity Log severity
#param message Log message
#return
"""
logger = logging.getLogger()
logger.setLevel(severity)
syslog = SysLogHandler(address="/dev/log")
syslog.setFormatter(
logging.Formatter("%(module)s-%(processName)s[%(process)d]: %(name)s: %(message)s")
)
logger.addHandler(syslog)
logger.log(severity, message)
It is quite simple and I use this method as a global logging package in my projects.