8
8
9
9
@pytest .fixture
10
10
def otel_scout_handler ():
11
- with patch ("scout_apm_logging.handler.OTLPLogExporter" ), patch (
12
- "scout_apm_logging.handler.LoggerProvider"
13
- ), patch ("scout_apm_logging.handler.BatchLogRecordProcessor" ), patch (
11
+ # Reset class initialization state
12
+ ScoutOtelHandler .otel_handler = None
13
+
14
+ with patch ("scout_apm_logging.handler.scout_config" ) as mock_scout_config , patch (
15
+ "scout_apm_logging.handler.OTLPLogExporter"
16
+ ), patch ("scout_apm_logging.handler.LoggerProvider" ), patch (
17
+ "scout_apm_logging.handler.BatchLogRecordProcessor"
18
+ ), patch (
14
19
"scout_apm_logging.handler.Resource"
15
20
):
21
+
22
+ mock_scout_config .value .return_value = "test-ingest-key"
16
23
handler = ScoutOtelHandler (service_name = "test-service" )
17
- yield handler
24
+ # Force initialization
25
+ handler ._initialize ()
26
+ return handler
18
27
19
28
20
29
def test_init (otel_scout_handler ):
@@ -37,7 +46,7 @@ def test_emit_with_scout_request(mock_tracked_request, otel_scout_handler):
37
46
]
38
47
mock_tracked_request .instance .return_value = mock_request
39
48
40
- with patch .object (otel_scout_handler , "otel_handler" ) as mock_otel_handler :
49
+ with patch .object (ScoutOtelHandler , "otel_handler" ) as mock_otel_handler :
41
50
record = logging .LogRecord (
42
51
name = "test" ,
43
52
level = logging .INFO ,
@@ -72,7 +81,7 @@ def test_emit_when_scout_request_contains_operation(
72
81
mock_request .operation = MagicMock ().return_value = "Controller/foobar"
73
82
mock_tracked_request .instance .return_value = mock_request
74
83
75
- with patch .object (otel_scout_handler , "otel_handler" ) as mock_otel_handler :
84
+ with patch .object (ScoutOtelHandler , "otel_handler" ) as mock_otel_handler :
76
85
record = logging .LogRecord (
77
86
name = "test" ,
78
87
level = logging .INFO ,
@@ -84,18 +93,18 @@ def test_emit_when_scout_request_contains_operation(
84
93
)
85
94
otel_scout_handler .emit (record )
86
95
87
- mock_otel_handler .emit .assert_called_once ()
88
- assert record .scout_request_id == "test-id"
89
- assert record .scout_start_time == "2024-03-06T12:00:00"
90
- assert record .scout_end_time == "2024-03-06T12:00:01"
91
- assert record .scout_tag_key == "value"
92
- assert record .controller_entrypoint == "foobar"
96
+ mock_otel_handler .emit .assert_called_once ()
97
+ assert record .scout_request_id == "test-id"
98
+ assert record .scout_start_time == "2024-03-06T12:00:00"
99
+ assert record .scout_end_time == "2024-03-06T12:00:01"
100
+ assert record .scout_tag_key == "value"
101
+ assert record .controller_entrypoint == "foobar"
93
102
94
103
95
104
@patch ("scout_apm_logging.handler.TrackedRequest" )
96
105
def test_emit_without_scout_request (mock_tracked_request , otel_scout_handler ):
97
106
mock_tracked_request .instance .return_value = None
98
- with patch .object (otel_scout_handler , "otel_handler" ) as mock_otel_handler :
107
+ with patch .object (ScoutOtelHandler , "otel_handler" ) as mock_otel_handler :
99
108
record = logging .LogRecord (
100
109
name = "test" ,
101
110
level = logging .INFO ,
@@ -112,7 +121,7 @@ def test_emit_without_scout_request(mock_tracked_request, otel_scout_handler):
112
121
113
122
114
123
def test_emit_already_handling_log (otel_scout_handler ):
115
- with patch .object (otel_scout_handler , "otel_handler" ) as mock_otel_handler :
124
+ with patch .object (ScoutOtelHandler , "otel_handler" ) as mock_otel_handler :
116
125
# Simulate that we're already handling a log message
117
126
otel_scout_handler ._handling_log .value = True
118
127
@@ -132,35 +141,6 @@ def test_emit_already_handling_log(otel_scout_handler):
132
141
otel_scout_handler ._handling_log .value = False
133
142
134
143
135
- def test_emit_exception_handling (otel_scout_handler ):
136
- with patch (
137
- "scout_apm_logging.handler.TrackedRequest"
138
- ) as mock_tracked_request , patch (
139
- "sys.stdout" , new_callable = io .StringIO
140
- ) as mock_stdout :
141
-
142
- mock_tracked_request .instance .side_effect = Exception ("Test exception" )
143
-
144
- record = logging .LogRecord (
145
- name = "test" ,
146
- level = logging .INFO ,
147
- pathname = "" ,
148
- lineno = 0 ,
149
- msg = "Test message" ,
150
- args = (),
151
- exc_info = None ,
152
- )
153
-
154
- otel_scout_handler .emit (record )
155
-
156
- # Check that the exception was caught and the error message was printed
157
- assert (
158
- "Error in ScoutOtelHandler.emit: Test exception" in mock_stdout .getvalue ()
159
- )
160
-
161
- otel_scout_handler ._handling_log .value = False
162
-
163
-
164
144
def test_close (otel_scout_handler ):
165
145
with patch .object (otel_scout_handler .logger_provider , "shutdown" ) as mock_shutdown :
166
146
otel_scout_handler .close ()
@@ -195,3 +175,41 @@ def test_get_ingest_key_not_set(mock_scout_config, otel_scout_handler):
195
175
mock_scout_config .value .return_value = None
196
176
with pytest .raises (ValueError , match = "SCOUT_LOGS_INGEST_KEY is not set" ):
197
177
otel_scout_handler ._get_ingest_key ()
178
+
179
+
180
+ def test_initialize_only_once (otel_scout_handler ):
181
+ # First initialization happens in fixture
182
+ initial_service_name = otel_scout_handler .service_name
183
+
184
+ # Try to initialize again
185
+ otel_scout_handler ._initialize ()
186
+
187
+ # Service name should not change since second initialization should return early
188
+ assert otel_scout_handler .service_name == initial_service_name
189
+
190
+
191
+ def test_emit_handles_initialization_failure ():
192
+ with patch ("scout_apm_logging.handler.scout_config" ) as mock_scout_config :
193
+ mock_scout_config .value .return_value = (
194
+ None # This will cause _get_ingest_key to fail
195
+ )
196
+ ScoutOtelHandler .otel_handler = None
197
+
198
+ handler = ScoutOtelHandler (service_name = "test-service" )
199
+
200
+ with patch ("sys.stdout" , new_callable = io .StringIO ) as mock_stdout :
201
+ record = logging .LogRecord (
202
+ name = "test" ,
203
+ level = logging .INFO ,
204
+ pathname = "" ,
205
+ lineno = 0 ,
206
+ msg = "Test message" ,
207
+ args = (),
208
+ exc_info = None ,
209
+ )
210
+ handler .emit (record )
211
+
212
+ assert (
213
+ "Failed to initialize ScoutOtelHandler: "
214
+ "SCOUT_LOGS_INGEST_KEY is not set" in mock_stdout .getvalue ()
215
+ )
0 commit comments