2019-01-22 15:43:03 +01:00
|
|
|
import asyncio
|
|
|
|
import json
|
|
|
|
import logging.handlers
|
|
|
|
import traceback
|
2020-01-03 07:39:34 +01:00
|
|
|
|
2020-02-20 18:27:39 +01:00
|
|
|
import typing
|
2020-01-03 07:39:34 +01:00
|
|
|
from aiohttp.client_exceptions import ClientError
|
2019-10-04 15:40:41 +02:00
|
|
|
import aiohttp
|
2019-06-21 02:55:47 +02:00
|
|
|
from lbry import utils, __version__
|
2020-02-20 18:27:39 +01:00
|
|
|
if typing.TYPE_CHECKING:
|
|
|
|
from lbry.conf import Config
|
2019-01-22 15:43:03 +01:00
|
|
|
|
2019-01-21 21:55:50 +01:00
|
|
|
LOGGLY_TOKEN = 'BQEzZmMzLJHgAGxkBF00LGD0YGuyATVgAmqxAQEuAQZ2BQH4'
|
|
|
|
|
|
|
|
|
2019-01-22 15:43:03 +01:00
|
|
|
class JsonFormatter(logging.Formatter):
|
|
|
|
"""Format log records using json serialization"""
|
|
|
|
|
|
|
|
def __init__(self, **kwargs):
|
2020-01-03 07:39:34 +01:00
|
|
|
super().__init__()
|
2019-01-22 15:43:03 +01:00
|
|
|
self.attributes = kwargs
|
|
|
|
|
|
|
|
def format(self, record):
|
|
|
|
data = {
|
|
|
|
'loggerName': record.name,
|
|
|
|
'asciTime': self.formatTime(record),
|
|
|
|
'fileName': record.filename,
|
|
|
|
'functionName': record.funcName,
|
|
|
|
'levelNo': record.levelno,
|
|
|
|
'lineNo': record.lineno,
|
|
|
|
'levelName': record.levelname,
|
|
|
|
'message': record.getMessage(),
|
|
|
|
}
|
|
|
|
data.update(self.attributes)
|
|
|
|
if record.exc_info:
|
|
|
|
data['exc_info'] = self.formatException(record.exc_info)
|
|
|
|
return json.dumps(data)
|
|
|
|
|
|
|
|
|
|
|
|
class HTTPSLogglyHandler(logging.Handler):
|
2020-02-20 18:27:39 +01:00
|
|
|
def __init__(self, loggly_token: str, fqdn=False, localname=None, facility=None, cookies=None, config=None):
|
2019-01-22 15:43:03 +01:00
|
|
|
super().__init__()
|
|
|
|
self.fqdn = fqdn
|
|
|
|
self.localname = localname
|
|
|
|
self.facility = facility
|
|
|
|
self.cookies = cookies or {}
|
|
|
|
self.url = "https://logs-01.loggly.com/inputs/{token}/tag/{tag}".format(
|
|
|
|
token=utils.deobfuscate(loggly_token), tag='lbrynet-' + __version__
|
|
|
|
)
|
2019-10-04 15:40:41 +02:00
|
|
|
self._loop = asyncio.get_event_loop()
|
|
|
|
self._session = aiohttp.ClientSession()
|
2020-02-20 18:27:39 +01:00
|
|
|
self._config: typing.Optional['Config'] = config
|
2020-02-18 22:57:52 +01:00
|
|
|
|
|
|
|
@property
|
|
|
|
def enabled(self):
|
2020-02-20 18:27:39 +01:00
|
|
|
return self._config and self._config.share_usage_data
|
2019-01-22 15:43:03 +01:00
|
|
|
|
2020-01-03 07:39:34 +01:00
|
|
|
@staticmethod
|
|
|
|
def get_full_message(record):
|
2019-01-22 15:43:03 +01:00
|
|
|
if record.exc_info:
|
|
|
|
return '\n'.join(traceback.format_exception(*record.exc_info))
|
|
|
|
else:
|
|
|
|
return record.getMessage()
|
|
|
|
|
2019-10-04 15:40:41 +02:00
|
|
|
async def _emit(self, record, retry=True):
|
|
|
|
data = self.format(record).encode()
|
2019-08-21 19:28:12 +02:00
|
|
|
try:
|
2019-10-04 15:40:41 +02:00
|
|
|
async with self._session.post(self.url, data=data,
|
|
|
|
cookies=self.cookies) as response:
|
2019-08-21 19:28:12 +02:00
|
|
|
self.cookies.update(response.cookies)
|
|
|
|
except ClientError:
|
2020-02-18 22:57:52 +01:00
|
|
|
if self._loop.is_running() and retry and self.enabled:
|
2019-10-04 15:40:41 +02:00
|
|
|
await self._session.close()
|
|
|
|
self._session = aiohttp.ClientSession()
|
|
|
|
return await self._emit(record, retry=False)
|
2019-01-22 15:43:03 +01:00
|
|
|
|
|
|
|
def emit(self, record):
|
2020-02-18 22:57:52 +01:00
|
|
|
if not self.enabled:
|
|
|
|
return
|
2020-01-12 22:11:44 +01:00
|
|
|
try:
|
|
|
|
asyncio.ensure_future(self._emit(record), loop=self._loop)
|
|
|
|
except RuntimeError: # TODO: use a second loop
|
|
|
|
print(f"\nfailed to send traceback to loggly, please file an issue with the following traceback:\n"
|
|
|
|
f"{self.format(record)}")
|
2019-01-22 15:43:03 +01:00
|
|
|
|
2019-10-16 17:49:42 +02:00
|
|
|
def close(self):
|
|
|
|
super().close()
|
2019-10-26 19:33:43 +02:00
|
|
|
try:
|
|
|
|
loop = asyncio.get_event_loop()
|
|
|
|
loop.run_until_complete(self._session.close())
|
|
|
|
except RuntimeError:
|
|
|
|
pass
|
2019-10-16 17:49:42 +02:00
|
|
|
|
2019-01-22 15:43:03 +01:00
|
|
|
|
2020-02-20 18:27:39 +01:00
|
|
|
def get_loggly_handler(config):
|
|
|
|
handler = HTTPSLogglyHandler(LOGGLY_TOKEN, config=config)
|
2019-01-22 15:43:03 +01:00
|
|
|
handler.setFormatter(JsonFormatter())
|
|
|
|
return handler
|