[PATCH 2 of 7] [cubicweb-ctl] backport --loglevel option of pyramid to all instance commands

Laurent Peuch cortex at worlddomination.be
Sun Sep 1 04:06:58 CEST 2019


# HG changeset patch
# User Laurent Peuch <cortex at worlddomination.be>
# Date 1558454897 -7200
#      Tue May 21 18:08:17 2019 +0200
# Node ID b533d93f38ee32f597c830adf70f661abeddb706
# Parent  a63c93f27994cbb440a0431c1809166216eaa712
[cubicweb-ctl] backport --loglevel option of pyramid to all instance commands

diff --git a/cubicweb/cwctl.py b/cubicweb/cwctl.py
--- a/cubicweb/cwctl.py
+++ b/cubicweb/cwctl.py
@@ -44,6 +44,8 @@ from cubicweb.cwconfig import CubicWebCo
 from cubicweb.toolsutils import Command, rm, create_dir, underline_title
 from cubicweb.__pkginfo__ import version as cw_version
 
+LOG_LEVELS = ('debug', 'info', 'warning', 'error')
+
 # don't check duplicated commands, it occurs when reloading site_cubicweb
 CWCTL = CommandLine('cubicweb-ctl', 'The CubicWeb swiss-knife.',
                     version=cw_version, check_duplicated_command=False)
@@ -126,6 +128,13 @@ class InstanceCommand(Command):
           'help': 'launch pdb on exception',
           }
          ),
+        ("loglevel",
+         {'type': 'choice', 'default': None, 'metavar': '<log level>',
+          'choices': LOG_LEVELS, 'short': 'l',
+          'help': 'allow to specify log level for debugging (choices: %s)'
+                  % (', '.join(LOG_LEVELS)),
+          }
+         ),
     )
     actionverb = None
 
@@ -136,6 +145,19 @@ class InstanceCommand(Command):
         appid = args[0]
         cmdmeth = getattr(self, '%s_instance' % self.name)
 
+        # debugmode=True is to force to have a StreamHandler used instead of
+        # writting the logs into a file in /tmp
+        self.cwconfig = cwcfg.config_for(appid, debugmode=True)
+
+        # by default loglevel is 'error' but we keep the default value to None
+        # because some subcommands (e.g: pyramid) can override the loglevel in
+        # certain situations if it's not explicitly set by the user and we want
+        # to detect that (the "None" case)
+        if self['loglevel'] is None:
+            init_cmdline_log_threshold(self.cwconfig, 'error')
+        else:
+            init_cmdline_log_threshold(self.cwconfig, self['loglevel'])
+
         try:
             status = cmdmeth(appid) or 0
         except (ExecutionError, ConfigurationError) as ex:
@@ -415,7 +437,6 @@ class DeleteInstanceCommand(Command):
     name = 'delete'
     arguments = '<instance>'
     min_args = max_args = 1
-    options = ()
 
     def run(self, args):
         """run the command with its specific arguments"""
