- 
                Notifications
    You must be signed in to change notification settings 
- Fork 234
added auto-instrumentation of Django management commands #644
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
          
     Closed
      
      
    
  
     Closed
                    Changes from all commits
      Commits
    
    
            Show all changes
          
          
            7 commits
          
        
        Select commit
          Hold shift + click to select a range
      
      693111a
              
                added auto-instrumentation of Django management commands
              
              
                beniwohli 12040e2
              
                use a list of commands to exclude instead of a true/false flag
              
              
                beniwohli d6c9cce
              
                fix import error
              
              
                beniwohli 593b5b1
              
                Merge branch 'master' into autoinstrument-django-commands
              
              
                beniwohli e975b45
              
                copied six.reraise into our compat module, and use it in command inst…
              
              
                beniwohli ebbf500
              
                ZeroDivisionError is different in Python 2 and Python 3
              
              
                beniwohli 45c81b8
              
                Apply doc fixes from code review
              
              
                beniwohli File filter
Filter by extension
Conversations
          Failed to load comments.   
        
        
          
      Loading
        
  Jump to
        
          Jump to file
        
      
      
          Failed to load files.   
        
        
          
      Loading
        
  Diff view
Diff view
There are no files selected for viewing
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
|  | @@ -83,7 +83,7 @@ In order to collect performance metrics, | |
| the agent automatically inserts a middleware at the top of your middleware list | ||
| (`settings.MIDDLEWARE` in current versions of Django, `settings.MIDDLEWARE_CLASSES` in some older versions). | ||
| To disable the automatic insertion of the middleware, | ||
| see <<config-django-autoinsert-middleware,django_autoinsert_middleware>>. | ||
| see <<config-django-autoinsert-middleware,`django_autoinsert_middleware`>>. | ||
|  | ||
| NOTE: For automatic insertion to work, | ||
| your list of middlewares (`settings.MIDDLEWARE` or `settings.MIDDLEWARE_CLASSES`) must be of type `list` or `tuple`. | ||
|  | @@ -93,6 +93,15 @@ the agent also collects fine grained metrics on template rendering, | |
| database queries, HTTP requests, etc. | ||
| You can find more information on what we instrument in the <<automatic-instrumentation, Automatic Instrumentation>> section. | ||
|  | ||
| Lastly, the agent will also collect performance data for Django management commands. | ||
| You can disable instrumentation for certain commands using the | ||
| <<config-django-commands-exclude,`django_commands_exclude`>> setting. | ||
| Transactions for management commands can be accessed in the APM app in Kibana by choosing `django_command` in the "transaction type" filter. | ||
| There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. APM app 😍 | ||
|  | ||
| NOTE: The agent collects command line arguments as additional metadata for transactions. | ||
| If you run a command that contains sensitive data on the command line, like tokens or passwords, | ||
| we recommend to exclude that command from instrumentation. | ||
|  | ||
| [float] | ||
| [[django-instrumenting-custom-python-code]] | ||
| ===== Instrumenting custom Python code | ||
|  | ||
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| # BSD 3-Clause License | ||
| # | ||
| # Copyright (c) 2019, Elasticsearch BV | ||
| # All rights reserved. | ||
| # | ||
| # Redistribution and use in source and binary forms, with or without | ||
| # modification, are permitted provided that the following conditions are met: | ||
| # | ||
| # * Redistributions of source code must retain the above copyright notice, this | ||
| # list of conditions and the following disclaimer. | ||
| # | ||
| # * Redistributions in binary form must reproduce the above copyright notice, | ||
| # this list of conditions and the following disclaimer in the documentation | ||
| # and/or other materials provided with the distribution. | ||
| # | ||
| # * Neither the name of the copyright holder nor the names of its | ||
| # contributors may be used to endorse or promote products derived from | ||
| # this software without specific prior written permission. | ||
| # | ||
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
| # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
| # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
| # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | ||
| # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
| # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
| # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||
| # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||
| # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| import sys | ||
|  | ||
| from elasticapm.instrumentation.packages.base import AbstractInstrumentedModule | ||
| from elasticapm.utils import compat | ||
|  | ||
|  | ||
| class DjangoCommandInstrumentation(AbstractInstrumentedModule): | ||
| name = "django_command" | ||
|  | ||
| instrument_list = [("django.core.management", "BaseCommand.execute")] | ||
|  | ||
| def call_if_sampling(self, module, method, wrapped, instance, args, kwargs): | ||
| from django.apps import apps # import at top level fails if Django is not installed | ||
|  | ||
| app = apps.get_app_config("elasticapm.contrib.django") | ||
| client = getattr(app, "client", None) | ||
| full_name = compat.text_type(instance.__module__) | ||
| name = full_name.rsplit(".", 1)[-1] | ||
| if not client or any(pattern.match(name) for pattern in client.config.django_commands_exclude): | ||
| return wrapped(*args, **kwargs) | ||
|  | ||
| transaction = client.begin_transaction("django_command") | ||
| transaction.is_sampled = True # always sample transactions | ||
| status = "ok" | ||
| try: | ||
| return wrapped(*args, **kwargs) | ||
| except Exception: | ||
| status = "failed" | ||
| client.capture_exception() | ||
| compat.reraise(*sys.exc_info()) | ||
| finally: | ||
| client.end_transaction(full_name, status) | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,109 @@ | ||
| # BSD 3-Clause License | ||
| # | ||
| # Copyright (c) 2019, Elasticsearch BV | ||
| # All rights reserved. | ||
| # | ||
| # Redistribution and use in source and binary forms, with or without | ||
| # modification, are permitted provided that the following conditions are met: | ||
| # | ||
| # * Redistributions of source code must retain the above copyright notice, this | ||
| # list of conditions and the following disclaimer. | ||
| # | ||
| # * Redistributions in binary form must reproduce the above copyright notice, | ||
| # this list of conditions and the following disclaimer in the documentation | ||
| # and/or other materials provided with the distribution. | ||
| # | ||
| # * Neither the name of the copyright holder nor the names of its | ||
| # contributors may be used to endorse or promote products derived from | ||
| # this software without specific prior written permission. | ||
| # | ||
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
| # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
| # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
| # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | ||
| # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
| # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
| # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||
| # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||
| # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
| import pytest # isort:skip | ||
|  | ||
| django = pytest.importorskip("django") # isort:skip | ||
|  | ||
| from django.core.management import CommandError, call_command | ||
|  | ||
| import pytest | ||
|  | ||
| from elasticapm.conf import constants | ||
| from elasticapm.utils import compat | ||
|  | ||
|  | ||
| def test_management_command(django_elasticapm_client): | ||
| call_command("eapm_test_command") | ||
| transaction = django_elasticapm_client.events[constants.TRANSACTION][0] | ||
| assert transaction["type"] == "django_command" | ||
| assert transaction["name"] == "tests.contrib.django.testapp.management.commands.eapm_test_command" | ||
| assert transaction["result"] == "ok" | ||
|  | ||
| spans = django_elasticapm_client.spans_for_transaction(transaction) | ||
| assert len(spans) == 1 | ||
| assert spans[0]["name"] == "yay" | ||
|  | ||
|  | ||
| def test_management_command_command_error(django_elasticapm_client): | ||
| with pytest.raises(CommandError): | ||
| call_command("eapm_test_command", explode="yes") | ||
| transaction = django_elasticapm_client.events[constants.TRANSACTION][0] | ||
| assert transaction["type"] == "django_command" | ||
| assert transaction["name"] == "tests.contrib.django.testapp.management.commands.eapm_test_command" | ||
| assert transaction["result"] == "failed" | ||
|  | ||
| exception = django_elasticapm_client.events[constants.ERROR][0] | ||
| assert exception["culprit"] == "tests.contrib.django.testapp.management.commands.eapm_test_command.handle" | ||
| assert exception["exception"]["message"] == "CommandError: oh no" | ||
| assert exception["transaction_id"] == transaction["id"] | ||
|  | ||
|  | ||
| def test_management_command_other_error(django_elasticapm_client): | ||
| with pytest.raises(ZeroDivisionError): | ||
| call_command("eapm_test_command", explode="yes, really") | ||
| transaction = django_elasticapm_client.events[constants.TRANSACTION][0] | ||
| assert transaction["type"] == "django_command" | ||
| assert transaction["name"] == "tests.contrib.django.testapp.management.commands.eapm_test_command" | ||
| assert transaction["result"] == "failed" | ||
|  | ||
| exception = django_elasticapm_client.events[constants.ERROR][0] | ||
| assert exception["culprit"] == "tests.contrib.django.testapp.management.commands.eapm_test_command.handle" | ||
| assert exception["exception"]["message"].startswith("ZeroDivisionError:") | ||
| assert exception["transaction_id"] == transaction["id"] | ||
|  | ||
|  | ||
| @pytest.mark.parametrize("django_elasticapm_client", [{"django_commands_exclude": "*"}], indirect=True) | ||
| def test_management_command_ignore_all(django_elasticapm_client): | ||
| call_command("eapm_test_command") | ||
| assert len(django_elasticapm_client.events[constants.TRANSACTION]) == 0 | ||
|  | ||
|  | ||
| @pytest.mark.parametrize( | ||
| "django_elasticapm_client", [{"django_commands_exclude": "eapm_test_command,other_command"}], indirect=True | ||
| ) | ||
| def test_management_command_ignore_exact(django_elasticapm_client): | ||
| call_command("eapm_test_command") | ||
| assert len(django_elasticapm_client.events[constants.TRANSACTION]) == 0 | ||
|  | ||
|  | ||
| @pytest.mark.parametrize( | ||
| "django_elasticapm_client", [{"django_commands_exclude": "eapm_test_command,other_command"}], indirect=True | ||
| ) | ||
| def test_management_command_ignore_exact(django_elasticapm_client): | ||
| call_command("eapm_test_command") | ||
| assert len(django_elasticapm_client.events[constants.TRANSACTION]) == 0 | ||
|  | ||
|  | ||
| @pytest.mark.parametrize( | ||
| "django_elasticapm_client", [{"django_commands_exclude": "this_command,other_command"}], indirect=True | ||
| ) | ||
| def test_management_command_ignore_no_match(django_elasticapm_client): | ||
| call_command("eapm_test_command") | ||
| assert len(django_elasticapm_client.events[constants.TRANSACTION]) == 1 | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| # BSD 3-Clause License | ||
| # | ||
| # Copyright (c) 2019, Elasticsearch BV | ||
| # All rights reserved. | ||
| # | ||
| # Redistribution and use in source and binary forms, with or without | ||
| # modification, are permitted provided that the following conditions are met: | ||
| # | ||
| # * Redistributions of source code must retain the above copyright notice, this | ||
| # list of conditions and the following disclaimer. | ||
| # | ||
| # * Redistributions in binary form must reproduce the above copyright notice, | ||
| # this list of conditions and the following disclaimer in the documentation | ||
| # and/or other materials provided with the distribution. | ||
| # | ||
| # * Neither the name of the copyright holder nor the names of its | ||
| # contributors may be used to endorse or promote products derived from | ||
| # this software without specific prior written permission. | ||
| # | ||
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
| # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
| # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
| # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | ||
| # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
| # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
| # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||
| # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||
| # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
        
          
  
    
      
          
            29 changes: 29 additions & 0 deletions
          
          29 
        
  tests/contrib/django/testapp/management/commands/__init__.py
  
  
      
      
   
        
      
      
    
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| # BSD 3-Clause License | ||
| # | ||
| # Copyright (c) 2019, Elasticsearch BV | ||
| # All rights reserved. | ||
| # | ||
| # Redistribution and use in source and binary forms, with or without | ||
| # modification, are permitted provided that the following conditions are met: | ||
| # | ||
| # * Redistributions of source code must retain the above copyright notice, this | ||
| # list of conditions and the following disclaimer. | ||
| # | ||
| # * Redistributions in binary form must reproduce the above copyright notice, | ||
| # this list of conditions and the following disclaimer in the documentation | ||
| # and/or other materials provided with the distribution. | ||
| # | ||
| # * Neither the name of the copyright holder nor the names of its | ||
| # contributors may be used to endorse or promote products derived from | ||
| # this software without specific prior written permission. | ||
| # | ||
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
| # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
| # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
| # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | ||
| # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
| # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
| # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||
| # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||
| # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
        
          
  
    
      
          
            51 changes: 51 additions & 0 deletions
          
          51 
        
  tests/contrib/django/testapp/management/commands/eapm_test_command.py
  
  
      
      
   
        
      
      
    
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| # BSD 3-Clause License | ||
| # | ||
| # Copyright (c) 2019, Elasticsearch BV | ||
| # All rights reserved. | ||
| # | ||
| # Redistribution and use in source and binary forms, with or without | ||
| # modification, are permitted provided that the following conditions are met: | ||
| # | ||
| # * Redistributions of source code must retain the above copyright notice, this | ||
| # list of conditions and the following disclaimer. | ||
| # | ||
| # * Redistributions in binary form must reproduce the above copyright notice, | ||
| # this list of conditions and the following disclaimer in the documentation | ||
| # and/or other materials provided with the distribution. | ||
| # | ||
| # * Neither the name of the copyright holder nor the names of its | ||
| # contributors may be used to endorse or promote products derived from | ||
| # this software without specific prior written permission. | ||
| # | ||
| # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
| # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
| # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
| # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | ||
| # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||
| # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
| # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | ||
| # CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||
| # OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | ||
| # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
|  | ||
| from django.core.management.base import BaseCommand, CommandError | ||
|  | ||
| from elasticapm import capture_span | ||
|  | ||
|  | ||
| class Command(BaseCommand): | ||
| help = "Just a test" | ||
|  | ||
| def add_arguments(self, parser): | ||
| parser.add_argument("--explode", default="no", action="store") | ||
|  | ||
| def handle(self, *args, **options): | ||
|  | ||
| with capture_span("yay"): | ||
| pass | ||
|  | ||
| if options["explode"] == "yes": | ||
| raise CommandError("oh no") | ||
|  | ||
| elif options["explode"] == "yes, really": | ||
| nan = 1 / 0 | 
  Add this suggestion to a batch that can be applied as a single commit.
  This suggestion is invalid because no changes were made to the code.
  Suggestions cannot be applied while the pull request is closed.
  Suggestions cannot be applied while viewing a subset of changes.
  Only one suggestion per line can be applied in a batch.
  Add this suggestion to a batch that can be applied as a single commit.
  Applying suggestions on deleted lines is not supported.
  You must change the existing code in this line in order to create a valid suggestion.
  Outdated suggestions cannot be applied.
  This suggestion has been applied or marked resolved.
  Suggestions cannot be applied from pending reviews.
  Suggestions cannot be applied on multi-line comments.
  Suggestions cannot be applied while the pull request is queued to merge.
  Suggestion cannot be applied right now. Please check back later.
  
    
  
    
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would you think about making this a whitelist (with globbing included)? That would also make this much safer. (More thoughts in the review body)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A whitelist would definitely be the safest method, but it creates a lot of work for the user. Large Django projects can easily have dozens of management commands, and gain new ones if new 3rd party Django apps are added to the project. Keeping the white list up-to-date could be tedious work.
Another draw-back of a whitelist is that we can't provide a blacklist of commands that we should absolutely not instrument in code.
How about adding a second option, which is a flag, and disable it by default? Add some specific documentation in the Django docs, and include the
NOTEthere. That way, people will see the note when they read up on how to enable management command instrumentation.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds reasonable to me. 👍