|
22 | 22 | from . import protos |
23 | 23 | from . import constants |
24 | 24 |
|
25 | | -from .logging import error_logger, logger |
| 25 | +from .logging import error_logger, logger, is_system_log_category |
| 26 | +from .logging import enable_console_logging, disable_console_logging |
26 | 27 | from .tracing import marshall_exception_trace |
27 | 28 | from .utils.wrappers import disable_feature_by |
28 | 29 |
|
@@ -115,13 +116,21 @@ async def dispatch_forever(self): |
115 | 116 | self._loop.set_task_factory( |
116 | 117 | lambda loop, coro: ContextEnabledTask(coro, loop=loop)) |
117 | 118 |
|
| 119 | + # Attach gRPC logging to the root logger |
118 | 120 | logging_handler = AsyncLoggingHandler() |
119 | 121 | root_logger = logging.getLogger() |
120 | 122 | root_logger.setLevel(logging.INFO) |
121 | 123 | root_logger.addHandler(logging_handler) |
| 124 | + |
| 125 | + # Since gRPC channel is established, should use it for logging |
| 126 | + disable_console_logging() |
| 127 | + logger.info('Detach console logging. Switch to gRPC logging') |
| 128 | + |
122 | 129 | try: |
123 | 130 | await forever |
124 | 131 | finally: |
| 132 | + # Reenable console logging when there's an exception |
| 133 | + enable_console_logging() |
125 | 134 | root_logger.removeHandler(logging_handler) |
126 | 135 | finally: |
127 | 136 | DispatcherMeta.__current_dispatcher__ = None |
@@ -155,10 +164,16 @@ def _on_logging(self, record: logging.LogRecord, formatted_msg: str): |
155 | 164 | else: |
156 | 165 | log_level = getattr(protos.RpcLog, 'None') |
157 | 166 |
|
| 167 | + if is_system_log_category(record.name): |
| 168 | + log_category = protos.RpcLog.RpcLogCategory.System |
| 169 | + else: |
| 170 | + log_category = protos.RpcLog.RpcLogCategory.User |
| 171 | + |
158 | 172 | log = dict( |
159 | 173 | level=log_level, |
160 | 174 | message=formatted_msg, |
161 | 175 | category=record.name, |
| 176 | + log_category=log_category |
162 | 177 | ) |
163 | 178 |
|
164 | 179 | invocation_id = get_current_invocation_id() |
@@ -310,12 +325,17 @@ async def _handle__invocation_request(self, req): |
310 | 325 | args[name] = bindings.Out() |
311 | 326 |
|
312 | 327 | if fi.is_async: |
| 328 | + logger.info('Function is async, request ID: %s,' |
| 329 | + 'function ID: %s, invocation ID: %s', |
| 330 | + self.request_id, function_id, invocation_id) |
313 | 331 | call_result = await fi.func(**args) |
314 | 332 | else: |
| 333 | + logger.info('Function is sync, request ID: %s,' |
| 334 | + 'function ID: %s, invocation ID: %s', |
| 335 | + self.request_id, function_id, invocation_id) |
315 | 336 | call_result = await self._loop.run_in_executor( |
316 | 337 | self._sync_call_tp, |
317 | 338 | self.__run_sync_func, invocation_id, fi.func, args) |
318 | | - |
319 | 339 | if call_result is not None and not fi.has_return: |
320 | 340 | raise RuntimeError( |
321 | 341 | f'function {fi.name!r} without a $return binding ' |
@@ -499,10 +519,10 @@ def gen(resp_queue): |
499 | 519 | class AsyncLoggingHandler(logging.Handler): |
500 | 520 |
|
501 | 521 | def emit(self, record): |
502 | | - if not record.name.startswith('azure_functions_worker'): |
503 | | - # Skip worker system logs |
504 | | - msg = self.format(record) |
505 | | - Dispatcher.current._on_logging(record, msg) |
| 522 | + # Since we disable console log after gRPC channel is initiated |
| 523 | + # We should redirect all the messages into dispatcher |
| 524 | + msg = self.format(record) |
| 525 | + Dispatcher.current._on_logging(record, msg) |
506 | 526 |
|
507 | 527 |
|
508 | 528 | class ContextEnabledTask(asyncio.Task): |
|
0 commit comments