PKMOM;q==aio_logstash/__init__.py"""Python AsyncIO Logstash Logger""" __version__ = '0.1.0' PK+gMOh44aio_logstash/constants.py LOG_RECORD_DEFAULT_ATTRIBUTES = [ 'args', 'created', 'exc_info', 'exc_text', 'filename', 'funcName', 'levelname', 'levelno', 'lineno', 'module', 'msecs', 'msg', 'name', 'pathname', 'process', 'processName', 'relativeCreated', 'stack_info', 'thread', 'threadName' ] SOCKET_RETRY_TIMEOUT = 1 PKY^MOw aio_logstash/formatter.pyimport abc import json import logging import socket import sys import time import aio_logstash import traceback from aio_logstash import constants from datetime import datetime, date class BaseFormatter(logging.Formatter): def __init__(self, message_type='aio_logstash', fqdn=False): super().__init__() self._message_type = message_type self._host = socket.getfqdn() if fqdn else socket.gethostname() self._interpreter = sys.executable self._interpreter_vesion = '{major}.{minor}.{micro}'.format( major=sys.version_info.major, minor=sys.version_info.minor, micro=sys.version_info.micro ) self._program_name = sys.argv[0] @staticmethod def _format_timestamp(_time): tstamp = datetime.utcfromtimestamp(_time) return tstamp.strftime("%Y-%m-%dT%H:%M:%S") + ".%03d" % (tstamp.microsecond / 1000) + "Z" @staticmethod def _format_stack_trace(exc_info): if exc_info: return ''.join(traceback.format_exception(*exc_info)) return None @staticmethod def _serialize(message): return bytes(json.dumps(message), encoding='utf-8') @abc.abstractmethod def format(self, record): pass def _get_base_fields(self): base_fields = { 'host': self._host, 'type': self._message_type, 'interpreter': self._interpreter, 'interpreter_version': self._interpreter_vesion, 'program': self._program_name, 'aio_logstash_version': aio_logstash.__version__, } return base_fields def _get_record_fields(self, record): record_fields = { 'message': record.getMessage(), 'pid': record.process, 'func_name': record.funcName, 'line': record.lineno, 'logger_name': record.name, 'path': record.pathname, 'thread_name': record.threadName, 'level': record.levelname, 'process_name': record.processName, 'stack_trace': self._format_stack_trace(record.exc_info) } return record_fields def _get_extra_fields(self, record): extra_fields = dict() for k, v in record.__dict__.items(): if k not in constants.LOG_RECORD_DEFAULT_ATTRIBUTES: extra_fields[k] = self._get_value_repr(v) return extra_fields def _get_value_repr(self, value): easy_types = (bool, float, type(None), str, int) if isinstance(value, dict): return {k: self._get_value_repr(v) for k, v in value.items()} elif isinstance(value, (tuple, list)): return [self._get_value_repr(v) for v in value] elif isinstance(value, (datetime, date)): return self._format_timestamp(time.mktime(value.timetuple())) elif isinstance(value, easy_types): return value else: return repr(value) class V1Formatter(BaseFormatter): def format(self, record): message = { '@timestamp': self._format_timestamp(record.created), '@version': '1' } base_fields = self._get_base_fields() message.update(base_fields) record_fields = self._get_record_fields(record) message.update(record_fields) extra_fields = self._get_extra_fields(record) message.update({ 'extra': extra_fields }) return self._serialize(message) PK؂MODl l aio_logstash/handler.pyimport abc import asyncio import logging from aio_logstash import constants from aio_logstash.formatter import V1Formatter class BaseHandler(logging.Handler): def __init__(self, num_consumers=1): super().__init__() self.setFormatter(V1Formatter()) self._queue = asyncio.Queue() self._consumers = [ asyncio.create_task(self._consumer()) for _ in range(num_consumers) ] def _produce(self, item): self._queue.put_nowait(item) def emit(self, record): self._produce(record) def _serialize(self, record): return self.format(record) + b'\n' async def _consumer(self): while True: record = await self._queue.get() data = self._serialize(record) while True: try: await self._send(data) break except (OSError, RuntimeError): await self._reconnect() self._queue.task_done() @abc.abstractmethod async def _send(self, data): pass @abc.abstractmethod async def _disconnect(self): pass @abc.abstractmethod async def _connect(self): pass async def _reconnect(self): await self._disconnect() while True: try: await self._connect() return except (OSError, RuntimeError): await asyncio.sleep(constants.SOCKET_RETRY_TIMEOUT) async def exit(self): await self._queue.join() for consumer in self._consumers: consumer.cancel() await self._disconnect() class TCPHandler(BaseHandler): def __init__(self, num_consumers=1): super().__init__( num_consumers=num_consumers ) self._writer = None async def connect(self, host, port): self._host = host self._port = port await self._connect() async def _connect(self): _, self._writer = await asyncio.open_connection( host=self._host, port=self._port ) async def _send(self, data): self._writer.write(data) await self._writer.drain() async def _disconnect(self): if self._writer is not None: self._writer.close() await self._writer.wait_closed() self._writer = None PK[iHON%%$aio_logstash-0.1.0.dist-info/LICENSEMIT License Copyright (c) 2019 Sina Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. PK!HPO"aio_logstash-0.1.0.dist-info/WHEEL HM K-*ϳR03rOK-J,/RH,szd&Y)r$[)T&UrPK!H3%aio_logstash-0.1.0.dist-info/METADATAS0+F"Bv[D(UQId#ւMmh8U8Ps̼yc54ɔRpNɚ,ePBKG4Ȯk1lϦf, n ȽYӕ4:L n)lrsA֖4:_šj5L/PK!H|#aio_logstash-0.1.0.dist-info/RECORDr@} W,EBt!tӀO?X3U:FW.(BfHϩLSsHYNL802閰IZq3-~\'Wrʁk~S6ʹ,#C/GV='W0mS>?T JsJjȈ1a4Ym){5NRdU|}Q[; Ů0Aݒ6jWɜ( 7” B'Ewҁ<nH @ *5%c'?&,Uо,ұ3xmw^τ1jon.~w 6G"Qn(%ä?XKOǽPKMOM;q==aio_logstash/__init__.pyPK+gMOh44saio_logstash/constants.pyPKY^MOw aio_logstash/formatter.pyPK؂MODl l aio_logstash/handler.pyPK[iHON%%$aio_logstash-0.1.0.dist-info/LICENSEPK!HPO"aio_logstash-0.1.0.dist-info/WHEELPK!H3%aio_logstash-0.1.0.dist-info/METADATAPK!H|# aio_logstash-0.1.0.dist-info/RECORDPK_"