@@ -590,14 +611,13 @@ class ListVersionsInstanceCommand(Instan
     name = 'versions'
 
     def versions_instance(self, appid):
-        config = cwcfg.config_for(appid)
         # should not raise error if db versions don't match fs versions
-        config.repairing = True
+        self.cwconfig.repairing = True
         # no need to load all appobjects and schema
-        config.quick_start = True
-        if hasattr(config, 'set_sources_mode'):
-            config.set_sources_mode(('migration',))
-        vcconf = config.repository().get_versions()
+        self.cwconfig.quick_start = True
+        if hasattr(self.cwconfig, 'set_sources_mode'):
+            self.cwconfig.set_sources_mode(('migration',))
+        vcconf = self.cwconfig.repository().get_versions()
         for key in sorted(vcconf):
             print(key + ': %s.%s.%s' % vcconf[key])
 
@@ -622,7 +642,7 @@ class ShellCommand(Command):
     arguments = '<instance> [batch command file(s)] [-- <script arguments>]'
     min_args = 1
     max_args = None
-    options = (
+    options = merge_options((
         ('system-only',
          {'short': 'S', 'action': 'store_true',
           'help': 'only connect to the system source when the instance is '
@@ -646,7 +666,7 @@ sources for migration will be automatica
           'group': 'local'
           }),
 
-    )
+    ) + InstanceCommand.options)
 
     def _get_mih(self, appid):
         """ returns migration context handler & shutdown function """
@@ -690,16 +710,14 @@ class RecompileInstanceCatalogsCommand(I
     """
     name = 'i18ninstance'
 
-    @staticmethod
-    def i18ninstance_instance(appid):
+    def i18ninstance_instance(self, appid):
         """recompile instance's messages catalogs"""
-        config = cwcfg.config_for(appid)
-        config.quick_start = True  # notify this is not a regular start
-        repo = config.repository()
-        if config._cubes is None:
+        self.cwconfig.quick_start = True  # notify this is not a regular start
+        repo = self.cwconfig.repository()
+        if self.cwconfig._cubes is None:
             # web only config
-            config.init_cubes(repo.get_cubes())
-        errors = config.i18ncompile()
+            self.cwconfig.init_cubes(repo.get_cubes())
+        errors = self.cwconfig.i18ncompile()
         if errors:
             print('\n'.join(errors))
 
@@ -747,14 +765,13 @@ class ConfigureInstanceCommand(InstanceC
 
     def configure_instance(self, appid):
         if self.config.param is not None:
-            appcfg = cwcfg.config_for(appid)
             for key, value in self.config.param.items():
                 try:
-                    appcfg.global_set_option(key, value)
+                    self.cwconfig.global_set_option(key, value)
                 except KeyError:
                     raise ConfigurationError(
-                        'unknown configuration key "%s" for mode %s' % (key, appcfg.name))
-            appcfg.save()
+                        'unknown configuration key "%s" for mode %s' % (key, self.cwconfig.name))
+            self.cwconfig.save()
 
 
 for cmdcls in (ListCommand,
diff --git a/cubicweb/pyramid/pyramidctl.py b/cubicweb/pyramid/pyramidctl.py
--- a/cubicweb/pyramid/pyramidctl.py
+++ b/cubicweb/pyramid/pyramidctl.py
@@ -35,7 +35,6 @@ import warnings
 
 from logilab.common.configuration import merge_options
 
-from cubicweb.cwconfig import CubicWebConfiguration as cwcfg
 from cubicweb.cwctl import CWCTL, InstanceCommand, init_cmdline_log_threshold
 from cubicweb.pyramid import wsgi_application_from_cwconfig
 from cubicweb.pyramid.config import get_random_secret_key
@@ -48,7 +47,6 @@ import waitress
 MAXFD = 1024
 
 DBG_FLAGS = ('RQL', 'SQL', 'REPO', 'HOOKS', 'OPS', 'SEC', 'MORE')
-LOG_LEVELS = ('debug', 'info', 'warning', 'error')
 
 
 def _generate_pyramid_ini_file(pyramid_ini_path):
@@ -110,12 +108,6 @@ class PyramidStartHandler(InstanceComman
         ('reload-interval',
          {'type': 'int', 'default': 1,
           'help': 'Interval, in seconds, between file modifications checks'}),
-        ('loglevel',
-         {'short': 'l', 'type': 'choice', 'metavar': '<log level>',
-          'default': None, 'choices': LOG_LEVELS,
-          'help': 'debug if -D is set, error otherwise; '
-                  'one of %s' % (LOG_LEVELS,),
-          }),
         ('dbglevel',
          {'type': 'multiple_choice', 'metavar': '<dbg level>',
           'default': None,
@@ -248,13 +240,10 @@ class PyramidStartHandler(InstanceComman
 
         autoreload = self['reload'] or self['debug']
 
-        # debugmode=True is to force to have a StreamHandler used instead of
-        # writting the logs into a file in /tmp
-        cwconfig = cwcfg.config_for(appid, debugmode=True)
-        filelist_path = os.path.join(cwconfig.apphome,
+        filelist_path = os.path.join(self.cwconfig.apphome,
                                      '.pyramid-reload-files.list')
 
-        pyramid_ini_path = os.path.join(cwconfig.apphome, "pyramid.ini")
+        pyramid_ini_path = os.path.join(self.cwconfig.apphome, "pyramid.ini")
         if not os.path.exists(pyramid_ini_path):
             _generate_pyramid_ini_file(pyramid_ini_path)
 
@@ -265,26 +254,28 @@ class PyramidStartHandler(InstanceComman
             _turn_sigterm_into_systemexit()
             self.debug('Running reloading file monitor')
             extra_files = [sys.argv[0]]
-            extra_files.extend(self.configfiles(cwconfig))
-            extra_files.extend(self.i18nfiles(cwconfig))
+            extra_files.extend(self.configfiles(self.cwconfig))
+            extra_files.extend(self.i18nfiles(self.cwconfig))
             self.install_reloader(
                 self['reload-interval'], extra_files,
                 filelist_path=filelist_path)
 
         if self['dbglevel']:
-            self['loglevel'] = 'debug'
             set_debug('|'.join('DBG_' + x.upper() for x in self['dbglevel']))
-        init_cmdline_log_threshold(cwconfig, self['loglevel'])
+
+        # if no loglevel is specified and --debug or --dbglevel are here, set log level at debug
+        if self['loglevel'] is None and (self['debug'] or self['dbglevel']):
+            init_cmdline_log_threshold(self.cwconfig, 'debug')
 
         app = wsgi_application_from_cwconfig(
-            cwconfig, profile=self['profile'],
+            self.cwconfig, profile=self['profile'],
             profile_output=self['profile-output'],
             profile_dump_every=self['profile-dump-every']
         )
 
-        host = cwconfig['interface']
-        port = cwconfig['port'] or 8080
-        url_scheme = ('https' if cwconfig['base-url'].startswith('https')
+        host = self.cwconfig['interface']
+        port = self.cwconfig['port'] or 8080
+        url_scheme = ('https' if self.cwconfig['base-url'].startswith('https')
                       else 'http')
         repo = app.application.registry['cubicweb.repository']
         warnings.warn(
diff --git a/cubicweb/test/unittest_cwctl.py b/cubicweb/test/unittest_cwctl.py
--- a/cubicweb/test/unittest_cwctl.py
+++ b/cubicweb/test/unittest_cwctl.py
@@ -108,8 +108,11 @@ class InstanceCommandTest(unittest.TestC
         self.CWCTL.register(_TestCommand)
         self.CWCTL.register(_TestFailCommand)
 
+        self.fake_config = MagicMock()
+        self.fake_config.global_set_option = MagicMock()
+
         # pretend that this instance exists
-        patcher = patch.object(cwcfg, 'config_for', return_value=object())
+        patcher = patch.object(cwcfg, 'config_for', return_value=self.fake_config)
         patcher.start()
         self.addCleanup(patcher.stop)
 
@@ -164,6 +167,17 @@ class InstanceCommandTest(unittest.TestC
 
         test_fail_instance.assert_called_once()
 
+    def test_set_loglevel(self):
+        LOG_LEVELS = ('debug', 'info', 'warning', 'error')
+
+        for log_level in LOG_LEVELS:
+            with self.assertRaises(SystemExit) as cm:
+                self.CWCTL.run(["test", "some_instance", "--loglevel", log_level])
+            self.assertEqual(cm.exception.code, 0)
+
+            self.fake_config.global_set_option.assert_called_with('log-threshold',
+                                                                  log_level.upper())
+
 
 if __name__ == '__main__':
     unittest.main()
diff --git a/doc/changes/3.27.rst b/doc/changes/3.27.rst
--- a/doc/changes/3.27.rst
+++ b/doc/changes/3.27.rst
@@ -20,6 +20,9 @@ New features
 * add a --pdb flag to all cubicweb-ctl command to launch (i)pdb if an exception
   occurs during a command execution.
 
+* the --loglevel flag is available for all cubicweb-ctl instance commands (and
+  not only the ``pyramid`` one)
+
 Backwards incompatible changes
 ------------------------------
 



More information about the cubicweb-devel mailing list