How to do logging in python in an explicit file - python

I tried below code only to find that my logs are getting printed in console.
What mistake I am doing here?
import logging
logging.basicConfig(filename="logger.log",
format='%(asctime)s %(message)s',
filemode='w')
logger=logging.getLogger()
logger.setLevel(logging.INFO)
logger.info("An information")
I am running this code as a fastapi project via uvicorn server.

Pass the log level to run method
uvicorn.run("example:app", host='localhost', port=8000, reload=True, log_level='info')
Use logger
from uvicorn.config import logger
logger.info('Your Comment')

Related

Prevent Generation of Log File with Python logging

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

how to import packages and some custom setting professionally in python?

I'm using logging packages with some custom setting and I have multiple directory, sub-directory and file So I'm coping and pasting logging setting in every file, this seems unprofessional. like
I'm doing in every file:
import logging
logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s',
level=logging.INFO,datefmt='%Y-%m-%d %H:%M:%S')
I want to put this in thing like utils.py file So I only import function from utils and start work.
What I try to do, file-name: utils.py
def logger():
import logging
logging.basicConfig(format='%(asctime)s %(levelname)s %(message)s',
level=logging.INFO,
datefmt='%Y-%m-%d %H:%M:%S')
Importing in some other file and seem it's not working,file-name: database_service.py
from src.utils import logger as logging
def connection_creator():
try:
client = MongoClient(DB_MACHINE, DB_PORT, serverSelectionTimeoutMS=2000)
status = client.server_info()['ok']
logging.info(f'Connection created Successfully! ["Status":{status}] `localhost` Port: `27017`')
db_connection = client['techexpert']
return db_connection
except Exception as error:
logging.error(f'in Creating connection `localhost` Port: `27017`! {error}')
db_connection = connection_creator()
Here logging.info() in unresolved reference So what could be best professional way to import these type of settings.

Logging in Python WSGI application with Passenger not working

I'm trying to get the Python logging facility working without success, despite googling and reading the docs. This is a WSGI Python app inside Passenger on a Dreamhost shared server. The Paste middleware is working to provide info on 500 errors. There are no python errors when this code is run.
My sanitized code (passenger_wsgi.py):
#!/usr/bin/python
import os
import sys
import logging
cwd = os.getcwd()
sys.path.insert(0,cwd)
sys.path.append(cwd)
from paste.exceptions.errormiddleware import ErrorMiddleware
# configure the logging
logfilename = os.path.join('<path>/passenger_wsgi.log')
logging.basicConfig(filename=logfilename, level=logging.DEBUG, filemode='a+', format='%(asctime)s %(levelname)s %(message)s')
logging.info("Running %s", sys.executable)
log = file('<path>/passenger_wsgi_2.log', 'a')
print >>log, "Running %s" % (sys.executable)
log.flush()
application = ''
def application(environ, start_response):
results = ''
logging.info("Application called:")
logging.info("environ: %s", str(environ))
print >>log, "Application called:"
log.flush()
status = '200 OK'
results = 'Hello World! Running Python version ' + sys.version + '\n\n'
response_headers = [('Content-type', 'text/plain'),
('Content-Length', str(len(results)))]
# to test paste's error catching prowess, uncomment the following line
#raise("error")
start_response(status, response_headers)
return results
# load the application within Paste's error middleware
application = ErrorMiddleware(application, debug=True)
The print >>log statements work as expected, both when run from the command line and when run in response to an http request. The first logging.info statement works when run from the command line (of course the other logging.info statements never get hit from the command line). However, when run in response to an HTTP request, none of the logging.info statements work.
When I say 'work' here, I mean 'writes the statements to the log file'. I'd much rather use the logging facility than the print statements, if it can be made to work.
Thanks in advance for helping me understand and solve this issue.
Answering for posterity because I recently hit the same issue.
It looks like the default logger doesn't work inside the dreamhost passenger environment. I got it to work with this (snipped from https://gist.github.com/jhamrick/044c3607979eea2123ae):
import logging
from logging.handlers import RotatingFileHandler
logfilename = os.path.join(os.environ['HOME'], 'logs', 'passenger_wsgi.log')
logformat = "[%(asctime)s] [%(levelname)s] [%(name)s] %(message)s"
loglevel = logging.INFO
handler = RotatingFileHandler(logfilename, maxBytes=1048576, backupCount=5)
handler.setLevel(loglevel)
handler.setFormatter(logging.Formatter(logformat))
logging.basicConfig(filename=logfilename, format=logformat, level=loglevel)
logger = logging.getLogger("passenger_wsgi")
logger.addHandler(handler)
logger.setLevel(loglevel)
logger.debug("Starting application")
Using logger from inside routes works as well. Hope this helps others who come across this!

Try to write into syslog

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")

