# -*- coding: utf-8 -*- from typing import Optional import logging import logging.config import os import traceback from primordial.log.data import LogData from primordial.constants import IP LOG = logging.getLogger(__name__) class ConfigLogData(LogData): """Store configuration log data for passing to other logging classes and easy retrieval.""" TYPE_FIELD = 'type' SUB_TYPE_FIELD = 'sub_type' DATACENTER_FIELD = 'datacenter' ENVIRONMENT_FIELD = 'environment' FIELDS = (TYPE_FIELD, SUB_TYPE_FIELD, DATACENTER_FIELD, ENVIRONMENT_FIELD) DEFAULT_TYPE = 'hfs' DEFAULT_SUB_TYPE = 'vhfs' DEFAULT_DATACENTER = 'local' DEFAULT_ENVIRONMENT = 'LOCAL' def __init__(self) -> None: super().__init__() self.set(self.TYPE_FIELD, self.DEFAULT_TYPE) self.set(self.SUB_TYPE_FIELD, self.DEFAULT_SUB_TYPE) self.set(self.DATACENTER_FIELD, self.DEFAULT_DATACENTER) self.set(self.ENVIRONMENT_FIELD, self.DEFAULT_ENVIRONMENT) class PayloadLogData(LogData): """Extract and store payload log data for parsing and easy retrieval.""" DATA_SCHEMA_VERSION = '1.0.0' LINENO_FIELD = 'lineno' RAW_FIELDS = (LINENO_FIELD,) def __init__(self, record: Optional[logging.LogRecord] = None) -> None: self.freefields = True super().__init__(record) def load(self, record: logging.LogRecord) -> None: super().load(record) self.set('msg', record.getMessage()) self.set('pathname', record.pathname) self.set('class_name', None) self.set('module', record.module) self.set('filename', record.filename) self.set('func_name', record.funcName) self.set(self.LINENO_FIELD, record.lineno) self.set('version', self.DATA_SCHEMA_VERSION) if record.exc_info: exc_type, exc_value, exc_traceback = record.exc_info self.set('strace', ''.join( traceback.format_exception(exc_type, exc_value, exc_traceback))) class ServiceLogData(LogData): """Extract and store service log data for parsing and easy retrieval.""" NAME_FIELD = 'name' THREAD_FIELD = 'thread' FIELDS = (NAME_FIELD, THREAD_FIELD) def load(self, record: logging.LogRecord) -> None: super().load(record) self.set(self.NAME_FIELD, os.getenv('SYSLOG_IDENT') or record.processName) self.set(self.THREAD_FIELD, str(record.thread)) class HostLogData(LogData): """Extract and store host log data for parsing and easy retrieval.""" SERVICE_FIELD = 'service' HOSTNAME_FIELD = 'hostname' IP_FIELD = 'ip' FIELDS = (HOSTNAME_FIELD, IP_FIELD, SERVICE_FIELD) def load(self, record: logging.LogRecord) -> None: super().load(record) self.set(self.HOSTNAME_FIELD, os.getenv('HOSTNAME')) self.set(self.IP_FIELD, IP) serviceLogData = ServiceLogData(record) self.set(self.SERVICE_FIELD, serviceLogData) class EnvelopeRole(LogData): """Store log role (e.g. ''PERFORMANCE' ) for passing to other classes and easy retrieval.""" ROLE_FIELD = 'role' ROLE_DEVELOPMENT = 'DEVELOPMENT' ROLE_PERFORMANCE = 'PERFORMANCE' ROLE_BUSINESS_ANALYTICS = 'BUSINESS_ANALYTICS' FIELDS = (ROLE_FIELD,) DEFAULT_ROLE = ROLE_DEVELOPMENT def __init__(self) -> None: super().__init__() self.set(self.ROLE_FIELD, self.DEFAULT_ROLE) def __str__(self) -> str: return str(self.get(self.ROLE_FIELD)) __repr__ = __str__ class EnvelopeVersion(LogData): """Store Envelope version (e.g. '1.0.0') for passing to other classes and easy retrieval.""" MAJOR_FIELD = 'major' MINOR_FIELD = 'minor' PATCH_FIELD = 'patch' FIELDS = (MAJOR_FIELD, MINOR_FIELD, PATCH_FIELD) RAW_FIELDS = FIELDS DEFAULT_MAJOR = 1 DEFAULT_MINOR = 0 DEFAULT_PATCH = 0 def __init__(self) -> None: super().__init__() self.set(self.MAJOR_FIELD, self.DEFAULT_MAJOR) self.set(self.MINOR_FIELD, self.DEFAULT_MINOR) self.set(self.PATCH_FIELD, self.DEFAULT_PATCH) def __str__(self) -> str: return str(".".join([str(self.get(field)) for field in self.FIELDS])) __repr__ = __str__ @staticmethod def fromString(version: str) -> 'EnvelopeVersion': major, minor, patch = map(int, version.split(".")) envelopeVersion = EnvelopeVersion() envelopeVersion.set(EnvelopeVersion.MAJOR_FIELD, major) envelopeVersion.set(EnvelopeVersion.MINOR_FIELD, minor) envelopeVersion.set(EnvelopeVersion.PATCH_FIELD, patch) return envelopeVersion class EnvelopeDataSchema(LogData): """Store Envelope data schema version (e.g. '1.0.0') for passing to other classes and easy retrieval.""" NAME_FIELD = 'name' MAJOR_FIELD = 'major' MINOR_FIELD = 'minor' PATCH_FIELD = 'patch' VERSION_SEPARATOR = '.' NAME_VERSION_SEPARATOR = '-' FIELDS = (NAME_FIELD, MAJOR_FIELD, MINOR_FIELD, PATCH_FIELD) RAW_FIELDS = FIELDS DEFAULT_NAME = 'default' DEFAULT_MAJOR = 1 DEFAULT_MINOR = 0 DEFAULT_PATCH = 0 def __init__(self) -> None: super().__init__() self.set(self.NAME_FIELD, self.DEFAULT_NAME) self.set(self.MAJOR_FIELD, self.DEFAULT_MAJOR) self.set(self.MINOR_FIELD, self.DEFAULT_MINOR) self.set(self.PATCH_FIELD, self.DEFAULT_PATCH) def __str__(self) -> str: version = str( self.VERSION_SEPARATOR.join( [str(self.get(field)) for field in (self.MAJOR_FIELD, self.MINOR_FIELD, self.PATCH_FIELD)])) return str(self.NAME_VERSION_SEPARATOR.join([self.get(self.NAME_FIELD), version])) __repr__ = __str__ @staticmethod def fromString(data_schema: str) -> 'EnvelopeDataSchema': name, version = map(str, data_schema.split(EnvelopeDataSchema.NAME_VERSION_SEPARATOR)) major, minor, patch = map(int, version.split(EnvelopeDataSchema.VERSION_SEPARATOR)) envelopeDataSchema = EnvelopeDataSchema() envelopeDataSchema.set(EnvelopeDataSchema.NAME_FIELD, name) envelopeDataSchema.set(EnvelopeDataSchema.MAJOR_FIELD, major) envelopeDataSchema.set(EnvelopeDataSchema.MINOR_FIELD, minor) envelopeDataSchema.set(EnvelopeDataSchema.PATCH_FIELD, patch) return envelopeDataSchema