9

I'm creating a Webservice using BaseHTTPServer.HTTPServer

I would like to log the following to be logged to a file rather than to the console. But I have not managed to find a way to do so yet.

10.23.23.19 - - [29/Nov/2013 08:39:06] "GET / HTTP/1.1" 200 -
10.23.23.19 - - [29/Nov/2013 08:39:06] "POST / HTTP/1.1" 200 -
10.24.20.14 - - [29/Nov/2013 08:39:27] "POST / HTTP/1.1" 200 -
10.24.20.14 - - [29/Nov/2013 08:39:31] "POST / HTTP/1.1" 200 -

My Code looks like this:

from BaseHTTPServer import HTTPServer
from pysimplesoap.server import SoapDispatcher, SOAPHandler
.
# The rest of the code
.
.
httpd = HTTPServer(("", 8059),SOAPHandler)
    httpd.dispatcher = dispatcher
    httpd.serve_forever()

I'm using Python 2.6

Phil
  • 2,859
  • 5
  • 20
  • 21
  • I have simply been looking for solutions online but what I keep finding is how to 'turn off' console logging rather than how to redirect it to a file. The best & simplest solution that I have found is: `from BaseHTTPServer import BaseHTTPRequestHandler class QuietBaseHTTPRequestHandler(BaseHTTPRequestHandler): def send_response(self, code, message=None): pass` – Phil Nov 29 '13 at 09:04
  • An older question, but still 3 years newer than the post that already answered this over on [How to silent/quiet HTTPServer and BasicHTTPRequestHandler's stderr output?](https://stackoverflow.com/questions/3389305/how-to-silent-quiet-httpserver-and-basichttprequesthandlers-stderr-output) =) – Mike 'Pomax' Kamermans Nov 15 '22 at 17:40

4 Answers4

9

If you read the doc or source code for BaseHTTPRequestHandler you'll find that all logging goes thru BaseHTTPRequestHandler.log_message(), which docstring explicitely specifies:

Log an arbitrary message.

This is used by all other logging functions. Override it if you have specific logging wishes.

So the solution is obviously to leave .send_response() alone (obviously you want your response to be sent), and replace .log_message() with either a call to a proper logger (cf http://docs.python.org/2/library/logging.html) which is the clean and flexible way to to handle logging in Python or if you just want an quick hack a write to a filesystem file.

bruno desthuilliers
  • 75,974
  • 6
  • 88
  • 118
  • Note that you usually don't want to override the master `log_message` def, but rather only the `log_request` handler, since you typically don't care about a constant stream successful requests, but you _do_ care about error. – Mike 'Pomax' Kamermans Nov 15 '22 at 17:43
6

I managed to find a solution.

I created a logger with a FileHandler in the pysimplesoap/server.py file. I created the logger right after doing the necessary imports.

httpdkenlogger = logging.getLogger('httpd-ken')
#setup file handler
fh = logging.FileHandler('/opt/python/dev/interim/httpd-kenserver.3.log')
fh.setLevel(logging.INFO)
frmt = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fh.setFormatter(frmt)
# Add this handler to the logger
httpdkenlogger.addHandler(fh)

Thereafter, within the definition of the SOAPHandler class, I decided to override the log_message function as follows:

class SOAPHandler(BaseHTTPRequestHandler):
    def log_message(self, format, *args):
        httpdkenlogger.info("%s - - [%s] %s\n" % (self.address_string(),self.log_date_time_string(),format%args))
Phil
  • 2,859
  • 5
  • 20
  • 21
1

I managed to suppress BaseHTTPRequestHandler info on console with:

class https_server(BaseHTTPRequestHandler):
    def log_request(self, code): 
        pass
    ...

Source

Pedro Lobito
  • 94,083
  • 31
  • 258
  • 268
0

In the manual it is stated:

BaseHTTPRequestHandler has the following instance variables:

log_message(format, ...)

The parameters to this are not listed, but by trial and error:

class MyClass(BaseHTTPRequestHandler):

    def fn( self, *args ):
        print( args )

    def do_POST(self):
        self.log_message = self.fn

there are four parameters display (the first is the format, then the request info, status code, and one other field.

So using a something like:

    def myLog( self, fmt, request, code, other ):
        syslog( LOG_INFO, '%s %s' % ( code, request) )

    def do_POST(self):
        self.log_message = self.myLog

It's possible to log to your own endpoint.

The only down side I see is it's necessary to replace log_message on every handler instance.

greg
  • 484
  • 3
  • 11