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.

niedziela, 18 listopada 2012

Logitech Solar K750

Gdy dni stają się krótsze, gdy słońca jest coraz mniej - używając linux'a zaczynasz się zastanawiać jak długo jeszcze będziesz mógł korzystać ze swej nowej klawiatury Logitech K750 Solar :). By rozwiązać ten problem, stworzyłem aplikację umożliwiającą odczyt danych z sensorów np. klawiatury k750, wszystko jest dostępne w projekcie na bitbucket.

Moje poszukiwania rozpocząłem od artykułu Julien Danjou, gdzie oprócz przejrzystego rozpracowywania protokołu Logitech'a został dodany później link do specyfikacji zdobytej przez Lars-Dominik Braun.

Jako że dość szybko odkryłem te informacje, uznałem że może ktoś już napisał jakąś aplikację wyciągającą stan baterii czy naświetlenia. Trafiłem na projekt na github'ie: https://github.com/aheadley/logitech-solar-k750-linux/blob/master/logitech_k750.py.

Niestety posiadał pewne wady:

  • nie do końca działał na moim sprzęcie
  • podczas odczytu wartości blokował cały interfejs usb - czyli klawiatura po prostu nie działała

Podczas poszukiwań mój cel stał się bardziej klarowny - postanowiłem napisać jakiś serwis pozwalający na bezproblemowy odczyt chociażby informacji o naładowaniu baterii.

Następnym problemem z którym musiałam się zmierzyć był fakt że wiele bezprzewodowych urządzeń logitech'a mogło korzystać z 1 odbiornika, powodowało to brak takowego podziału w urządzeniach /dev/hidraw, miałem nadzieję że patch proponowany na https://lkml.org/lkml/2012/1/17/118 mógłby to naprawić ale niestety to nie było to. Napisałem więc własny parser pakietów HID++ (których oczywiście nie mogłem znaleźć w specyfikacji :D ). Posiadam tylko jedno bezprzewodowe urządzenie logitech'a więc nie mogłem sprawdzić czy kod zachowa się poprawnie dla większej ilości.

Gdy już posiadałem kod potrafiący wyciągać i prosić o informacje o naładowaniu dodałem do tego serwis DBus, prostego klienta konsolowego oraz rozszerzenie do Gnome-Shell. Użytkownicy sytemu Gentoo mogą pobrać ebuild'a z https://bitbucket.org/glorpen/pysolar/src/tip/gentoo/app-misc/pysolar?at=default


Cała opisywania powyżej aplikacja jest dostępna jako projekt na bitbucket

poniedziałek, 12 listopada 2012

TinyMCE - Czy wysiwyg jest potrzebny?

wyswig

TinyMCE jest edytorem z kategorii wysiwyg - czyli “widzimy” jak treść będzie wyglądała po wyświetleniu użytkownikowi. Niestety nie zdarzyło mi się jeszcze zobaczyć tak przygotowanego edytora by rzeczywiście odwzorowywał style, nie mówię że jest to niemożliwe czy nawet bardzo trudne, po prostu najczęściej zaniedbywane - podstawowe style zazwyczaj działają (pogrubienie, kursywa, itp.).

Sądzę że najgorszym momentem jest gdy użytkownik będzie chciał dodać do treści widgeta złożonego z css/js, jako że tinymce jest edytorem html’a umożliwia wykonanie wszystkiego, nawet dodanie inlinowo do treści stylów i zewnętrznych javascript'ów a następnie węzła script z odpowiednim kodem inicjalizującym widget’a. Tak, będzie działało. Z punktu widzenia developera takie użycie zepsuje wiele dobrych praktyk - minifikacja, opóźnione ładowanie js (a co gdy np. jQuery jest załączane PO widgecie?),

Próbując znaleźć idealną odpowiedź na to pytanie, sporządziłem listę rzeczy która powinna być wspierana przez edytora:

  • prezentacja w jakiś sposób wyglądu końcowego
  • by użytkownik nie mógł “psuć” strony - załączać w treści nowych bibliotek, zmiana styli, dodawanie tagów skopiowanych z word’a czy też innych programów Microsoft’u
  • możliwość implementacji “interfejsów” przez developera - by użytkownik mógł w znormalizowany i kontrolowany przez developera sposób dodawać różne elemeny/widgety/embedować pliki

