Răsfoiți Sursa

Add some fixes.

Cixo Develop 1 săptămână în urmă
părinte
comite
7fe407d3be

+ 4 - 0
.gitignore

@@ -1,3 +1,7 @@
+# ---> Logs
+*.log
+logs/
+
 # ---> Python
 # Byte-compiled / optimized / DLL files
 __pycache__/

+ 40 - 1
README.md

@@ -1,3 +1,42 @@
 # cx-logger
 
-This is simple thread-safe logger for Python.
+That is really easy to use automatic logger. To start using it in app just
+install it.
+
+```bash
+pip install cx-logger
+```
+
+When library had been installed, import it. All code snippets above would use that import.
+
+```python
+import cx_logger as logger
+```
+
+How create log directory? That is really simple, just type.
+
+```python
+import cx_logger as logger
+import pathlib
+
+manager = logger.logs_manager(pathlib.Path("./logs"))
+logging = manager.get_logger(logger.sync_logger)
+
+logging.use_handler(logger.stderr_handler())
+
+logging.info("That is only info.")
+logging.warning("Oh, that's warning!!!")
+```
+
+After that operation You would see something like that in stderr.
+
+```
+[info] 2025-10-23 14:12:12 That is only info.
+[warning] 2025-10-23 14:12:12 Oh, that's warning!!!
+```
+
+Directory ./logs would be created if not already exists, and in it You
+would see somethind like "2025-10-23-1.log". When You run script twice, then second file would be named like "2025-10-23-2.log".
+
+### More info
+ * See in the [wiki](https://git.cixoelectronic.pl/cixo-electronic/cx-logger/wiki/_pages)

+ 4 - 1
pyproject.toml

@@ -2,9 +2,12 @@
 requires = [ "setuptools >= 77.0.3" ]
 build-backend = "setuptools.build_meta"
 
+[tool.setuptools.packages.find]
+where = [ "source" ]
+
 [project]
 name = "cx-logger"
-version = "2025.10.23"
+version = "2025.10.23-1"
 requires-python = ">= 3.7"
 
 readme = "README.md"

+ 0 - 9
source/__init__.py

@@ -1,9 +0,0 @@
-from .handler import handler
-from .stdout_handler import stdout_handler
-from .stderr_handler import stderr_handler
-from .file_handler import file_handler
-from .levels import levels
-from .logger import logger
-from .async_logger import async_logger
-from .sync_logger import sync_logger
-from .logs_manager import logs_manager

+ 0 - 125
source/async_logger.py

@@ -1,125 +0,0 @@
-from .levels import levels
-from .handler import handler
-from .logger import logger
-
-class async_logger(logger):
-    """
-    That is logger, which use async methods to save data into handles.
-
-    Methods
-    -------
-    async info(content, *args, **kwargs)
-        That log info level message.
-
-    async warning(content, *args, **kwargs)
-        That log warning level message.
-
-    async error(content, *args, **kwargs)
-        That log error level message.
-
-    async critical(content, *args, **kwargs)
-        That log critical level message.
-
-    async log(level, content, *args, **kwargs)
-        That generally save content to log with given level.
-    """
-
-    async def info(self, content: str, *args, **kwargs) -> None:
-        """
-        That log info level message.
-
-        Parameters
-        ----------
-        content : str
-            Content to store in the log.
-
-        *args, **kwargs
-            When any of that parameters had been given, then format funcion
-            hed been used on the content.
-        """
-
-        await self.log(levels.info, content, *args, **kwargs)
-
-    async def warning(self, content: str, *args, **kwargs) -> None:
-        """
-        That log warning level message.
-
-        Parameters
-        ----------
-        content : str
-            Content to store in the log.
-
-        *args, **kwargs
-            When any of that parameters had been given, then format funcion
-            hed been used on the content.
-        """
-
-        await self.log(levels.warning, content, *args, **kwargs)
-
-    async def error(self, content: str, *args, **kwargs) -> None:
-        """
-        That log error level message.
-
-        Parameters
-        ----------
-        content : str
-            Content to store in the log.
-
-        *args, **kwargs
-            When any of that parameters had been given, then format funcion
-            hed been used on the content.
-        """
-
-        await self.log(levels.error, content, *args, **kwargs)
-
-    async def critical(self, content: str, *args, **kwargs) -> None:
-        """
-        That log critical level message.
-
-        Parameters
-        ----------
-        content : str
-            Content to store in the log.
-
-        *args, **kwargs
-            When any of that parameters had been given, then format funcion
-            hed been used on the content.
-        """
-
-        await self.log(levels.critical, content, *args, **kwargs)
-
-    async def log(self, level: levels, content: str, *args, **kwargs) -> None:
-        """
-        That log message, log level is given in the parameter.
-
-        Parameters
-        ----------
-        level : levels
-            Level of the message to save.
-        
-        content : str
-            Content to store in the log.
-
-        *args, **kwargs
-            When any of that parameters had been given, then format funcion
-            hed been used on the content.
-        """
-        
-        await self._write_to_all(
-            self._get_message(level, content, *args, **kwargs)
-        )
-    
-    async def _write_to_all(self, content: str) -> None:
-        """
-        That write content to all handlers.
-
-        Parameters
-        ----------
-        content : str
-            Content to been writen.
-        """
-
-        for handler in self._get_handlers():
-            await handler.adding(content) 
-
-

+ 0 - 67
source/file_handler.py

@@ -1,67 +0,0 @@
-import pathlib
-import os
-
-from .handler import handler
-
-class file_handler(handler):    
-    """
-    That handler puts log to file given when object was created.
-    """
-
-    def __init__(self, target: pathlib.Path) -> None:
-        """
-        That initialize new object with given file.
-
-        Parameters
-        ----------
-        target : pathlib.Path
-            File to use by handler.
-        """
-
-        super().__init__()
-
-        self.__target = target
-        self.__handler = None
-
-    def add(self, content: str) -> None:
-        """
-        That add new content to the file as new line.
-
-        Parameters
-        ----------
-        content : str
-            Content to add into the file as new line.
-        """
-
-        if not self.is_ready:
-            self.open()
-        
-        self.__handler.write(content + os.linesep)
-
-    @property
-    def is_ready(self) -> bool: 
-        """
-        That check that file handler is ready to use or not.
-        """
-
-        return self.__handler is not None and not self.__handler.closed
-
-    def open(self) -> None:
-        """
-        That open file and save handler to use in the future.
-        """
-
-        if not self.is_ready:
-            self.__handler = self.__target.open("a")
-
-    def clean(self) -> None:
-        """
-        That close file handler if it is open yet. 
-        """
-
-        if not self.is_ready:
-            return
-
-        self.__handler.close()
-
-

+ 0 - 67
source/handler.py

@@ -1,67 +0,0 @@
-import asyncio
-
-class handler:
-    """
-    That is class, which is used to implements new handlers. Handler is 
-    element, which directly store content to log. For example.
-    
-    To implement property handler, implement:
-     * add(str) <- Add new content to log,
-     * open() <- Optional function, create creatr handler for add,
-     * clean() <- Optional function, clean up resources user by handler.
-    """
-
-    def __init__(self) -> None:
-        """
-        That prepare lock for the hndler.
-        """
-
-        self.__lock = asyncio.Lock()
-    
-    def __del__(self) -> None:
-        """
-        That clean up handler when item is removed.
-        """
-
-        self.clean()
-
-    def open(self) -> None:
-        """
-        That register system resources for handler.
-        """
-
-        pass
-
-    async def adding(self, content: str) -> None:
-        """
-        That add new content to the the log as new line. It do that 
-        asynchronically.
-        
-        Parameters
-        ----------
-        content : str
-            Content which must be added to log.
-        """
-
-        async with self.__lock:
-            await asyncio.to_thread(self.add, content)
-
-    def add(self, content: str) -> None:
-        """
-        That add new content to the log as new line . It is virtual 
-        function, and must being overwritten.
-
-        Parameters
-        ----------
-        content : str
-            Content which must be added to log.
-        """
-
-        raise NotImplementedError()
-
-    def clean(self) -> None:
-        """
-        That clean up resources used by handler.
-        """
-
-        pass

+ 0 - 21
source/levels.py

@@ -1,21 +0,0 @@
-import enum
-
-class levels(enum.Enum):
-    """
-    That enum store log levels to use.
-    """
-
-    """ Info about any action. """
-    info = 0
-    
-    """ Simple warning. """
-    warning = 1
-
-    """ Not critical error. """
-    error = 2
-
-    """ Critical error. """
-    critical = 3
-
-
-

+ 0 - 129
source/logger.py

@@ -1,129 +0,0 @@
-import time
-
-from .handler import handler
-from .levels import levels 
-
-class logger:
-    """
-    That class is responsible for managing log handlers, and generating
-    log message. That formats log messages by adding time, date and also
-    level of the message.
-    """
-
-    def __init__(self) -> None:
-        """
-        That initialize handlers set.
-        """
-
-        self.__handlers = set()
-
-    def _get_handlers(self) -> tuple:   
-        """
-        That returns copy of the handlers list.
-        """
-
-        return tuple(self.__handlers)
-
-    def _get_message(
-        self, 
-        level: levels, 
-        content: str, 
-        *args, 
-        **kwargs
-    ) -> str:
-        """
-        That try to format log message. It require level of the message and 
-        also message itself. When it get only level and message itself, that
-        only add message to level and timestamp info. When more parameters
-        had been given that run format function on the first message. It is
-        useable when log message must contain for example IP address or
-        other things like that.
-
-        Parameters
-        ----------
-        level : levels
-            Log level of the message.
-
-        content : str
-            Content of the message to log.
-        
-        *args, **kwargs
-            Optional arguments used when format would be used.
-
-        Returns
-        -------
-        str
-            Result message which would be saved in the logs.
-        """
-
-        if len(args) > 0 or len(kwargs) > 0:
-            content = content.format(*args, **kwargs)
-
-        return ( \
-            self.__level_name(level) + " " + \
-            self.time_stamp + " " + \
-            content \
-        )
-
-    @property
-    def time_stamp(self) -> str:
-        """
-        That return current time as timestamp to use in log message.
-
-        Returns
-        -------
-        str
-            Current time as timestamp.
-        """
-
-        return time.strftime("%Y-%m-%d %H:%M:%S")
-
-    def __level_name(self, level: levels) -> str:
-        """
-        That convert level enum value into level stamp.
-
-        Parameters
-        ----------
-        level : levels
-            Level enum to convert.
-
-        Returns
-        -------
-        str
-            Result as string stamp.
-        """
-
-        name = ""
-
-        if level == levels.info:
-            name = "info"
-
-        if level == levels.warning:
-            name = "warning"
-
-        if level == levels.error:
-            name = "error"
-
-        if level == levels.critical:
-            name = "CRITICAL"
-
-        return ("[" + name + "]")
-
-    def use_handler(self, target: handler) -> object:
-        """
-        That add new handler to the handlers set.
-
-        Parameters
-        ----------
-        target : handler
-            New handler to add.
-        
-        Returns
-        -------
-            Self to chain loading.
-        """
-
-        self.__handlers.add(target)
-        return self
-
-

+ 0 - 170
source/logs_manager.py

@@ -1,170 +0,0 @@
-import pathlib
-import time
-import typing
-
-from .file_handler import file_handler
-from .async_logger import async_logger
-from .sync_logger import sync_logger
-from .logger import logger
-
-class logs_manager:
-    def __init__(self, target: pathlib.Path | None = None) -> None:
-        """
-        That create new logs manager. It require directory, where logs would
-        be stored.
-
-        Parameters
-        ----------
-        target : pathlib.Path
-        """
-
-        if target is None:
-            target = pathlib.Path("./logs")
-
-        if not target.is_dir():
-            target.mkdir()
-
-        self.__root = target
-
-    @staticmethod
-    def _ends_with(name: str, ending: str) -> bool:
-        """
-        That check name, and returh True when ends with ending.
-
-        Parameters
-        ----------
-        name : str
-            Name to check.
-
-        ending : str
-            Ending to check that name ends with.
-
-        Returns
-        -------
-        bool   
-            True when name ends with ending.
-        """
-
-        return name[-len(ending):] == ending
-
-    @property
-    def root(self) -> pathlib.Path:
-        """
-        Logs directory.
-        """
-
-        return self.__root
-
-    @property
-    def logs(self) -> tuple:
-        """
-        That return tuple with all logs.
-        """
-
-        return tuple(self.iter_logs())
-
-    def iter_logs(self) -> typing.Iterator[pathlib.Path]:
-        """
-        That generator iterate all logs in the log directory.
-
-        Returns
-        -------
-        typing.Generator[pathlib.Path]
-            Log files.
-        """
-
-        for count in self.__root.iterdir():
-            if self._ends_with(count.name, ".log"):
-                yield self.__root / count
-
-    def search_log(self, name: str | None = None) -> tuple:
-        """
-        That search for log in the logs directory.
-
-        Parameters
-        ----------
-        name : str | None
-            Name to filter logs by. If none, current date.
-
-        Returns
-        -------
-        tuple
-            All logs for given name.
-        """
-
-        if name is None:
-            name = self._base_name
-
-        logs = self.iter_logs()
-        filtered = filter(lambda count: str(count).find(name) != -1, logs)
-
-        return tuple(filtered)
-
-    @property
-    def _base_name(self) -> str:
-        """
-        That return default base name for current date.
-
-        Returns
-        -------
-        str
-            Name for current date.
-        """
-
-        return time.strftime("%Y-%m-%d", time.localtime())
-    
-    def get_new_file(self) -> pathlib.Path:
-        """
-        That generate new log file handler.
-
-        Returns
-        -------
-        pathlib.Path
-            New file handler.
-        """
-
-        base_name = self._base_name
-        name_logs = self.search_log(base_name)
-        name_count = len(name_logs)
-
-        while True:
-            result_name = (
-                base_name + "-" + \
-                str(name_count + 1) + ".log" \
-            )
-
-            result_path = self.root / pathlib.Path(result_name)
-
-            if not result_path.exists():
-                return result_path
-            
-            name_count = name_count + 1
-
-    def get_new_handler(self) -> file_handler:
-        """
-        That return handler to the new file.
-
-        Returns
-        -------
-        file_handler
-            That return new handler to the new log file.
-        """
-
-        return file_handler(self.get_new_file())
-
-    def get_logger(self, logger_type : type) -> logger:
-        """
-        That return new logger that use new log file.
-
-        Parameters
-        ----------
-        logger_type : type
-            Select async_logger or sync_logger.
-
-        Returns
-        -------
-        logger
-            New logger that use new log file
-        """
-
-        return logger_type().use_handler(self.get_new_handler()) 

+ 0 - 24
source/stderr_handler.py

@@ -1,24 +0,0 @@
-import sys
-import os
-
-from .handler import handler
-
-class stderr_handler(handler):
-    """
-    That handler simple put logs into stderr.
-    """
-
-    def add(self, content: str) -> None:
-        """
-        That put contewnt as new line in stderr.
-        
-        Parameters
-        ----------
-        content : str
-            Content to write as new line.
-        """
-
-        sys.stderr.write(content + os.linesep)
-
-
-

+ 0 - 23
source/stdout_handler.py

@@ -1,23 +0,0 @@
-import sys
-import os
-
-from .handler import handler
-
-class stdout_handler(handler):
-    """
-    That handler simple put logs into stdout.
-    """
-
-    def add(self, content: str) -> None:
-        """
-        That put content as new line into stdout.
-
-        Parameters
-        ----------
-        content : str
-            Content to write as new line.
-        """
-
-        sys.stdout.write(content + os.linesep)
-
-    

+ 0 - 122
source/sync_logger.py

@@ -1,122 +0,0 @@
-from .levels import levels
-from .handler import handler
-from .logger import logger
-
-class sync_logger(logger):
-    """
-    That is logger which use standard sync mode..
-
-    Methods
-    -------
-    info(content, *args, **kwargs)
-        That log info level message.
-
-    warning(content, *args, **kwargs)
-        That log warning level message.
-
-    error(content, *args, **kwargs)
-        That log error level message.
-
-    critical(content, *args, **kwargs)
-        That log critical level message.
-
-    log(level, content, *args, **kwargs)
-        That generally save content to log with given level.
-    """
-
-
-    def info(self, *args, **kwargs) -> None:
-        """
-        That log info level message.
-
-        Parameters
-        ----------
-        content : str
-            Content to store in the log.
-
-        *args, **kwargs
-            When any of that parameters had been given, then format funcion
-            hed been used on the content.
-        """
-        
-        self.log(levels.info, *args, **kwargs)
-
-    def warning(self, *args, **kwargs) -> None:
-        """
-        That log warning level message.
-
-        Parameters
-        ----------
-        content : str
-            Content to store in the log.
-
-        *args, **kwargs
-            When any of that parameters had been given, then format funcion
-            hed been used on the content.
-        """
-        
-        self.log(levels.warning, *args, **kwargs)
-  
-    def error(self, *args, **kwargs) -> None:
-        """
-        That log error level message.
-
-        Parameters
-        ----------
-        content : str
-            Content to store in the log.
-
-        *args, **kwargs
-            When any of that parameters had been given, then format funcion
-            hed been used on the content.
-        """
-
-        self.log(levels.error, *args, **kwargs)
-    
-    def critical(self, *args, **kwargs) -> None:
-        """
-        That log critical level message.
-
-        Parameters
-        ----------
-        content : str
-            Content to store in the log.
-
-        *args, **kwargs
-            When any of that parameters had been given, then format funcion
-            hed been used on the content.
-        """
-        
-        self.log(levels.critical, *args, **kwargs)
-
-    def log(self, level: levels, *args, **kwargs) -> None:
-        """
-        That log message, log level is given in the parameter.
-
-        Parameters
-        ----------
-        level : levels
-            Level of the message to save.
-        
-        content : str
-            Content to store in the log.
-
-        *args, **kwargs
-            When any of that parameters had been given, then format funcion
-            hed been used on the content.
-        """
-
-        self._write_to_all(self._get_message(level, *args, **kwargs))
-
-    def _write_to_all(self, content: str) -> None: 
-        """
-        That write content to all handlers.
-
-        Parameters
-        ----------
-        content : str
-            Content to been writen.
-        """
-
-        for handler in self._get_handlers():
-            handler.add(content)