logging.info doesn't show up on console but warn and error do

When I log an event with logging.info, it doesn't appear in the Python terminal.
import logging
logging.info('I am info') # no output
In contrast, events logged with logging.warn do appear in the terminal.
import logging
logging.warn('I am warning') # outputs "I am warning"
Is there a environment level change I can to make logging.info print to the console? I want to avoid making changes in each Python file.
The root logger always defaults to WARNING level. Try calling
logging.getLogger().setLevel(logging.INFO)
and you should be fine.
Like #ztyx said that default logger level is WARNING. You have to set it to a lower level
You can do it by using logging.basicConfig and setting logger level:
logging.basicConfig(level=logging.DEBUG)
The above solutions didn't work for me, but the code here did:
# set up logging to file
logging.basicConfig(level=logging.DEBUG,
format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s',
datefmt='%m-%d %H:%M',
filename='/temp/myapp.log',
filemode='w')
# define a Handler which writes INFO messages or higher to the sys.stderr
console = logging.StreamHandler()
console.setLevel(logging.INFO)
# add the handler to the root logger
logging.getLogger('').addHandler(console)
(I omitted parts of the code for the sake of readability)
This will work
import logging
logging.basicConfig()
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
logger.info('its working')
In more recent versions of Python 3 (tested with Python 3.8), console logging requires creating a console handler to correctly show info messages.
The following example is modified from the Configuring Logging example in the Python documentation:
import logging
# create logger
logger = logging.getLogger('__name__')
level = logging.INFO
logger.setLevel(level)
# ----> console info messages require these lines <----
# create console handler and set level to debug
ch = logging.StreamHandler()
ch.setLevel(level)
# add ch to logger
logger.addHandler(ch)
# -----------------------------------------------------
# 'application' code
logger.debug('debug message')
logger.info('info message')
logger.warning('warn message')
logger.error('error message')
logger.critical('critical message')
Running the above code generates the following output:
info message
warn message
error message
critical message
Here is this same code without the console handler.
import logging
# create logger
logger = logging.getLogger('__name__')
level = logging.INFO
logger.setLevel(level)
# 'application' code
logger.debug('debug message')
logger.info('info message')
logger.warning('warn message')
logger.error('error message')
logger.critical('critical message')
Without the console handler, the output does not include the info message:
warn message
error message
critical message
I do not understand why this is the case as it seems unnecessary.
What's the minimum required code for a working module-level logger? I did an experiment (with python version 3.8.6).
The take-away is:
logging.basicConfig() is needed (however, specifying level=... is NOT needed)
it's necessary to configure the root logger: logging.getLogger().setLevel(...)
So, a minimum working example is:
The library/module code does NOT need to configure the logger:
# library/module code: lib.py
import logging
LOGGER = logging.getLogger('x.y.z')
def some_function():
LOGGER.info("hi")
The application code need to configure the logger with 2 lines at minimum:
# Application Code
import logging, lib
logging.basicConfig()
logging.getLogger().setLevel(logging.INFO) # configure root logger
main() # code that will trigger lib
Here's the experiment:
In [1]: import logging
In [2]: lg = logging.getLogger('x.y.z')
In [3]: lg.info(1)
In [4]: logging.basicConfig()
In [5]: lg.info(1)
In [6]: logging.basicConfig(level=logging.INFO)
In [7]: lg.info(1)
In [8]: logging.basicConfig()
In [9]: logging.getLogger().setLevel(logging.INFO)
In [10]: lg.info(1)
INFO:x.y.z:1
For those using absl.logging, the equivalent command is
from absl import logging
logging.set_verbosity(logging.INFO)
If you are using Django to power your server, you just simply need to change the log level in your settings.py file as such:
"handlers": {
"console": {
-- "level": "WARNING",
++ "level": "INFO",
"class": "logging.StreamHandler",
"formatter": "stackdriver",
}
},
More examples in the documentation here:
https://docs.djangoproject.com/en/4.0/topics/logging/#configuring-logging-1
logging.info() will use the root logger for logging.
According to official doc,
if you do not set an explicit handler for the logger, a special handler called lastResort will be used.
See the code here. By default the logging level of lastResort (it is stream handler) is 30.
we can change its level to output info message.
# setting both the logger and handler's level will work as expected.
logger.setLevel(logging.DEBUG)
logging.lastResort.setLevel(logging.DEBUG)
However, this is like a hack and never a encouraged action.
Using logging.basicConfig()
If we want to do logging real quick, we can use the method logging.basicConfig.
logging.basicConfig(level=logging.DEBUG)
This will create the logger. The logger.level will be the level we set here.
A stream handler will be also created, with level NOTSET.
Without a level param, the default level for root logger is WARNING.
reference
logger logging without handler: logger logging without a handler

Categories

Resources