File size: 5,615 Bytes
7ab470d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
"""
Tests for Loguru performance optimizations.

These tests verify:
- Lazy evaluation doesn't execute expensive operations when filtered
- Logger level filtering works correctly
- Performance characteristics of Loguru logging
"""

from pathlib import Path

from loguru import logger


class TestLoguruPerformance:
    """Test Loguru performance optimizations."""

    def test_lazy_evaluation_with_opt_lazy(self, tmp_path: Path):
        """Verify lazy evaluation doesn't execute expensive operations when filtered."""
        log_file = tmp_path / "lazy.log"
        logger.remove()
        logger.add(log_file, level="ERROR")  # Only ERROR and above

        expensive_call_count = 0

        def expensive_operation():
            nonlocal expensive_call_count
            expensive_call_count += 1
            return "expensive result"

        # This should NOT call expensive_operation() because level is INFO < ERROR
        logger.opt(lazy=True).info("Result: {}", expensive_operation)

        assert expensive_call_count == 0  # Not called!

        # This SHOULD call expensive_operation() because level is ERROR
        logger.opt(lazy=True).error("Error: {}", expensive_operation)

        assert expensive_call_count == 1  # Called once

    def test_log_level_filtering(self, tmp_path: Path):
        """Verify log level filtering works correctly."""
        log_file = tmp_path / "filtering.log"
        logger.remove()
        logger.add(log_file, level="WARNING")  # WARNING and above only

        logger.debug("Debug message")
        logger.info("Info message")
        logger.warning("Warning message")
        logger.error("Error message")

        content = log_file.read_text()

        # Should not contain DEBUG or INFO
        assert "Debug message" not in content
        assert "Info message" not in content

        # Should contain WARNING and ERROR
        assert "Warning message" in content
        assert "Error message" in content

    def test_string_formatting_overhead(self, tmp_path: Path):
        """Verify string formatting is efficient."""
        log_file = tmp_path / "formatting.log"
        logger.remove()
        logger.add(log_file, level="INFO")

        # Format strings should work efficiently
        for i in range(100):
            logger.info(f"Iteration {i}: Processing item")

        content = log_file.read_text()
        lines = content.strip().split("\n")

        # Should have 100 log entries
        assert len(lines) == 100

    def test_batch_logging_performance(self, tmp_path: Path):
        """Verify Loguru can handle batch logging efficiently."""
        log_file = tmp_path / "batch.log"
        logger.remove()
        logger.add(log_file, level="INFO")

        # Log 1000 messages rapidly
        for i in range(1000):
            logger.info(f"Batch message {i}")

        content = log_file.read_text()
        lines = content.strip().split("\n")

        assert len(lines) == 1000

    def test_logger_with_many_bindings(self, tmp_path: Path):
        """Verify logger performs well with many bound fields."""
        log_file = tmp_path / "bindings.log"
        logger.remove()
        logger.add(log_file, format="{message}", level="INFO")

        # Bind many fields
        bound_logger = logger.bind(
            field1="value1",
            field2="value2",
            field3="value3",
            field4="value4",
            field5="value5",
            request_id="test-123",
            user_id=456,
            session_id="session-789",
        )

        bound_logger.info("Message with many bindings")

        content = log_file.read_text()
        assert "Message with many bindings" in content

    def test_exception_logging_overhead(self, tmp_path: Path):
        """Verify exception logging doesn't significantly impact performance."""
        log_file = tmp_path / "exceptions.log"
        logger.remove()
        logger.add(log_file, level="ERROR")

        # Log multiple exceptions
        for i in range(10):
            try:
                raise ValueError(f"Test exception {i}")
            except ValueError:
                logger.exception(f"Caught exception {i}")

        content = log_file.read_text()

        # Should have logged all exceptions
        assert content.count("Caught exception") == 10

    def test_conditional_logging_performance(self, tmp_path: Path):
        """Verify conditional logging doesn't execute when disabled."""
        log_file = tmp_path / "conditional.log"
        logger.remove()
        logger.add(log_file, level="ERROR")

        call_count = 0

        def count_calls():
            nonlocal call_count
            call_count += 1
            return "result"

        # Info logs should not execute the function
        for _ in range(100):
            logger.opt(lazy=True).info("Value: {}", count_calls)

        assert call_count == 0  # Never called because INFO < ERROR

    def test_logger_disable_and_enable(self, tmp_path: Path):
        """Verify logger can be disabled and enabled efficiently."""
        log_file = tmp_path / "disable.log"
        handler_id = logger.add(log_file, level="INFO")

        # Log with handler enabled
        logger.info("Message 1")

        # Disable handler
        logger.remove(handler_id)
        logger.info("Message 2")  # Should not be logged

        # Re-enable handler
        logger.add(log_file, level="INFO")
        logger.info("Message 3")

        content = log_file.read_text()

        assert "Message 1" in content
        assert "Message 2" not in content
        assert "Message 3" in content