2013-08-28

Django logging setting

It took me some time to figure out how to set up logging in Django.  What I want to do is to log to a pair of rotating files each 1MB in size.

What I come up with is the following code segment to replace the LOGGING setting in the settings.py:

U_LOGFILE_NAME = r'/path/to/log.txt'
U_LOGFILE_SIZE = 1 * 1024 * 1024
U_LOGFILE_COUNT = 2
U_LOGFILE_APP1 = 'app1'
U_LOGFILE_APP2 = 'app2'

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'formatters': {
        'standard': {
            'format' : "[%(asctime)s] %(levelname)s [%(name)s:%(lineno)s] %(message)s",
            #'datefmt' : "%d/%b/%Y %H:%M:%S"
        },
    },
    'filters': {
        'require_debug_false': {
            '()': 'django.utils.log.RequireDebugFalse'
        }
    },
    'handlers': {
        'mail_admins': {
            'level': 'ERROR',
            'filters': ['require_debug_false'],
            'class': 'django.utils.log.AdminEmailHandler'
        },
        'logfile': {
            'level':'DEBUG',
            'class':'logging.handlers.RotatingFileHandler',
            'filename': U_LOGFILE_NAME,
            'maxBytes': U_LOGFILE_SIZE,
            'backupCount': U_LOGFILE_COUNT,
            'formatter': 'standard',
        },
    },
    'loggers': {
        'django.request': {
            'handlers': ['mail_admins'],
            'level': 'ERROR',
            'propagate': True,
        },
        U_LOGFILE_APP1: {
            'handlers': ['logfile'],
            'level': 'DEBUG',
            'propagate': True,
        },
        U_LOGFILE_APP2: {
            'handlers': ['logfile'],
            'level': 'DEBUG',
            'propagate': True,
        },
    }
}

Usage:

import os
log = logging.getLogger(__name__)

log.debug("debug")
log.info("info")
log.warn("warn")
log.error("error")

This post also appears in Django Snippets.


2013-08-01

Add password to a PDF with PyPDF

PyPDF is a pure python module to manipulate PDF.

Examples:

# add password to a pdf
# add_password.py input.pdf password output.pdf


import sys
from pyPdf import PdfFileWriter, PdfFileReader

output = PdfFileWriter()
input = PdfFileReader(file(sys.argv[1], "rb"))
for i in range(0, input.getNumPages()):
    output.addPage(input.getPage(i))
outputStream = file(sys.argv[3], "wb")
output.encrypt(sys.argv[2], use_128bit=True)
output.write(outputStream)
outputStream.close()


# extract pages from a pdf
# extract_page.py input.pdf start_page end_page out.pdf
# page starts from 1


import sys
from pyPdf import PdfFileWriter, PdfFileReader

output = PdfFileWriter()
input = PdfFileReader(file(sys.argv[1], "rb"))
for i in range(int(sys.argv[2]), int(sys.argv[3])+1):
    output.addPage(input.getPage(i-1))
outputStream = file(sys.argv[4], "wb")
output.write(outputStream)
outputStream.close()


# rotate all pages clockwise
# rotate.py input.pdf degrees output.pdf

# degrees must be multiple of 90 

import sys
from pyPdf import PdfFileWriter, PdfFileReader

output = PdfFileWriter()
input = PdfFileReader(file(sys.argv[1], "rb"))
for i in range(0, input.getNumPages()):
    output.addPage(input.getPage(i).rotateClockwise(int(sys.argv[2])))
outputStream = file(sys.argv[3], "wb")
output.write(outputStream)
outputStream.close()

Troubleshooting ssh "Too many authentication failures"

Some time ago all of a sudden, I was unable to ssh into a host anymore with the above error.  I didn't even have a chance to enter my password.

Eventual the cause of the problem was found.  I have multiple ssh keys but none of them is for the target host.  SSH is configure to use public key authentication before password authentication.  Hence ssh tries all my keys without success, hitting the maximum password attempts, and ends with the error "Too many authentication failures".

The solution:

Force ssh to not use public key authentication, and then copy over
the public key for the target host:

$ ssh-copy-id -i ~/.ssh/id_rsa.pub "-o PubKeyAuthentication=no user@host.com -p 22"

Note the use of double quote, otherwise ssh-copy-id will not recognize 
the ssh options.