Skip to content

Instantly share code, notes, and snippets.

@dasimmet
Last active March 1, 2024 09:50
Show Gist options
  • Select an option

  • Save dasimmet/65183abc7e8aae7fcf115b8c452b1e41 to your computer and use it in GitHub Desktop.

Select an option

Save dasimmet/65183abc7e8aae7fcf115b8c452b1e41 to your computer and use it in GitHub Desktop.
a python stdlib SimpleHttpServer with ThreadingMixIn and logfile rotation support
#!/usr/bin/env python3
#
# httpserver.py
# by Tobias Simetsreiter <dasimmet@gmail.com> 2024
# https://gist.github.com/dasimmet/65183abc7e8aae7fcf115b8c452b1e41
from logging.handlers import RotatingFileHandler
import logging
import argparse
import sys
from http.server import HTTPServer,SimpleHTTPRequestHandler
from socketserver import ThreadingMixIn
def main():
p = parser()
args = p.parse_args()
Handler.HTTPDIR = args.directory
logHandlers = [
logging.StreamHandler(sys.stderr),
]
if args.logfile:
logHandlers.append(RotatingFileHandler(
args.logfile, maxBytes=args.logsize, backupCount=args.logcount,
))
if args.verbose:
logformat = '[%(asctime)s] %(levelname)s [%(name)s.%(funcName)s:%(lineno)d] %(message)s'
else:
logformat = '[%(asctime)s] %(levelname)s %(message)s'
logging.basicConfig(
handlers=logHandlers,
level=logging.DEBUG if args.verbose else logging.INFO,
format=logformat,
datefmt='%Y-%m-%dT%H:%M:%S'
)
if args.verbose and args.logfile:
logging.debug('Logging to: %s', args.logfile)
addr = (args.bind, args.port)
server = Server(addr,Handler)
logging.info('Listening on: http://{}:{}'.format(addr[0],addr[1]))
server.serve_forever()
def parser():
p = argparse.ArgumentParser(description='a python stdlib SimpleHttpServer with ThreadingMixIn and logfile rotation support')
p.add_argument('-b','--bind', default='0.0.0.0',
help='bind address, defaults to 0.0.0.0')
p.add_argument('-p','--port', type=int, default=8000,
help='bind port, defaults to 8000')
p.add_argument('-d','--directory', default='.',
help='directory to serve, defaults to ')
p.add_argument('-l','--logfile',
help='file to log to in addition to stdout')
p.add_argument('--logsize', type=int, default=5*2**20,
help='size of a logfile in bytes. Defaults to 5Mb. Ignored without --logfile')
p.add_argument('--logcount', type=int, default=5,
help='count of logfiles to keep. Defaults to 5. Ignored without --logfile')
p.add_argument("-v", "--verbose", help="increase output verbosity",
action="store_true")
return p
class Server(HTTPServer,ThreadingMixIn):
daemon_threads = True
allow_reuse_address = True
class Handler(SimpleHTTPRequestHandler):
HTTPDIR="."
def __init__(self, *args, **kwargs):
super().__init__(*args, directory=self.HTTPDIR, **kwargs)
# logging.debug((args,kwargs))
def log_error(self, format: str, *args) -> None:
return self.log_client_address(format, logging.error, *args)
def log_message(self, format: str, *args) -> None:
return self.log_client_address(format, logging.info, *args)
def log_client_address(self, format: str, logf, *args):
format = '%s:%s ' + format
args = (str(self.client_address[0]),str(self.client_address[1]))+args
return logf(format, *args)
if __name__=='__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment