|
14 | 14 |
|
15 | 15 | # pylint: disable=protected-access
|
16 | 16 | import logging
|
| 17 | +import os |
| 18 | +import time |
17 | 19 | import unittest
|
18 | 20 | from concurrent.futures import ThreadPoolExecutor
|
19 |
| -from unittest.mock import Mock |
| 21 | +from unittest.mock import Mock, patch |
20 | 22 |
|
21 | 23 | from opentelemetry.sdk import trace
|
22 |
| -from opentelemetry.sdk.logs import LogEmitterProvider, OTLPHandler |
23 |
| -from opentelemetry.sdk.logs.export import BatchLogProcessor, SimpleLogProcessor |
| 24 | +from opentelemetry.sdk.logs import ( |
| 25 | + LogData, |
| 26 | + LogEmitterProvider, |
| 27 | + LogRecord, |
| 28 | + OTLPHandler, |
| 29 | +) |
| 30 | +from opentelemetry.sdk.logs.export import ( |
| 31 | + BatchLogProcessor, |
| 32 | + ConsoleExporter, |
| 33 | + SimpleLogProcessor, |
| 34 | +) |
24 | 35 | from opentelemetry.sdk.logs.export.in_memory_log_exporter import (
|
25 | 36 | InMemoryLogExporter,
|
26 | 37 | )
|
27 | 38 | from opentelemetry.sdk.logs.severity import SeverityNumber
|
| 39 | +from opentelemetry.sdk.resources import Resource as SDKResource |
| 40 | +from opentelemetry.sdk.util.instrumentation import InstrumentationInfo |
| 41 | +from opentelemetry.trace import TraceFlags |
28 | 42 | from opentelemetry.trace.span import INVALID_SPAN_CONTEXT
|
29 | 43 |
|
30 | 44 |
|
@@ -254,3 +268,55 @@ def bulk_log_and_flush(num_logs):
|
254 | 268 |
|
255 | 269 | finished_logs = exporter.get_finished_logs()
|
256 | 270 | self.assertEqual(len(finished_logs), 2415)
|
| 271 | + |
| 272 | + |
| 273 | +class TestConsoleExporter(unittest.TestCase): |
| 274 | + def test_export(self): # pylint: disable=no-self-use |
| 275 | + """Check that the console exporter prints log records.""" |
| 276 | + log_data = LogData( |
| 277 | + log_record=LogRecord( |
| 278 | + timestamp=int(time.time() * 1e9), |
| 279 | + trace_id=2604504634922341076776623263868986797, |
| 280 | + span_id=5213367945872657620, |
| 281 | + trace_flags=TraceFlags(0x01), |
| 282 | + severity_text="WARN", |
| 283 | + severity_number=SeverityNumber.WARN, |
| 284 | + name="name", |
| 285 | + body="Zhengzhou, We have a heaviest rains in 1000 years", |
| 286 | + resource=SDKResource({"key": "value"}), |
| 287 | + attributes={"a": 1, "b": "c"}, |
| 288 | + ), |
| 289 | + instrumentation_info=InstrumentationInfo( |
| 290 | + "first_name", "first_version" |
| 291 | + ), |
| 292 | + ) |
| 293 | + exporter = ConsoleExporter() |
| 294 | + # Mocking stdout interferes with debugging and test reporting, mock on |
| 295 | + # the exporter instance instead. |
| 296 | + |
| 297 | + with patch.object(exporter, "out") as mock_stdout: |
| 298 | + exporter.export([log_data]) |
| 299 | + mock_stdout.write.assert_called_once_with( |
| 300 | + log_data.log_record.to_json() + os.linesep |
| 301 | + ) |
| 302 | + |
| 303 | + self.assertEqual(mock_stdout.write.call_count, 1) |
| 304 | + self.assertEqual(mock_stdout.flush.call_count, 1) |
| 305 | + |
| 306 | + def test_export_custom(self): # pylint: disable=no-self-use |
| 307 | + """Check that console exporter uses custom io, formatter.""" |
| 308 | + mock_record_str = Mock(str) |
| 309 | + |
| 310 | + def formatter(record): # pylint: disable=unused-argument |
| 311 | + return mock_record_str |
| 312 | + |
| 313 | + mock_stdout = Mock() |
| 314 | + exporter = ConsoleExporter(out=mock_stdout, formatter=formatter) |
| 315 | + log_data = LogData( |
| 316 | + log_record=LogRecord(), |
| 317 | + instrumentation_info=InstrumentationInfo( |
| 318 | + "first_name", "first_version" |
| 319 | + ), |
| 320 | + ) |
| 321 | + exporter.export([log_data]) |
| 322 | + mock_stdout.write.assert_called_once_with(mock_record_str) |
0 commit comments