Dość szybko trafiłem na MarkItUp!. Pozwala on na zdefiniowanie własnego schematu który będzie później parsowany przez stronę serwerową, dostarcza możliwość podglądu aktualnie edytowanej treści (tutaj to samo ograniczenie co w tinymce - jeśli developer nie doda styli ze strony, podgląd nie będzie tak zbliżony do prawdziwego wyglądu jakby mógł być). Po stronie serwerowej wybrałem pythonowe Docutils z obsługą ReStructuredText (używane też na github’ie).

Plusy

  • Potrzeba sposobu na kolorowanie kodu? Nie ma problemu - wystarczy zarejestrować bibliotekę pygments jako funkcję w docutils
  • Dodawanie obrazka? Jest. Ma być po prawej? dodajemy align: right do opcji metody

W skrócie - trzeba dodać funkcjonalność X? Dodajemy nową funkcję rest_X do docutils :)

Minusy

  • Trzeba wiedzieć że jest to parsowane jako ReST
  • Znajomość struktury

Decyzję zostawiam wam :)

środa, 7 listopada 2012

Sprite’s i wiele teł

W czasach kiedy jeszcze studiowałem, na ćwiczeniach pojawiło się zadanie - napisać aplet którego głównymi bohaterami były drożdże. Minęło już dużo czasu od tego momentu ale hipnotyczne właściwości tej prostej aplikacji nie osłabły. Zdecydowałem sie więc na przepisanie jej na javascript'a - http://glorpen.pl/projects/yeast.

Tła przedstawiały stany danego pola i nie musiały występować same, tak więc potrzebowałem ustawić wiele teł dla pojedynczego elementu. Niestety jak na razie CSS nie wspiera rozszerzania deklaracji background. Napisałem więc następującego mixin’a:

@mixin yeast-background($theme, $args...){
  $positions: ();
  $backgrounds: ();

  @each $v in $args {
      $positions: append($positions, sprite-position($theme, $v), comma);
      $backgrounds: append($backgrounds, $theme, comma);
  }

  background: $backgrounds;
  background-position: $positions;
}

Jego użycie:

$theme: sprite-map("projects/yeast/themes/normal/*.png");

@include yeast-background($theme, background);

&.grass {
      @include yeast-background($theme, food, background);
  }
  &.carnivore {
      @include yeast-background($theme, thing, background);
  }
}

Co po skompilowaniu da nam mniej więcej coś takiego:

#project-yeast .app.normal td.grass {
 background: url('/static/img/projects/yeast/themes/normal-s1b3c760646.png'), url('/static/img/projects/yeast/themes/normal-s1b3c760646.png');
 background-position: 0 -64px, 0 -160px;
}
#project-yeast .app.normal td.carnivore {
 background: url('/static/img/projects/yeast/themes/normal-s1b3c760646.png'), url('/static/img/projects/yeast/themes/normal-s1b3c760646.png');
 background-position: 0 -96px, 0 -160px;
}

czwartek, 11 października 2012

pyftpdlib

Jeśli chciałeś kiedyś przesłać szybko kilka plików na inny komputer w sieci lokalnej ale napotkałeś następujące problemy: komunikatory nie są ze sobą kompatybilne pod względem przesyłania plików, plik jest przesyłany "na zewnątrz" a nie w lanie, znalezione rozwiązanie trzeba najpierw zainstalować.. skonfigurować... - z pomocą przychodzi biblioteka pyftpdlib!

Biblioteka pyftpdlib dostarcza wysokopoziomowy interfejs do tworzenia serwerów ftp. Nie przeszkadza to do użycia jako szybkie rozwiązanie do przesyłania plików.

Instalacja

W zależności od manadżera pakietów w twoim systemie :) Lub też po python'owemu:

pip install pyftpdlib

Użycie

Wersja z kodem:

from pyftpdlib import ftpserver
authorizer = ftpserver.DummyAuthorizer()
authorizer.add_anonymous("/home/ftp", perm="elradfmw")
handler = ftpserver.FTPHandler
handler.authorizer = authorizer
address = ("10.0.0.123", 21)
ftpd = ftpserver.FTPServer(address, handler)
ftpd.serve_forever()

wersja bardziej poręczna:

python -m pyftpdlib.ftpserver -w -p 2121 ./

W obu przypadkach dostępne są konta anonymous z możliwością odczytu/zapisu.