|
33 | 33 | .. versionadded:: 1.15.0 |
34 | 34 | """ |
35 | 35 |
|
36 | | -from abc import ABC, abstractmethod |
37 | | -from logging import getLogger |
38 | | -from os import environ |
39 | | -from typing import Any, Optional, cast |
40 | | - |
| 36 | +from opentelemetry._logs._internal import ( |
| 37 | + Logger, |
| 38 | + LoggerProvider, |
| 39 | + NoOpLogger, |
| 40 | + NoOpLoggerProvider, |
| 41 | + get_logger, |
| 42 | + get_logger_provider, |
| 43 | + set_logger_provider, |
| 44 | +) |
41 | 45 | from opentelemetry._logs.severity import SeverityNumber, std_to_otel |
42 | | -from opentelemetry.context.context import Context |
43 | | -from opentelemetry.environment_variables import _OTEL_PYTHON_LOGGER_PROVIDER |
44 | | -from opentelemetry.util._once import Once |
45 | | -from opentelemetry.util._providers import _load_provider |
46 | | -from opentelemetry.util.types import Attributes |
47 | | - |
48 | | -_logger = getLogger(__name__) |
49 | | - |
50 | | - |
51 | | -class Logger(ABC): |
52 | | - """Handles emitting events and logs via `LogRecord`.""" |
53 | | - |
54 | | - def __init__( |
55 | | - self, |
56 | | - name: str, |
57 | | - version: Optional[str] = None, |
58 | | - schema_url: Optional[str] = None, |
59 | | - attributes: Optional[Attributes] = None, |
60 | | - ) -> None: |
61 | | - super().__init__() |
62 | | - self._name = name |
63 | | - self._version = version |
64 | | - self._schema_url = schema_url |
65 | | - self._attributes = attributes |
66 | | - |
67 | | - @abstractmethod |
68 | | - def is_enabled( |
69 | | - self, |
70 | | - severity_number: Optional[SeverityNumber] = None, |
71 | | - context: Optional[Context] = None, |
72 | | - ) -> bool: |
73 | | - """Returns True if the logger is enabled for given severity and context, False otherwise.""" |
74 | | - |
75 | | - @abstractmethod |
76 | | - def emit( |
77 | | - self, |
78 | | - name: str = None, |
79 | | - timestamp: Optional[int] = None, |
80 | | - observed_timestamp: Optional[int] = None, |
81 | | - severity_number: Optional[SeverityNumber] = None, |
82 | | - severity_text: Optional[str] = None, |
83 | | - context: Optional[Context] = None, |
84 | | - body: Optional[Any] = None, |
85 | | - attributes: Optional[Attributes] = None, |
86 | | - ) -> None: |
87 | | - """Emits a log record.""" |
88 | | - |
89 | | - |
90 | | -class NoOpLogger(Logger): |
91 | | - """The default Logger used when no Logger implementation is available. |
92 | | -
|
93 | | - All operations are no-op. |
94 | | - """ |
95 | | - |
96 | | - def is_enabled( |
97 | | - self, |
98 | | - severity_number: Optional[SeverityNumber] = None, |
99 | | - context: Optional[Context] = None, |
100 | | - ) -> bool: |
101 | | - return False |
102 | | - |
103 | | - def emit( |
104 | | - self, |
105 | | - name: str = None, |
106 | | - timestamp: Optional[int] = None, |
107 | | - observed_timestamp: Optional[int] = None, |
108 | | - severity_number: Optional[SeverityNumber] = None, |
109 | | - severity_text: Optional[str] = None, |
110 | | - context: Optional[Context] = None, |
111 | | - body: Optional[Any] = None, |
112 | | - attributes: Optional[Attributes] = None, |
113 | | - ) -> None: |
114 | | - pass |
115 | | - |
116 | | - |
117 | | -class ProxyLogger(Logger): |
118 | | - def __init__( # pylint: disable=super-init-not-called |
119 | | - self, |
120 | | - name: str, |
121 | | - version: Optional[str] = None, |
122 | | - schema_url: Optional[str] = None, |
123 | | - attributes: Optional[Attributes] = None, |
124 | | - ): |
125 | | - self._name = name |
126 | | - self._version = version |
127 | | - self._schema_url = schema_url |
128 | | - self._attributes = attributes |
129 | | - self._real_logger: Optional[Logger] = None |
130 | | - self._noop_logger = NoOpLogger(name) |
131 | | - |
132 | | - @property |
133 | | - def _logger(self) -> Logger: |
134 | | - if self._real_logger: |
135 | | - return self._real_logger |
136 | | - |
137 | | - if _LOGGER_PROVIDER: |
138 | | - self._real_logger = _LOGGER_PROVIDER.get_logger( |
139 | | - self._name, |
140 | | - self._version, |
141 | | - self._schema_url, |
142 | | - self._attributes, |
143 | | - ) |
144 | | - return self._real_logger |
145 | | - return self._noop_logger |
146 | | - |
147 | | - def is_enabled( |
148 | | - self, |
149 | | - severity_number: Optional[SeverityNumber] = None, |
150 | | - context: Optional[Context] = None, |
151 | | - ) -> bool: |
152 | | - return self._logger.is_enabled( |
153 | | - severity_number=severity_number, context=context |
154 | | - ) |
155 | | - |
156 | | - def emit( |
157 | | - self, |
158 | | - name: str = None, |
159 | | - timestamp: Optional[int] = None, |
160 | | - observed_timestamp: Optional[int] = None, |
161 | | - severity_number: Optional[SeverityNumber] = None, |
162 | | - severity_text: Optional[str] = None, |
163 | | - context: Optional[Context] = None, |
164 | | - body: Optional[Any] = None, |
165 | | - attributes: Optional[Attributes] = None, |
166 | | - ) -> None: |
167 | | - self._logger.emit( |
168 | | - name=name, |
169 | | - timestamp=timestamp, |
170 | | - observed_timestamp=observed_timestamp, |
171 | | - severity_number=severity_number, |
172 | | - severity_text=severity_text, |
173 | | - context=context, |
174 | | - body=body, |
175 | | - attributes=attributes, |
176 | | - ) |
177 | | - |
178 | | - |
179 | | -class LoggerProvider(ABC): |
180 | | - """ |
181 | | - LoggerProvider is the entry point of the API. It provides access to Logger instances. |
182 | | - """ |
183 | | - |
184 | | - @abstractmethod |
185 | | - def get_logger( |
186 | | - self, |
187 | | - name: str, |
188 | | - version: Optional[str] = None, |
189 | | - schema_url: Optional[str] = None, |
190 | | - attributes: Optional[Attributes] = None, |
191 | | - ) -> Logger: |
192 | | - """Returns a `Logger` for use by the given instrumentation library. |
193 | | -
|
194 | | - For any two calls it is undefined whether the same or different |
195 | | - `Logger` instances are returned, even for different library names. |
196 | | -
|
197 | | - This function may return different `Logger` types (e.g. a no-op logger |
198 | | - vs. a functional logger). |
199 | | -
|
200 | | - Args: |
201 | | - name: The name of the instrumenting module. |
202 | | - ``__name__`` may not be used as this can result in |
203 | | - different logger names if the loggers are in different files. |
204 | | - It is better to use a fixed string that can be imported where |
205 | | - needed and used consistently as the name of the logger. |
206 | | -
|
207 | | - This should *not* be the name of the module that is |
208 | | - instrumented but the name of the module doing the instrumentation. |
209 | | - E.g., instead of ``"requests"``, use |
210 | | - ``"opentelemetry.instrumentation.requests"``. |
211 | | -
|
212 | | - version: Optional. The version string of the |
213 | | - instrumenting library. Usually this should be the same as |
214 | | - ``importlib.metadata.version(instrumenting_library_name)``. |
215 | | -
|
216 | | - schema_url: Optional. Specifies the Schema URL of the emitted telemetry. |
217 | | - """ |
218 | | - |
219 | | - |
220 | | -class NoOpLoggerProvider(LoggerProvider): |
221 | | - """The default LoggerProvider used when no LoggerProvider implementation is available.""" |
222 | | - |
223 | | - def get_logger( |
224 | | - self, |
225 | | - name: str, |
226 | | - version: Optional[str] = None, |
227 | | - schema_url: Optional[str] = None, |
228 | | - attributes: Optional[Attributes] = None, |
229 | | - ) -> Logger: |
230 | | - """Returns a NoOpLogger.""" |
231 | | - return NoOpLogger( |
232 | | - name, version=version, schema_url=schema_url, attributes=attributes |
233 | | - ) |
234 | | - |
235 | | - |
236 | | -class ProxyLoggerProvider(LoggerProvider): |
237 | | - def get_logger( |
238 | | - self, |
239 | | - name: str, |
240 | | - version: Optional[str] = None, |
241 | | - schema_url: Optional[str] = None, |
242 | | - attributes: Optional[Attributes] = None, |
243 | | - ) -> Logger: |
244 | | - if _LOGGER_PROVIDER: |
245 | | - return _LOGGER_PROVIDER.get_logger( |
246 | | - name, |
247 | | - version=version, |
248 | | - schema_url=schema_url, |
249 | | - attributes=attributes, |
250 | | - ) |
251 | | - return ProxyLogger( |
252 | | - name, |
253 | | - version=version, |
254 | | - schema_url=schema_url, |
255 | | - attributes=attributes, |
256 | | - ) |
257 | | - |
258 | | - |
259 | | -_LOGGER_PROVIDER_SET_ONCE = Once() |
260 | | -_LOGGER_PROVIDER: Optional[LoggerProvider] = None |
261 | | -_PROXY_LOGGER_PROVIDER = ProxyLoggerProvider() |
262 | | - |
263 | | - |
264 | | -def get_logger_provider() -> LoggerProvider: |
265 | | - """Gets the current global :class:`~.LoggerProvider` object.""" |
266 | | - global _LOGGER_PROVIDER # pylint: disable=global-variable-not-assigned |
267 | | - if _LOGGER_PROVIDER is None: |
268 | | - if _OTEL_PYTHON_LOGGER_PROVIDER not in environ: |
269 | | - return _PROXY_LOGGER_PROVIDER |
270 | | - |
271 | | - logger_provider: LoggerProvider = _load_provider( # type: ignore |
272 | | - _OTEL_PYTHON_LOGGER_PROVIDER, "logger_provider" |
273 | | - ) |
274 | | - _set_logger_provider(logger_provider, log=False) |
275 | | - |
276 | | - # _LOGGER_PROVIDER will have been set by one thread |
277 | | - return cast("LoggerProvider", _LOGGER_PROVIDER) |
278 | | - |
279 | | - |
280 | | -def _set_logger_provider(logger_provider: LoggerProvider, log: bool) -> None: |
281 | | - def set_lp() -> None: |
282 | | - global _LOGGER_PROVIDER # pylint: disable=global-statement |
283 | | - _LOGGER_PROVIDER = logger_provider |
284 | | - |
285 | | - did_set = _LOGGER_PROVIDER_SET_ONCE.do_once(set_lp) |
286 | | - |
287 | | - if log and not did_set: |
288 | | - _logger.warning("Overriding of current LoggerProvider is not allowed") |
289 | | - |
290 | | - |
291 | | -def set_logger_provider(logger_provider: LoggerProvider) -> None: |
292 | | - """Sets the current global :class:`~.LoggerProvider` object. |
293 | | -
|
294 | | - This can only be done once, a warning will be logged if any further attempt |
295 | | - is made. |
296 | | - """ |
297 | | - _set_logger_provider(logger_provider, log=True) |
298 | | - |
299 | | - |
300 | | -def get_logger( |
301 | | - instrumenting_module_name: str, |
302 | | - instrumenting_library_version: str = "", |
303 | | - logger_provider: Optional[LoggerProvider] = None, |
304 | | - schema_url: Optional[str] = None, |
305 | | - attributes: Optional[Attributes] = None, |
306 | | -) -> "Logger": |
307 | | - """Returns a `Logger` for use within a python process. |
308 | | -
|
309 | | - This function is a convenience wrapper for |
310 | | - opentelemetry.sdk._logs.LoggerProvider.get_logger. |
311 | | -
|
312 | | - If logger_provider param is omitted the current configured one is used. |
313 | | - """ |
314 | | - if logger_provider is None: |
315 | | - logger_provider = get_logger_provider() |
316 | | - return logger_provider.get_logger( |
317 | | - instrumenting_module_name, |
318 | | - instrumenting_library_version, |
319 | | - schema_url, |
320 | | - attributes, |
321 | | - ) |
322 | | - |
323 | 46 |
|
324 | 47 | __all__ = [ |
325 | 48 | "Logger", |
326 | 49 | "LoggerProvider", |
327 | | - "LogRecord", |
328 | 50 | "NoOpLogger", |
329 | 51 | "NoOpLoggerProvider", |
330 | 52 | "get_logger", |
|
0 commit comments