Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
_handler.py342 linesDownload Raw Back to loguru
1import functools2import json3import multiprocessing4import os5import threading6from contextlib import contextmanager7from threading import Thread8 9from ._colorizer import Colorizer10from ._locks_machinery import create_handler_lock11 12 13def prepare_colored_format(format_, ansi_level):14    colored = Colorizer.prepare_format(format_)15    return colored, colored.colorize(ansi_level)16 17 18def prepare_stripped_format(format_):19    colored = Colorizer.prepare_format(format_)20    return colored.strip()21 22 23def memoize(function):24    return functools.lru_cache(maxsize=64)(function)25 26 27class Message(str):28    __slots__ = ("record",)29 30 31class Handler:32    def __init__(33        self,34        *,35        sink,36        name,37        levelno,38        formatter,39        is_formatter_dynamic,40        filter_,41        colorize,42        serialize,43        enqueue,44        multiprocessing_context,45        error_interceptor,46        exception_formatter,47        id_,48        levels_ansi_codes49    ):50        self._name = name51        self._sink = sink52        self._levelno = levelno53        self._formatter = formatter54        self._is_formatter_dynamic = is_formatter_dynamic55        self._filter = filter_56        self._colorize = colorize57        self._serialize = serialize58        self._enqueue = enqueue59        self._multiprocessing_context = multiprocessing_context60        self._error_interceptor = error_interceptor61        self._exception_formatter = exception_formatter62        self._id = id_63        self._levels_ansi_codes = levels_ansi_codes  # Warning, reference shared among handlers64 65        self._decolorized_format = None66        self._precolorized_formats = {}67        self._memoize_dynamic_format = None68 69        self._stopped = False70        self._lock = create_handler_lock()71        self._lock_acquired = threading.local()72        self._queue = None73        self._queue_lock = None74        self._confirmation_event = None75        self._confirmation_lock = None76        self._owner_process_pid = None77        self._thread = None78 79        if self._is_formatter_dynamic:80            if self._colorize:81                self._memoize_dynamic_format = memoize(prepare_colored_format)82            else:83                self._memoize_dynamic_format = memoize(prepare_stripped_format)84        else:85            if self._colorize:86                for level_name in self._levels_ansi_codes:87                    self.update_format(level_name)88            else:89                self._decolorized_format = self._formatter.strip()90 91        if self._enqueue:92            if self._multiprocessing_context is None:93                self._queue = multiprocessing.SimpleQueue()94                self._confirmation_event = multiprocessing.Event()95                self._confirmation_lock = multiprocessing.Lock()96            else:97                self._queue = self._multiprocessing_context.SimpleQueue()98                self._confirmation_event = self._multiprocessing_context.Event()99                self._confirmation_lock = self._multiprocessing_context.Lock()100            self._queue_lock = create_handler_lock()101            self._owner_process_pid = os.getpid()102            self._thread = Thread(103                target=self._queued_writer, daemon=True, name="loguru-writer-%d" % self._id104            )105            self._thread.start()106 107    def __repr__(self):108        return "(id=%d, level=%d, sink=%s)" % (self._id, self._levelno, self._name)109 110    @contextmanager111    def _protected_lock(self):112        """Acquire the lock, but fail fast if its already acquired by the current thread."""113        if getattr(self._lock_acquired, "acquired", False):114            raise RuntimeError(115                "Could not acquire internal lock because it was already in use (deadlock avoided). "116                "This likely happened because the logger was re-used inside a sink, a signal "117                "handler or a '__del__' method. This is not permitted because the logger and its "118                "handlers are not re-entrant."119            )120        self._lock_acquired.acquired = True121        try:122            with self._lock:123                yield124        finally:125            self._lock_acquired.acquired = False126 127    def emit(self, record, level_id, from_decorator, is_raw, colored_message):128        try:129            if self._levelno > record["level"].no:130                return131 132            if self._filter is not None:133                if not self._filter(record):134                    return135 136            if self._is_formatter_dynamic:137                dynamic_format = self._formatter(record)138 139            formatter_record = record.copy()140 141            if not record["exception"]:142                formatter_record["exception"] = ""143            else:144                type_, value, tb = record["exception"]145                formatter = self._exception_formatter146                lines = formatter.format_exception(type_, value, tb, from_decorator=from_decorator)147                formatter_record["exception"] = "".join(lines)148 149            if colored_message is not None and colored_message.stripped != record["message"]:150                colored_message = None151 152            if is_raw:153                if colored_message is None or not self._colorize:154                    formatted = record["message"]155                else:156                    ansi_level = self._levels_ansi_codes[level_id]157                    formatted = colored_message.colorize(ansi_level)158            elif self._is_formatter_dynamic:159                if not self._colorize:160                    precomputed_format = self._memoize_dynamic_format(dynamic_format)161                    formatted = precomputed_format.format_map(formatter_record)162                elif colored_message is None:163                    ansi_level = self._levels_ansi_codes[level_id]164                    _, precomputed_format = self._memoize_dynamic_format(dynamic_format, ansi_level)165                    formatted = precomputed_format.format_map(formatter_record)166                else:167                    ansi_level = self._levels_ansi_codes[level_id]168                    formatter, precomputed_format = self._memoize_dynamic_format(169                        dynamic_format, ansi_level170                    )171                    coloring_message = formatter.make_coloring_message(172                        record["message"], ansi_level=ansi_level, colored_message=colored_message173                    )174                    formatter_record["message"] = coloring_message175                    formatted = precomputed_format.format_map(formatter_record)176 177            else:178                if not self._colorize:179                    precomputed_format = self._decolorized_format180                    formatted = precomputed_format.format_map(formatter_record)181                elif colored_message is None:182                    ansi_level = self._levels_ansi_codes[level_id]183                    precomputed_format = self._precolorized_formats[level_id]184                    formatted = precomputed_format.format_map(formatter_record)185                else:186                    ansi_level = self._levels_ansi_codes[level_id]187                    precomputed_format = self._precolorized_formats[level_id]188                    coloring_message = self._formatter.make_coloring_message(189                        record["message"], ansi_level=ansi_level, colored_message=colored_message190                    )191                    formatter_record["message"] = coloring_message192                    formatted = precomputed_format.format_map(formatter_record)193 194            if self._serialize:195                formatted = self._serialize_record(formatted, record)196 197            str_record = Message(formatted)198            str_record.record = record199 200            with self._protected_lock():201                if self._stopped:202                    return203                if self._enqueue:204                    self._queue.put(str_record)205                else:206                    self._sink.write(str_record)207        except Exception:208            if not self._error_interceptor.should_catch():209                raise210            self._error_interceptor.print(record)211 212    def stop(self):213        with self._protected_lock():214            self._stopped = True215            if self._enqueue:216                if self._owner_process_pid != os.getpid():217                    return218                self._queue.put(None)219                self._thread.join()220                if hasattr(self._queue, "close"):221                    self._queue.close()222 223            self._sink.stop()224 225    def complete_queue(self):226        if not self._enqueue:227            return228 229        with self._confirmation_lock:230            self._queue.put(True)231            self._confirmation_event.wait()232            self._confirmation_event.clear()233 234    def tasks_to_complete(self):235        if self._enqueue and self._owner_process_pid != os.getpid():236            return []237        lock = self._queue_lock if self._enqueue else self._protected_lock()238        with lock:239            return self._sink.tasks_to_complete()240 241    def update_format(self, level_id):242        if not self._colorize or self._is_formatter_dynamic:243            return244        ansi_code = self._levels_ansi_codes[level_id]245        self._precolorized_formats[level_id] = self._formatter.colorize(ansi_code)246 247    @property248    def levelno(self):249        return self._levelno250 251    @staticmethod252    def _serialize_record(text, record):253        exception = record["exception"]254 255        if exception is not None:256            exception = {257                "type": None if exception.type is None else exception.type.__name__,258                "value": exception.value,259                "traceback": bool(exception.traceback),260            }261 262        serializable = {263            "text": text,264            "record": {265                "elapsed": {266                    "repr": record["elapsed"],267                    "seconds": record["elapsed"].total_seconds(),268                },269                "exception": exception,270                "extra": record["extra"],271                "file": {"name": record["file"].name, "path": record["file"].path},272                "function": record["function"],273                "level": {274                    "icon": record["level"].icon,275                    "name": record["level"].name,276                    "no": record["level"].no,277                },278                "line": record["line"],279                "message": record["message"],280                "module": record["module"],281                "name": record["name"],282                "process": {"id": record["process"].id, "name": record["process"].name},283                "thread": {"id": record["thread"].id, "name": record["thread"].name},284                "time": {"repr": record["time"], "timestamp": record["time"].timestamp()},285            },286        }287 288        return json.dumps(serializable, default=str, ensure_ascii=False) + "\n"289 290    def _queued_writer(self):291        message = None292        queue = self._queue293 294        # We need to use a lock to protect sink during fork.295        # Particularly, writing to stderr may lead to deadlock in child process.296        lock = self._queue_lock297 298        while True:299            try:300                message = queue.get()301            except Exception:302                with lock:303                    self._error_interceptor.print(None)304                continue305 306            if message is None:307                break308 309            if message is True:310                self._confirmation_event.set()311                continue312 313            with lock:314                try:315                    self._sink.write(message)316                except Exception:317                    self._error_interceptor.print(message.record)318 319    def __getstate__(self):320        state = self.__dict__.copy()321        state["_lock"] = None322        state["_lock_acquired"] = None323        state["_memoize_dynamic_format"] = None324        if self._enqueue:325            state["_sink"] = None326            state["_thread"] = None327            state["_owner_process"] = None328            state["_queue_lock"] = None329        return state330 331    def __setstate__(self, state):332        self.__dict__.update(state)333        self._lock = create_handler_lock()334        self._lock_acquired = threading.local()335        if self._enqueue:336            self._queue_lock = create_handler_lock()337        if self._is_formatter_dynamic:338            if self._colorize:339                self._memoize_dynamic_format = memoize(prepare_colored_format)340            else:341                self._memoize_dynamic_format = memoize(prepare_stripped_format)342 
codekingpro/portable-devtools · Team Ai