Optimize loguru reporter plugin (#302)

* Optimize loguru reporter plugin

* update CHANGELOG.md

* fix support matrix

* fix support matrix and plugin doc

* fix message to be archived

---------

Co-authored-by: Superskyyy (AWAY - OFFLINE) <Superskyyy@outlook.com>
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 87ff06f..0f5811a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,9 @@
 - Feature:
   - Add a new workflow to push docker images for arm64 and amd64 (#297)
 
+- Plugins:
+  - Optimize loguru reporter plugin.(#302)
+
 - Fixes:
   - Fix sw8 loss when use aiohttp (#299, issue#10669)
   - **Critical**: Fix a bug that leads to high cpu usage (#300, issue#10672)
diff --git a/docs/en/setup/Plugins.md b/docs/en/setup/Plugins.md
index dc61b2b..cf4dac5 100644
--- a/docs/en/setup/Plugins.md
+++ b/docs/en/setup/Plugins.md
@@ -31,7 +31,7 @@
 | [werkzeug](https://werkzeug.palletsprojects.com/) | Python >=3.7 - ['1.0.1', '2.0'];  | `sw_http_server` |
 | [httpx](https://www.python-httpx.org/) | Python >=3.7 - ['0.23.*', '0.22.*'];  | `sw_httpx` |
 | [kafka-python](https://kafka-python.readthedocs.io) | Python >=3.7 - ['2.0'];  | `sw_kafka` |
-| [loguru](https://pypi.org/project/loguru/) | Python >=3.7 - ['0.6.0'];  | `sw_loguru` |
+| [loguru](https://pypi.org/project/loguru/) | Python >=3.7 - ['0.6.0', '0.7.0'];  | `sw_loguru` |
 | [mysqlclient](https://mysqlclient.readthedocs.io/) | Python >=3.7 - ['2.1.*'];  | `sw_mysqlclient` |
 | [psycopg[binary]](https://www.psycopg.org/) | Python >=3.11 - ['3.1.*']; Python >=3.7 - ['3.0.18', '3.1.*'];  | `sw_psycopg` |
 | [psycopg2-binary](https://www.psycopg.org/) | Python >=3.10 - NOT SUPPORTED YET; Python >=3.7 - ['2.9'];  | `sw_psycopg2` |
diff --git a/skywalking/plugins/sw_loguru.py b/skywalking/plugins/sw_loguru.py
index 0adee84..8528b17 100644
--- a/skywalking/plugins/sw_loguru.py
+++ b/skywalking/plugins/sw_loguru.py
@@ -16,11 +16,7 @@
 #
 
 import logging
-import sys
 import traceback
-from multiprocessing import current_process
-from os.path import basename, splitext
-from threading import current_thread
 
 from skywalking import config
 from skywalking.agent import agent
@@ -33,136 +29,29 @@
 link_vector = ['https://pypi.org/project/loguru/']
 support_matrix = {
     'loguru': {
-        '>=3.7': ['0.6.0']
+        '>=3.7': ['0.6.0', '0.7.0']
     }
 }
 note = """"""
 
 
 def install():
-    from loguru import logger
-    from loguru._recattrs import RecordException, RecordFile, RecordLevel, RecordProcess, RecordThread
-    from loguru._datetime import aware_now
-    from loguru._get_frame import get_frame
-    from loguru._logger import start_time, context as logger_context, Logger
-    from types import MethodType
+    if not config.agent_log_reporter_active:
+        return
 
-    _log = logger._log
+    from loguru import logger
+
     log_reporter_level = logging.getLevelName(config.agent_log_reporter_level)  # type: int
 
-    def gen_record(self, level_id, static_level_no, from_decorator, options, message, args, kwargs):
-        """ Generate log record as loguru.logger._log """
-        core = self._core
+    def _sw_sink(message):
+        record = message.record
 
-        if not core.handlers:
-            return
-
-        (exception, depth, record, lazy, colors, raw, capture, patcher, extra) = options
-
-        frame = get_frame(depth + 2)
-
-        try:
-            name = frame.f_globals['__name__']
-        except KeyError:
-            name = None
-
-        try:
-            if not core.enabled[name]:
-                return
-        except KeyError:
-            enabled = core.enabled
-            if name is None:
-                status = core.activation_none
-                enabled[name] = status
-                if not status:
-                    return
-            else:
-                dotted_name = name + '.'
-                for dotted_module_name, status in core.activation_list:
-                    if dotted_name[: len(dotted_module_name)] == dotted_module_name:
-                        if status:
-                            break
-                        enabled[name] = False
-                        return
-                enabled[name] = True
-
-        current_datetime = aware_now()
-
-        if level_id is None:
-            level_icon = ' '
-            level_no = static_level_no
-            level_name = f'Level {level_no}'  # not really level name, just as loguru
-        else:
-            level_name, level_no, _, level_icon = core.levels[level_id]
-
-        if level_no < core.min_level:
-            return
-
-        code = frame.f_code
-        file_path = code.co_filename
-        file_name = basename(file_path)
-        thread = current_thread()
-        process = current_process()
-        elapsed = current_datetime - start_time
-
-        if exception:
-            if isinstance(exception, BaseException):
-                type_, value, traceback = (type(exception), exception, exception.__traceback__)
-            elif isinstance(exception, tuple):
-                type_, value, traceback = exception
-            else:
-                type_, value, traceback = sys.exc_info()
-            exception = RecordException(type_, value, traceback)
-        else:
-            exception = None
-
-        log_record = {
-            'elapsed': elapsed,
-            'exception': exception,
-            'extra': {**core.extra, **logger_context.get(), **extra},
-            'file': RecordFile(file_name, file_path),
-            'function': code.co_name,
-            'level': RecordLevel(level_name, level_no, level_icon),
-            'line': frame.f_lineno,
-            'message': str(message),
-            'module': splitext(file_name)[0],
-            'name': name,
-            'process': RecordProcess(process.ident, process.name),
-            'thread': RecordThread(thread.ident, thread.name),
-            'time': current_datetime,
-        }
-
-        if capture and kwargs:
-            log_record['extra'].update(kwargs)
-
-        if record:
-            kwargs.update(record=log_record)
-
-        if args or kwargs:
-            log_record['message'] = message.format(*args, **kwargs)
-
-        if core.patcher:
-            core.patcher(log_record)
-
-        if patcher:
-            patcher(log_record)
-
-        return log_record
-
-    def _sw_log(self, level_id, static_level_no, from_decorator, options, message, args, kwargs):
-        _log(level_id, static_level_no, from_decorator, options, message, args, kwargs)
-        record = gen_record(self, level_id, static_level_no, from_decorator, options, message, args, kwargs)
         if record is None:
             return
 
-        core = self._core
-
         if record['level'].no < log_reporter_level:
             return
 
-        if not config.agent_log_reporter_ignore_filter and record['level'].no < core.min_level:  # ignore filtered logs
-            return
-
         # loguru has only one logger. Use tags referring Python-Agent doc
         core_tags = [
             KeyStringValuePair(key='level', value=record['level'].name),
@@ -202,7 +91,7 @@
             body=LogDataBody(
                 type='text',
                 text=TextLog(
-                    text=sw_filter(message)
+                    text=sw_filter(record['message'])
                 )
             ),
             tags=tags,
@@ -221,8 +110,5 @@
 
         agent.archive_log(log_data)
 
-    # Bind _sw_log function to default logger instance.
-    bound_sw_log = MethodType(_sw_log, logger)
-    logger._log = bound_sw_log
-    # Bind _sw_log function to Logger class for new instance.
-    Logger._log = _sw_log
+    # Make sure any logged message by loguru is also sent to skywalking OAP
+    logger.add(_sw_sink)