czwartek, 13 grudnia 2012

SysLogHandler i metalog

Logowanie błędów w web aplikacji to dość ważna rzecz. Czasami taki podsystem działa out-of-the-box, czasami wystarczy dobrze skonfigurować. Czasami coś po prostu nie działa :) ... i to zdarzyło się właśnie wtedy gdy postanowiłem w aplikacji opartej na Django zastosować logowanie do systemowego loggera.

Szybkie googlowanie wykazało że by dodać logowanie wiadomości do systemowego loggera w django wystarczy dodać do konfiguracji:

from logging.handlers import SysLogHandler

LOGGING = {
      #...
      'syslog':{
          'level':'INFO',
          'class': 'logging.handlers.SysLogHandler',
          'facility': SysLogHandler.LOG_LOCAL5
      }
      #...
}

... po uruchomieniu okazuje się że.. sposób ten nie działa :)

Okazuje się że domyślnym zachowaniem SysLogHandler'a jest łączenie się z procesem sysloga poprzez port 514. W moim systemie używany jest unix-socket w /dev/log.

Musimy więc dodać nowy klucz do naszej konfiguracji, wskazując tym samym na nasz socket:

LOGGING = {
      'syslog':{
          #to samo co wcześniej
          'address': '/dev/log'
      },
}

Część osób w tym momencie będzie miała już działające logowanie, ja nie miałem tego szczęścia - nie wiedzieć czemu, wiadomości wciąż nie były łapane przez syslog'a. Po chwili gimnastyki z kodem wiedziałem że socket jest używany, wiadomość jest wysyłana lecz z jakiegoś powodu nie jest odczytywana przez logera systemowego. Dlaczego?

O pomoc zwróciłem się do google :) W końcu natrafiłem na maila z 2010 roku.

Okazuje się że problemem był fakt posiadania Metalog'a - składnia wiadomości była przez niego odrzucana. Rozwiązanie jest dość proste:

Rozwiązanie z klassą

Osobiście nie przepadam za umieszczaniem "magicznych tekstów" (patrz - Rozwiązanie "szybko i prosto") w konfiguracji więc napisałem klasę MetaLogHandler:

# -*- coding: utf-8 -*-
'''
Created on 13-12-2012

@author: Arkadiusz Dzięgiel
'''
from logging.handlers import SysLogHandler
import logging

class MetaLogHandler(SysLogHandler):
       def __init__(self, *args, **kwargs):
               super(MetaLogHandler, self).__init__(*args, **kwargs)
               self.formatter = logging.Formatter('%(asctime)s %(name)s: %(levelname)s %(message)s',
                                                  '%b %e %H:%M:%S')

Jej użycie:

from glorpenlib.logging.handlers import MetaLogHandler

LOGGING = {
    'handlers': {
       'syslog':{
            'level':'INFO',
            'class': 'glorpenlib.logging.handlers.MetaLogHandler',
            'facility': MetaLogHandler.LOG_LOCAL5,
            'address': '/dev/log'
        },
    }
}

Rozwiązanie "szybko i prosto"

Można też umieścić tekst formatujący prosto w konfiguracji, wyglądałaby ona wtedy następująco:

from logging.handlers import SysLogHandler

LOGGING = {
     'formatters': {
        'metalog': { 'format': '%(asctime)s %(name)s: %(levelname)s %(message)s',
                     'dateformat': '%b %e %H:%M:%S'}
     },
    'handlers': {
       'syslog':{
            'level':'INFO',
            'class': 'logging.handlers.SysLogHandler',
            'formatter': 'metalog',
            'facility': SysLogHandler.LOG_LOCAL5,
            'address': '/dev/log'
        },
    }
}

sobota, 8 grudnia 2012

SSH i autoryzacja kluczem publicznym

Krótki snippet pozwalający na jednolinijkowe dodanie klucza publicznego SSH do autoryzowanych hostów na zdalnym systemie. Nie jest to odkrycie wieku ale miło oszczędza czas :)

Poniższy kawałek kodu kopiuje klucz publiczny z aktualnego konta. By wygenerować klucz można użyć polecenia ssh-keygen. Nie jest to odkrycie wieku, bo każdy kto się bardziej orientuje w linii poleceń linux'a mógłby coś takiego napisać - jednak znalezienie gotowca miło oszczędza czas :).

ssh -l user host 'mkdir ~/.ssh;echo '`cat ~/.ssh/id_rsa.pub`' >> ~/.ssh/authorized_keys'

Należy pamiętać o zmianie ścieżki ~/.ssh/id_rsa.pub jeśli klucz znajduje się w innym pliku.