158

I want to print the current timestamp, when an event succeeded or not in my python script. By only adding...

datetime.datetime.now().strftime("%d.%b %Y %H:%M:%S")

.... at the beginning of each line, te same date appears in every line

[INFO] 04.Feb 2015 20:49:41: cl1
[ OK ] 04.Feb 2015 20:49:41: 8.8.8.8 ONLINE!
[INFO] 04.Feb 2015 20:49:41: cl2
[ OK ] 04.Feb 2015 20:49:41: 8.8.8.8 ONLINE!
[INFO] 04.Feb 2015 20:49:41: cl3
[ OK ] 04.Feb 2015 20:49:41: 8.8.8.8 ONLINE!

(I added time.sleep(5)in between)

My next idea was to create a function, calling the current time, but i'm failing at embedding this function to the printcommand.

File rs.py

OK =   "[" + bc.OKGREEN + " OK "  + bc.ENDC + "] " + datetime.datetime.now().strftime("%d.%b %Y %H:%M:%S")
INFO = "[" + bc.OKBLUE  + "INFO"  + bc.ENDC + "] " + datetime.datetime.now().strftime("%d.%b %Y %H:%M:%S")
WARN = "[" + bc.WARN    + "WARN"  + bc.ENDC + "] " + datetime.datetime.now().strftime("%d.%b %Y %H:%M:%S")
ERR =  "[" + bc.ERR     + "FAIL"  + bc.ENDC + "] " + datetime.datetime.now().strftime("%d.%b %Y %H:%M:%S")
DEB =  "[" + bc.HEADER  + "DEBUG" + bc.ENDC + "] " + datetime.datetime.now().strftime("%d.%b %Y %H:%M:%S")

File myapp.py

import rs # importing rs.py

print rs.OK + hostname + "is up!"
time.sleep(3)
print rs.ERR+ hostname + "is down!"

Is printing:

>>> [INFO] 04.Feb 2015 20:49:41: xxx is up!
>>> [ERR ] 04.Feb 2015 20:49:41: xxx is down!
0

3 Answers 3

336

Before the first time you log anything do this:

logging.basicConfig(
    format='%(asctime)s %(levelname)-8s %(message)s',
    level=logging.INFO,
    datefmt='%Y-%m-%d %H:%M:%S')

Example on the REPL:

>>> import logging
>>> logging.basicConfig(
...         format='%(asctime)s %(levelname)-8s %(message)s',
...         level=logging.INFO,
...         datefmt='%Y-%m-%d %H:%M:%S')
>>> 
>>> logging.info('an info messge')
2017-05-25 00:58:28 INFO     an info messge
>>> logging.debug('a debug messag is not shown')
>>> 
Sign up to request clarification or add additional context in comments.

3 Comments

Documentation on how to use logging: docs.python.org/3/howto/logging.html
This modifies the root logger which can have unforseen consequences. @paidhima's answer is preferable for this reason.
81

Something like below would do:

formatter = logging.Formatter(fmt='%(asctime)s %(levelname)-8s %(message)s',
                              datefmt='%Y-%m-%d %H:%M:%S')

Have a look at the logging module for Python. You don't need to mess about with creating your own date, just let the logging module do it for you. That formatter object can be applied to a logging handler so you can just log with logger.info('This is an info message.'). No print statements required.

Here's a boilerplate procedure I use:

import logging
import sys

def setup_custom_logger(name):
    formatter = logging.Formatter(fmt='%(asctime)s %(levelname)-8s %(message)s',
                                  datefmt='%Y-%m-%d %H:%M:%S')
    handler = logging.FileHandler('log.txt', mode='w')
    handler.setFormatter(formatter)
    screen_handler = logging.StreamHandler(stream=sys.stdout)
    screen_handler.setFormatter(formatter)
    logger = logging.getLogger(name)
    logger.setLevel(logging.DEBUG)
    logger.addHandler(handler)
    logger.addHandler(screen_handler)
    return logger

>>> logger = setup_custom_logger('myapp')
>>> logger.info('This is a message!')
2015-02-04 15:07:12 INFO     This is a message!
>>> logger.error('Here is another')
2015-02-04 15:07:30 ERROR    Here is another

4 Comments

without the "datefmt', how would the formatter display the timestamp? I have a project where no date format is mentioned, I need to read logs and I see the timestamp as a 10 digit value like "0063730209" How should I read it as a real human understandable date? I have to right to edit the Logger. EPOCH convertor shows the time as a date in 1972 which is definitely an invalid and incorrect value. Any suggestions how I can read the timestamp present in my log file?
It is possible to use the modern f-strings-like style specification: logging.basicConfig(level=logging.DEBUG, style='{', datefmt='%Y-%m-%d %H:%M:%S', format='{asctime} {levelname} {filename}:{lineno}: {message}')
Thanks @HansGinzel for the idea of using that syntax... Wasn't aware of style='{' as a valid parameter. It looks odd at first :) And you included {filename}:{lineno}: which is a nice touch
Hey @paidhima, can I check with you, if it want to append that print statement to my log.txt in the same format how do I do that?
3

The datetime is calculated when the string is formed. So in your case, only once at the initialisation. Instead, you should do something like this:

def ok(hostname=None, status=None):
    output = (
        "[" + bc.OKGREEN + " OK "  + bc.ENDC + "] " +
        datetime.datetime.now().strftime("%d.%b %Y %H:%M:%S")
    )
    if hostname is not None:
        output += ' ' + hostname
    if status is not None:
        output += ' ' + status
    print output

To log, just do use ok() which will reevaluate the datetime each time.

Note that @paidhima suggestion is also good.

2 Comments

Can i print this function besides a text output like print ok() + Started! or do i have to edit the function so that ok("Started!") prints [ OK ] 2015-03-02 ... Started!?
@HerrAusragend I updated my answer to match your needs. Putting everything in the function that prints into the log is a good idea if you want to keep all the logging logic into one function. If not, the function could return a string instead of printing and then you can do whatever you want with the string.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.