Repository: celery/celery

Issue:
celery worker has --quiet to suppress banner output but celery beat does not
Sorry for leaving out the issue template but I believe this is fairly trivial and straight-forward.

In master, there is code to enable the suppressing of printing the banner when running `celery worker` with `--quiet`:
https://github.com/celery/celery/blob/9773eba837982c84380c93bd3788470273e7674d/celery/apps/worker.py#L138-L139

This conditional is not present in the code that runs `celery beat`:
https://github.com/celery/celery/blob/9773eba837982c84380c93bd3788470273e7674d/celery/apps/beat.py#L77-L78
https://github.com/celery/celery/blob/9773eba837982c84380c93bd3788470273e7674d/celery/apps/beat.py#L100

This causes a few issues for us because we expect all our services to only emit JSON.




Discussion:
do you have the time to send improvements?
I do, with a little guidance. Do I just need to add the `quiet` kwarg to `on_before_init` in `beat.py`? Or is there something more I need to do to make sure that I can figure out whether `--quiet` was passed or not?
ping :)
> I do, with a little guidance. Do I just need to add the `quiet` kwarg to `on_before_init` in `beat.py`? Or is there something more I need to do to make sure that I can figure out whether `--quiet` was passed or not?

you really need to dig the code to figure out that

Resolving patch:
diff --git a/celery/apps/beat.py b/celery/apps/beat.py
--- a/celery/apps/beat.py
+++ b/celery/apps/beat.py
@@ -44,7 +44,8 @@ def __init__(self, max_interval=None, app=None,
                  scheduler=None,
                  scheduler_cls=None,  # XXX use scheduler
                  redirect_stdouts=None,
-                 redirect_stdouts_level=None, **kwargs):
+                 redirect_stdouts_level=None,
+                 quiet=False, **kwargs):
         self.app = app = app or self.app
         either = self.app.either
         self.loglevel = loglevel
@@ -56,6 +57,7 @@ def __init__(self, max_interval=None, app=None,
             'worker_redirect_stdouts', redirect_stdouts)
         self.redirect_stdouts_level = either(
             'worker_redirect_stdouts_level', redirect_stdouts_level)
+        self.quiet = quiet
 
         self.max_interval = max_interval
         self.socket_timeout = socket_timeout
@@ -70,8 +72,9 @@ def __init__(self, max_interval=None, app=None,
             self.loglevel = LOG_LEVELS[self.loglevel.upper()]
 
     def run(self):
-        print(str(self.colored.cyan(
-            f'celery beat v{VERSION_BANNER} is starting.')))
+        if not self.quiet:
+            print(str(self.colored.cyan(
+                f'celery beat v{VERSION_BANNER} is starting.')))
         self.init_loader()
         self.set_process_title()
         self.start_scheduler()
@@ -93,7 +96,8 @@ def start_scheduler(self):
             schedule_filename=self.schedule,
         )
 
-        print(self.banner(service))
+        if not self.quiet:
+            print(self.banner(service))
 
         self.setup_logging()
         if self.socket_timeout:
diff --git a/celery/bin/beat.py b/celery/bin/beat.py
--- a/celery/bin/beat.py
+++ b/celery/bin/beat.py
@@ -62,7 +62,8 @@ def beat(ctx, detach=False, logfile=None, pidfile=None, uid=None,
         maybe_drop_privileges(uid=uid, gid=gid)
 
     beat = partial(app.Beat,
-                   logfile=logfile, pidfile=pidfile, **kwargs)
+                   logfile=logfile, pidfile=pidfile,
+                   quiet=ctx.obj.quiet, **kwargs)
 
     if detach:
         with detached(logfile, pidfile, uid, gid, umask, workdir):
diff --git a/t/unit/bin/proj/scheduler.py b/t/unit/bin/proj/scheduler.py
new file mode 100644
--- /dev/null
+++ b/t/unit/bin/proj/scheduler.py
@@ -0,0 +1,6 @@
+from celery.beat import Scheduler
+
+
+class mScheduler(Scheduler):
+    def tick(self):
+        raise Exception


Test patch:
diff --git a/t/unit/bin/test_beat.py b/t/unit/bin/test_beat.py
new file mode 100644
--- /dev/null
+++ b/t/unit/bin/test_beat.py
@@ -0,0 +1,34 @@
+import pytest
+from click.testing import CliRunner
+
+from celery.app.log import Logging
+from celery.bin.celery import celery
+
+
+@pytest.fixture(scope='session')
+def use_celery_app_trap():
+    return False
+
+
+def test_cli(isolated_cli_runner: CliRunner):
+    Logging._setup = True  # To avoid hitting the logging sanity checks
+    res = isolated_cli_runner.invoke(
+        celery,
+        ["-A", "t.unit.bin.proj.app", "beat", "-S", "t.unit.bin.proj.scheduler.mScheduler"],
+        catch_exceptions=True
+    )
+    assert res.exit_code == 1, (res, res.stdout)
+    assert res.stdout.startswith("celery beat")
+    assert "Configuration ->" in res.stdout
+
+
+def test_cli_quiet(isolated_cli_runner: CliRunner):
+    Logging._setup = True  # To avoid hitting the logging sanity checks
+    res = isolated_cli_runner.invoke(
+        celery,
+        ["-A", "t.unit.bin.proj.app", "--quiet", "beat", "-S", "t.unit.bin.proj.scheduler.mScheduler"],
+        catch_exceptions=True
+    )
+    assert res.exit_code == 1, (res, res.stdout)
+    assert not res.stdout.startswith("celery beat")
+    assert "Configuration -> " not in res.stdout