def test_mail_handler(activation_strategy, logger): subject = u('\xf8nicode') handler = make_fake_mail_handler(subject=subject) with capturing_stderr_context() as fallback: with activation_strategy(handler): logger.warn('This is not mailed') try: 1 / 0 except Exception: logger.exception(u('Viva la Espa\xf1a')) if not handler.mails: # if sending the mail failed, the reason should be on stderr assert False, fallback.getvalue() assert len(handler.mails) == 1 sender, receivers, mail = handler.mails[0] mail = mail.replace('\r', '') assert sender == handler.from_addr assert '=?utf-8?q?=C3=B8nicode?=' in mail header, data = mail.split('\n\n', 1) if 'Content-Transfer-Encoding: base64' in header: data = base64.b64decode(data).decode('utf-8') assert re.search('Message type:\s+ERROR', data) assert re.search('Location:.*%s' % re.escape(__file_without_pyc__), data) assert re.search('Module:\s+%s' % __name__, data) assert re.search('Function:\s+test_mail_handler', data) body = u('Viva la Espa\xf1a') if sys.version_info < (3, 0): body = body.encode('utf-8') assert body in data assert '\nTraceback (most' in data assert '1 / 0' in data assert 'This is not mailed' in fallback.getvalue()
def record_ticket(self, record, data, hash, app_id): """Records a log record as ticket.""" # Can use the session instead engine.connection and transaction s = self.session try: q = self.tickets.select(self.tickets.c.record_hash == hash) row = s.execute(q).fetchone() if row is None: row = s.execute(self.tickets.insert().values( record_hash=hash, level=record.level, channel=record.channel or u(''), location=u('%s:%d') % (record.filename, record.lineno), module=record.module or u('<unknown>'), occurrence_count=0, solved=False, app_id=app_id)) ticket_id = row.inserted_primary_key[0] else: ticket_id = row['ticket_id'] s.execute(self.occurrences.insert().values(ticket_id=ticket_id, time=record.time, app_id=app_id, data=json.dumps(data))) s.execute(self.tickets.update().where( self.tickets.c.ticket_id == ticket_id).values( occurrence_count=self.tickets.c.occurrence_count + 1, last_occurrence_time=record.time, solved=False)) s.commit() except Exception: s.rollback() raise # Closes the session and removes it from the pool s.remove()
def record_ticket(self, record, data, hash, app_id): """Records a log record as ticket.""" db = self.database ticket = db.tickets.find_one({"record_hash": hash}) if not ticket: doc = { "record_hash": hash, "level": record.level, "channel": record.channel or u(""), "location": u("%s:%d") % (record.filename, record.lineno), "module": record.module or u("<unknown>"), "occurrence_count": 0, "solved": False, "app_id": app_id, } ticket_id = db.tickets.insert(doc) else: ticket_id = ticket["_id"] db.tickets.update( {"_id": ticket_id}, {"$inc": {"occurrence_count": 1}, "$set": {"last_occurrence_time": record.time, "solved": False}}, ) # We store occurrences in a seperate collection so that # we can make it a capped collection optionally. db.occurrences.insert( {"ticket_id": self._oid(ticket_id), "app_id": app_id, "time": record.time, "data": json.dumps(data)} )
def record_ticket(self, record, data, hash, app_id): """Records a log record as ticket.""" cnx = self.engine.connect() trans = cnx.begin() try: q = self.tickets.select(self.tickets.c.record_hash == hash) row = cnx.execute(q).fetchone() if row is None: row = cnx.execute(self.tickets.insert().values( record_hash=hash, level=record.level, channel=record.channel or u(''), location=u('%s:%d') % (record.filename, record.lineno), module=record.module or u('<unknown>'), occurrence_count=0, solved=False, app_id=app_id)) ticket_id = row.inserted_primary_key[0] else: ticket_id = row['ticket_id'] cnx.execute(self.occurrences.insert().values( ticket_id=ticket_id, time=record.time, app_id=app_id, data=json.dumps(data))) cnx.execute(self.tickets.update().where( self.tickets.c.ticket_id == ticket_id).values( occurrence_count=self.tickets.c.occurrence_count + 1, last_occurrence_time=record.time, solved=False)) trans.commit() except Exception: trans.rollback() raise cnx.close()
def __call__(self, record, handler): formatted = StringFormatter.__call__(self, record, handler) rv = [] length = 0 for piece in _ws_re.split(formatted): length += len(piece) if length > self.max_length: if length - len(piece) < self.max_length: rv.append(u('…')) break rv.append(piece) return u('').join(rv)
def test_zeromq_handler(logger, handlers, subscriber): tests = [ u('Logging something'), u('Something with umlauts äöü'), u('Something else for good measure'), ] for test in tests: for handler in handlers: with handler: logger.warn(test) record = subscriber.recv() assert record.message == test assert record.channel == logger.name
def test_jsonhelper(): from logbook.helpers import to_safe_json class Bogus(object): def __str__(self): return 'bogus' rv = to_safe_json([ None, 'foo', u('jäger'), 1, datetime(2000, 1, 1), { 'jäger1': 1, u('jäger2'): 2, Bogus(): 3, 'invalid': object() }, object() # invalid ]) assert rv == [ None, u('foo'), u('jäger'), 1, '2000-01-01T00:00:00Z', { u('jäger1'): 1, u('jäger2'): 2, u('bogus'): 3, u('invalid'): None }, None ]
def setup_backend(self): from couchdb import Server uri = self.options.pop('uri', u('')) couch = Server(uri) db_name = self.options.pop('db') self.database = couch[db_name]
def exception_message(self): """The message of the exception.""" if self.exc_info is not None: val = self.exc_info[1] try: return u(str(val)) except UnicodeError: return str(val).decode('utf-8', 'replace')
def test_exception_catching_with_unicode(): """ See https://github.com/getlogbook/logbook/issues/104 """ try: raise Exception(u('\u202a test \u202c')) except: r = logbook.LogRecord('channel', 'DEBUG', 'test', exc_info=sys.exc_info()) r.exception_message
def __init__(self, uri, app_id='generic', level=NOTSET, filter=None, bubble=False, hash_salt=None, backend=None, **db_options): if hash_salt is None: hash_salt = u('apphash-') + app_id TicketingBaseHandler.__init__(self, hash_salt, level, filter, bubble) if backend is None: backend = self.default_backend db_options['uri'] = uri self.set_backend(backend, **db_options) self.app_id = app_id
def test_syslog_handler(logger, activation_strategy, unix_sock_path): to_test = [ (socket.AF_INET, ('127.0.0.1', 0)), ] if hasattr(socket, 'AF_UNIX'): to_test.append((socket.AF_UNIX, unix_sock_path)) for sock_family, address in to_test: with closing(socket.socket(sock_family, socket.SOCK_DGRAM)) as inc: inc.bind(address) inc.settimeout(1) for app_name in [None, 'Testing']: handler = logbook.SyslogHandler(app_name, inc.getsockname()) with activation_strategy(handler): logger.warn('Syslog is weird') try: rv = inc.recvfrom(1024)[0] except socket.error: assert False, 'got timeout on socket' assert rv == (u('<12>%stestlogger: Syslog is weird\x00') % ((app_name and (app_name + u(':'))) or u(''))).encode('utf-8')
def record_ticket(self, record, data, hash, app_id): """Records a log record as ticket.""" # Can use the session instead engine.connection and transaction s = self.session try: q = self.tickets.select(self.tickets.c.record_hash == hash) row = s.execute(q).fetchone() if row is None: row = s.execute( self.tickets.insert().values( record_hash=hash, level=record.level, channel=record.channel or u(""), location=u("%s:%d") % (record.filename, record.lineno), module=record.module or u("<unknown>"), occurrence_count=0, solved=False, app_id=app_id, ) ) ticket_id = row.inserted_primary_key[0] else: ticket_id = row["ticket_id"] s.execute( self.occurrences.insert().values( ticket_id=ticket_id, time=record.time, app_id=app_id, data=json.dumps(data) ) ) s.execute( self.tickets.update() .where(self.tickets.c.ticket_id == ticket_id) .values( occurrence_count=self.tickets.c.occurrence_count + 1, last_occurrence_time=record.time, solved=False ) ) s.commit() except Exception: s.rollback() raise # Closes the session and removes it from the pool s.remove()
def record_ticket(self, record, data, hash, app_id): """Records a log record as ticket.""" db = self.database ticket = db.tickets.find_one({'record_hash': hash}) if not ticket: doc = { 'record_hash': hash, 'level': record.level, 'channel': record.channel or u(''), 'location': u('%s:%d') % (record.filename, record.lineno), 'module': record.module or u('<unknown>'), 'occurrence_count': 0, 'solved': False, 'app_id': app_id, } ticket_id = db.tickets.insert(doc) else: ticket_id = ticket['_id'] db.tickets.update({'_id': ticket_id}, { '$inc': { 'occurrence_count': 1 }, '$set': { 'last_occurrence_time': record.time, 'solved': False } }) # We store occurrences in a seperate collection so that # we can make it a capped collection optionally. db.occurrences.insert({ 'ticket_id': self._oid(ticket_id), 'app_id': app_id, 'time': record.time, 'data': json.dumps(data), })
def record_ticket(self, record, data, hash, app_id): """Records a log record as ticket.""" cnx = self.engine.connect() trans = cnx.begin() try: q = self.tickets.select(self.tickets.c.record_hash == hash) row = cnx.execute(q).fetchone() if row is None: row = cnx.execute(self.tickets.insert().values( record_hash=hash, level=record.level, channel=record.channel or u(''), location=u('%s:%d') % (record.filename, record.lineno), module=record.module or u('<unknown>'), occurrence_count=0, solved=False, app_id=app_id )) ticket_id = row.inserted_primary_key[0] else: ticket_id = row['ticket_id'] cnx.execute(self.occurrences.insert() .values(ticket_id=ticket_id, time=record.time, app_id=app_id, data=json.dumps(data))) cnx.execute(self.tickets.update() .where(self.tickets.c.ticket_id == ticket_id) .values(occurrence_count=self.tickets.c.occurrence_count + 1, last_occurrence_time=record.time, solved=False)) trans.commit() except Exception: trans.rollback() raise cnx.close()
def emit(self, record): if not self.check_delivery(record)[1]: return body = urlencode({ 'notification[from_screen_name]': self.get_screen_name(record).encode('utf-8'), 'notification[message]': self.make_text(record).encode('utf-8'), 'notification[from_remote_service_id]': str(int(time() * 100)) }) con = http_client.HTTPSConnection('boxcar.io') con.request('POST', '/notifications/', headers={ 'Authorization': 'Basic ' + base64.b64encode((u('%s:%s') % (self.email, self.password)) .encode('utf-8')).strip(), }, body=body) con.close()
def test_jsonhelper(): from logbook.helpers import to_safe_json class Bogus(object): def __str__(self): return 'bogus' rv = to_safe_json([ None, 'foo', u('jäger'), 1, datetime(2000, 1, 1), {'jäger1': 1, u('jäger2'): 2, Bogus(): 3, 'invalid': object()}, object() # invalid ]) assert rv == [None, u('foo'), u('jäger'), 1, '2000-01-01T00:00:00Z', {u('jäger1'): 1, u('jäger2'): 2, u('bogus'): 3, u('invalid'): None}, None]
def setup_backend(self): import pymongo from pymongo import ASCENDING, DESCENDING from pymongo.connection import Connection try: from pymongo.uri_parser import parse_uri except ImportError: from pymongo.connection import _parse_uri as parse_uri from pymongo.errors import AutoReconnect _connection = None uri = self.options.pop('uri', u('')) _connection_attempts = 0 parsed_uri = parse_uri(uri, Connection.PORT) if type(parsed_uri) is tuple: # pymongo < 2.0 database = parsed_uri[1] else: # pymongo >= 2.0 database = parsed_uri['database'] # Handle auto reconnect signals properly while _connection_attempts < 5: try: if _connection is None: _connection = Connection(uri) database = _connection[database] break except AutoReconnect: _connection_attempts += 1 time.sleep(0.1) self.database = database # setup correct indexes database.tickets.ensure_index([('record_hash', ASCENDING)], unique=True) database.tickets.ensure_index([('solved', ASCENDING), ('level', ASCENDING)]) database.occurrences.ensure_index([('time', DESCENDING)])
def setup_backend(self): from pymongo import ASCENDING, DESCENDING from pymongo.connection import Connection try: from pymongo.uri_parser import parse_uri except ImportError: from pymongo.connection import _parse_uri as parse_uri from pymongo.errors import AutoReconnect _connection = None uri = self.options.pop('uri', u('')) _connection_attempts = 0 parsed_uri = parse_uri(uri, Connection.PORT) if type(parsed_uri) is tuple: # pymongo < 2.0 database = parsed_uri[1] else: # pymongo >= 2.0 database = parsed_uri['database'] # Handle auto reconnect signals properly while _connection_attempts < 5: try: if _connection is None: _connection = Connection(uri) database = _connection[database] break except AutoReconnect: _connection_attempts += 1 time.sleep(0.1) self.database = database # setup correct indexes database.tickets.ensure_index([('record_hash', ASCENDING)], unique=True) database.tickets.ensure_index([('solved', ASCENDING), ('level', ASCENDING)]) database.occurrences.ensure_index([('time', DESCENDING)])
def emit(self, record): if not self.check_delivery(record)[1]: return body = urlencode( { "notification[from_screen_name]": self.get_screen_name(record).encode("utf-8"), "notification[message]": self.make_text(record).encode("utf-8"), "notification[from_remote_service_id]": str(int(time() * 100)), } ) con = http_client.HTTPSConnection("boxcar.io") con.request( "POST", "/notifications/", headers={ "Authorization": "Basic " + base64.b64encode((u("%s:%s") % (self.email, self.password)).encode("utf-8")).strip() }, body=body, ) con.close()
def __init__(self, uri=None, context=None, multi=False): try: import zmq except ImportError: raise RuntimeError("The pyzmq library is required for " "the ZeroMQSubscriber.") self._zmq = zmq #: the zero mq context self.context = context or zmq.Context() if multi: #: the zero mq socket. self.socket = self.context.socket(zmq.PULL) if uri is not None: self.socket.bind(uri) else: #: the zero mq socket. self.socket = self.context.socket(zmq.SUB) if uri is not None: self.socket.connect(uri) self.socket.setsockopt_unicode(zmq.SUBSCRIBE, u(""))
def __init__(self, uri=None, context=None, multi=False): try: import zmq except ImportError: raise RuntimeError('The pyzmq library is required for ' 'the ZeroMQSubscriber.') self._zmq = zmq #: the zero mq context self.context = context or zmq.Context() if multi: #: the zero mq socket. self.socket = self.context.socket(zmq.PULL) if uri is not None: self.socket.bind(uri) else: #: the zero mq socket. self.socket = self.context.socket(zmq.SUB) if uri is not None: self.socket.connect(uri) self.socket.setsockopt_unicode(zmq.SUBSCRIBE, u(''))
from logbook.handlers import Handler, StringFormatter, \ StringFormatterHandlerMixin, StderrHandler from logbook._termcolors import colorize from logbook.helpers import PY2, string_types, iteritems, u from logbook.ticketing import TicketingHandler as DatabaseHandler from logbook.ticketing import BackendBase if PY2: from urllib import urlencode else: from urllib.parse import urlencode _ws_re = re.compile(r'(\s+)(?u)') TWITTER_FORMAT_STRING = \ u('[{record.channel}] {record.level_name}: {record.message}') TWITTER_ACCESS_TOKEN_URL = 'https://twitter.com/oauth/access_token' NEW_TWEET_URL = 'https://api.twitter.com/1/statuses/update.json' class CouchDBBackend(BackendBase): """Implements a backend that writes into a CouchDB database. """ def setup_backend(self): from couchdb import Server uri = self.options.pop('uri', u('')) couch = Server(uri) db_name = self.options.pop('db') self.database = couch[db_name]
def format_exception(self, record): return u('%s: %s') % (record.exception_shortname, record.exception_message)
def exception_name(self): """The name of the exception.""" if self.exc_info is not None: cls = self.exc_info[0] return u(cls.__module__ + '.' + cls.__name__)
def __missing__(self, key): return u('')
def __getitem__(self, key): try: return dict.__getitem__(self, key) except KeyError: return u('')
def make_title(self, record): """Called to get the title from the record.""" return u("%s: %s") % (record.channel, record.level_name.title())
from logbook.helpers import u from logbook.compat import redirect_warnings from logbook.compat import redirect_logging from logbook.base import _datetime_factory from galacteek.core import SingletonDecorator from galacteek.core import runningApp try: from aiofile import AIOFile except ImportError: haveAioFile = False else: haveAioFile = True mainFormatString = u('[{record.time:%Y-%m-%d %H:%M:%S.%f%z}] ' '{record.level_name}: {record.module}: {record.message}') easyFormatString = u('[{record.time: %H:%M:%S}] ' '{record.module}: {record.message}') loggerMain = Logger('galacteek') loggerUser = Logger('galacteek.user') @SingletonDecorator class LogRecordStyler: red = Color('red') darkred = Color('darkred') blue = Color('blue') turquoise = Color('turquoise') green = Color('green')
def message_to_unicode(self, message): try: return u(str(message)) except UnicodeError: return str(message).decode('utf-8', 'replace')
def make_title(self, record): """Called to get the title from the record.""" return u('%s: %s') % (record.channel, record.level_name.title())
try: import riemann_client.client import riemann_client.transport except ImportError: riemann_client = None #from riemann_client.transport import TCPTransport, UDPTransport, BlankTransport if PY2: from urllib import urlencode from urlparse import parse_qsl else: from urllib.parse import parse_qsl, urlencode _ws_re = re.compile(r'(\s+)(?u)') TWITTER_FORMAT_STRING = u( '[{record.channel}] {record.level_name}: {record.message}') TWITTER_ACCESS_TOKEN_URL = 'https://twitter.com/oauth/access_token' NEW_TWEET_URL = 'https://api.twitter.com/1/statuses/update.json' class CouchDBBackend(BackendBase): """Implements a backend that writes into a CouchDB database. """ def setup_backend(self): from couchdb import Server uri = self.options.pop('uri', u('')) couch = Server(uri) db_name = self.options.pop('db') self.database = couch[db_name]
def test_file_handler_unicode(logfile, activation_strategy, logger): with capturing_stderr_context() as captured: with activation_strategy(logbook.FileHandler(logfile)): logger.info(u('\u0431')) assert (not captured.getvalue())
from logbook.handlers import (Handler, StringFormatter, StringFormatterHandlerMixin, StderrHandler) from logbook._termcolors import colorize from logbook.helpers import PY2, string_types, iteritems, u from logbook.ticketing import TicketingHandler as DatabaseHandler from logbook.ticketing import BackendBase if PY2: from urllib import urlencode from urlparse import parse_qsl else: from urllib.parse import parse_qsl, urlencode _ws_re = re.compile(r'(\s+)(?u)') TWITTER_FORMAT_STRING = u( '[{record.channel}] {record.level_name}: {record.message}') TWITTER_ACCESS_TOKEN_URL = 'https://twitter.com/oauth/access_token' NEW_TWEET_URL = 'https://api.twitter.com/1/statuses/update.json' class CouchDBBackend(BackendBase): """Implements a backend that writes into a CouchDB database. """ def setup_backend(self): from couchdb import Server uri = self.options.pop('uri', u('')) couch = Server(uri) db_name = self.options.pop('db') self.database = couch[db_name]