def __init__( self, api_url, api_version, tool_name, tool_version, auth_token=None, log_level_system=6, log_level_user=5, enabled=True, ): self.api_url = api_url self.logs_url = urlparse.urljoin(api_url, "logs") self.api_version = api_version self.tool_name = tool_name self.tool_version = tool_version self.log_level_system = log_level_system self.log_level_user = log_level_user self.enabled = enabled self.setup_log_levels() if enabled: self.request_manager = RequestManager(auth_token=auth_token) self.request_manager.start() super(MemexLogHandler, self).__init__()
class MemexLogHandler(logging.Handler): """Logging handler to use with Memex Artifact Storage API For more details, please see: http://docs.memexapi.apiary.io/ """ log = logging.getLogger("memex_logging.MemexLogHandler") _are_log_levels_set_up = False def __init__( self, api_url, api_version, tool_name, tool_version, auth_token=None, log_level_system=6, log_level_user=5, enabled=True, ): self.api_url = api_url self.logs_url = urlparse.urljoin(api_url, "logs") self.api_version = api_version self.tool_name = tool_name self.tool_version = tool_version self.log_level_system = log_level_system self.log_level_user = log_level_user self.enabled = enabled self.setup_log_levels() if enabled: self.request_manager = RequestManager(auth_token=auth_token) self.request_manager.start() super(MemexLogHandler, self).__init__() def emit(self, record): if self.enabled: if record.levelno in (self.log_level_system, self.log_level_user): document = self.to_document(record) self.send(document) def setup_log_levels(self): """Patch logging module to expose additional log level methods: system(), user() that receive well defined keyword arguments """ if self._are_log_levels_set_up: return def log( self_, description, level_no, type, privacy="public", inferred=False, workflow=None, activity=None, user_id=None, session_id=None, details=None, attribute_indexes=None, controls=None, ): extra = { "description": description, "type": type, "inferred": inferred, "privacy": privacy, "workflow": workflow, "activity": activity, "user_id": user_id, "session_id": session_id, "details": details, "attribute_indexes": attribute_indexes, "controls": controls, } self_._log(level_no, description, None, extra=extra) def log_system(self_, *args, **kwargs): return log(self_, level_no=self.log_level_system, type="SYSTEM", *args, **kwargs) def log_user(self_, *args, **kwargs): return log(self_, level_no=self.log_level_user, type="USER", *args, **kwargs) logging.addLevelName(self.log_level_system, "SYSTEM") logging.Logger.system = log_system logging.addLevelName(self.log_level_user, "USER") logging.Logger.user = log_user self._are_log_levels_set_up = True def to_document(self, record): document = { "key": str(uuid.uuid4()), "time": {"startedAt": int(calendar.timegm(time.gmtime()) * 1000)}, "action": {"type": record.type, "description": record.msg, "inferred": record.inferred}, "client": {"ipAddress": self.get_public_ip(), "userAgent": self.get_user_agent()}, "component": { "name": self.tool_name, "version": self.tool_version, "apiLanguage": "Python", "apiVersion": self.api_version, }, "acl": {"privacy": record.privacy}, } # Fill optional fields if provided if record.workflow is not None: document["action"]["workflow"] = record.workflow if record.activity is not None: document["action"]["activity"] = record.activity if record.user_id is not None: document["client"]["userId"] = record.user_id if record.session_id is not None: document["client"]["sessionId"] = record.session_id if record.details is not None: document["details"] = record.details if record.attribute_indexes is not None: document["attribute_indexes"] = record.attribute_indexes if record.privacy == "controlled": document["acl"]["controls"] = record.controls return document def send(self, document): try: data = json.dumps(document) except Exception as exc: self.log.error(exc) return request_kwargs = { "method": "POST", "url": self.logs_url, "headers": {"Content-Type": "application/json"}, "data": data, "timeout": 5, } self.request_manager.add_request(**request_kwargs) def get_public_ip(self): if not hasattr(self, "_public_ip"): # TODO: Maybe there is another way to do it? ip = requests.get("http://httpbin.org/ip").json()["origin"] self._public_ip = ip return self._public_ip def get_user_agent(self): if not hasattr(self, "_user_agent"): self._user_agent = default_user_agent() return self._user_agent