Repository: celery/celery

Issue:
Ability to customize `Received task` message
- [X] I have checked the [issues list](https://github.com/celery/celery/issues?q=is%3Aissue+label%3A%22Issue+Type%3A+Enhancement%22+-label%3A%22Category%3A+Documentation%22)
  for similar or identical enhancement to an existing feature.
- [X] I have checked the [pull requests list](https://github.com/celery/celery/pulls?q=is%3Apr+label%3A%22Issue+Type%3A+Enhancement%22+-label%3A%22Category%3A+Documentation%22)
  for existing proposed enhancements.
- [X] I have checked the [commit log](https://github.com/celery/celery/commits/master)
  to find out if the if the same enhancement was already implemented in the
  master branch.
- [X] I have included all related issues and possible duplicate issues in this issue
      (If there are none, check this box anyway).

## Related Issues and Possible Duplicates

#### Related Issues

- None

#### Possible Duplicates

- None

# Brief Summary
Currently `LOG_SUCCESS` and friends allows customizing the messages, but `Received task` is fixed. It would be good for this to be customizable and include the same values in `extra` (i.e. use `celery.app.trace.info` rather than `logging.info`). I was thinking something like this:
```
info('Received task: %s', {
    'name': req.name,
    'id': req.id,
})
```

# Design

## Architectural Considerations
Should be a non-breaking change that only adds a customization point

## Proposed Behavior
Add `LOG_RECEIVED` so it can be customized as well

## Proposed UI/UX
N/A

## Diagrams
N/A

## Alternatives
None that I can think of



Discussion:
Hey @daveisfera :wave:,
Thank you for opening an issue. We will get back to you as soon as we can.
Also, check out our [Open Collective](https://opencollective.com/celery) and consider backing us - every little helps!

We also offer priority support for our sponsors.
If you require immediate assistance please consider sponsoring us.

Pull requests are welcome!

Resolving patch:
diff --git a/celery/app/trace.py b/celery/app/trace.py
--- a/celery/app/trace.py
+++ b/celery/app/trace.py
@@ -52,6 +52,11 @@
 
 logger = get_logger(__name__)
 
+#: Format string used to log task receipt.
+LOG_RECEIVED = """\
+Task %(name)s[%(id)s] received\
+"""
+
 #: Format string used to log task success.
 LOG_SUCCESS = """\
 Task %(name)s[%(id)s] succeeded in %(runtime)ss: %(return_value)s\
diff --git a/celery/worker/strategy.py b/celery/worker/strategy.py
--- a/celery/worker/strategy.py
+++ b/celery/worker/strategy.py
@@ -4,6 +4,7 @@
 from kombu.asynchronous.timer import to_timestamp
 
 from celery import signals
+from celery.app import trace as _app_trace
 from celery.exceptions import InvalidTaskError
 from celery.utils.imports import symbol_by_name
 from celery.utils.log import get_logger
@@ -148,7 +149,10 @@ def task_message_handler(message, body, ack, reject, callbacks,
             body=body, headers=headers, decoded=decoded, utc=utc,
         )
         if _does_info:
-            info('Received task: %s', req)
+            # Similar to `app.trace.info()`, we pass the formatting args as the
+            # `extra` kwarg for custom log handlers
+            context = {'id': req.id, 'name': req.name}
+            info(_app_trace.LOG_RECEIVED, context, extra={'data': context})
         if (req.expires or req.id in revoked_tasks) and req.revoked():
             return
 


Test patch:
diff --git a/t/unit/worker/test_strategy.py b/t/unit/worker/test_strategy.py
--- a/t/unit/worker/test_strategy.py
+++ b/t/unit/worker/test_strategy.py
@@ -1,3 +1,4 @@
+import logging
 from collections import defaultdict
 from contextlib import contextmanager
 from unittest.mock import ANY, Mock, patch
@@ -6,6 +7,7 @@
 from kombu.utils.limits import TokenBucket
 
 from celery import Task, signals
+from celery.app.trace import LOG_RECEIVED
 from celery.exceptions import InvalidTaskError
 from celery.utils.time import rate
 from celery.worker import state
@@ -142,12 +144,14 @@ def _context(self, sig,
         message = self.prepare_message(message)
         yield self.Context(sig, s, reserved, consumer, message)
 
-    def test_when_logging_disabled(self):
+    def test_when_logging_disabled(self, caplog):
+        # Capture logs at any level above `NOTSET`
+        caplog.set_level(logging.NOTSET + 1, logger="celery.worker.strategy")
         with patch('celery.worker.strategy.logger') as logger:
             logger.isEnabledFor.return_value = False
             with self._context(self.add.s(2, 2)) as C:
                 C()
-                logger.info.assert_not_called()
+        assert not caplog.records
 
     def test_task_strategy(self):
         with self._context(self.add.s(2, 2)) as C:
@@ -165,6 +169,33 @@ def test_callbacks(self):
             for callback in callbacks:
                 callback.assert_called_with(req)
 
+    def test_log_task_received(self, caplog):
+        caplog.set_level(logging.INFO, logger="celery.worker.strategy")
+        with self._context(self.add.s(2, 2)) as C:
+            C()
+        for record in caplog.records:
+            if record.msg == LOG_RECEIVED:
+                assert record.levelno == logging.INFO
+                break
+        else:
+            raise ValueError("Expected message not in captured log records")
+
+    def test_log_task_received_custom(self, caplog):
+        caplog.set_level(logging.INFO, logger="celery.worker.strategy")
+        custom_fmt = "CUSTOM MESSAGE"
+        with self._context(
+            self.add.s(2, 2)
+        ) as C, patch(
+            "celery.app.trace.LOG_RECEIVED", new=custom_fmt,
+        ):
+            C()
+        for record in caplog.records:
+            if record.msg == custom_fmt:
+                assert set(record.args) == {"id", "name"}
+                break
+        else:
+            raise ValueError("Expected message not in captured log records")
+
     def test_signal_task_received(self):
         callback = Mock()
         with self._context(self.add.s(2, 2)) as C: