openmodule 14.0.1__tar.gz → 14.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {openmodule-14.0.1 → openmodule-14.0.2}/ChangeLog +5 -7
- {openmodule-14.0.1/openmodule.egg-info → openmodule-14.0.2}/PKG-INFO +1 -1
- {openmodule-14.0.1 → openmodule-14.0.2}/docs/sentry.md +6 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/dispatcher.py +6 -4
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/rpc/server.py +14 -11
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/sentry.py +56 -8
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/utils/io.py +17 -16
- {openmodule-14.0.1 → openmodule-14.0.2/openmodule.egg-info}/PKG-INFO +1 -1
- openmodule-14.0.2/openmodule.egg-info/pbr.json +1 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule.egg-info/requires.txt +1 -1
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule_test/sentry.py +12 -10
- {openmodule-14.0.1 → openmodule-14.0.2}/requirements.txt +1 -1
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_sentry.py +121 -9
- openmodule-14.0.1/openmodule.egg-info/pbr.json +0 -1
- {openmodule-14.0.1 → openmodule-14.0.2}/.gitlab-ci.yml +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/AUTHORS +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/LICENSE +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/README.md +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/docs/access_service.md +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/docs/anonymization.md +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/docs/cleanup.md +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/docs/coding_standard.md +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/docs/commands.md +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/docs/connection_status_listener.md +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/docs/csv_export.md +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/docs/database.md +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/docs/deprecated.md +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/docs/deprecated_code/README.md +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/docs/deprecated_code/access_service/openmodule/models/access_service.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/docs/deprecated_code/access_service/openmodule/utils/access_service.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/docs/deprecated_code/access_service/openmodule_test/access_service.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/docs/deprecated_code/access_service/tests/test_utils_access_service.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/docs/deprecated_code/api/openmodule/utils/api.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/docs/deprecated_code/api/openmodule_test/api.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/docs/deprecated_code/api/tests/test_utils_api.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/docs/deprecated_code/package_reader/openmodule/utils/package_reader.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/docs/deprecated_code/package_reader/openmodule_test/fake_package_creator.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/docs/deprecated_code/package_reader/tests/test_package_reader.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/docs/event_sending.md +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/docs/getting_started.md +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/docs/health.md +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/docs/images/broker.drawio.png +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/docs/known_issues.md +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/docs/migrations.md +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/docs/package_reader.md +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/docs/rpc.md +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/docs/settings.md +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/docs/settings_provider.md +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/docs/testing.md +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/docs/translation.md +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/docs/utils.md +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/__init__.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/alert.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/config.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/connection_status.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/core.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/database/custom_types.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/database/database.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/database/env.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/database/migration.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/health.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/logging.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/messaging.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/models/__init__.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/models/access_service.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/models/alert.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/models/base.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/models/io.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/models/kv_store.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/models/presence.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/models/privacy.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/models/rpc.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/models/settings.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/models/validation.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/models/vehicle.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/rpc/__init__.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/rpc/client.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/rpc/common.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/threading.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/utils/__init__.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/utils/access_service.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/utils/charset.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/utils/cleanup.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/utils/csv_export.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/utils/databox.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/utils/db_helper.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/utils/eventlog.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/utils/kv_store.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/utils/matching.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/utils/misc_functions.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/utils/package_reader.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/utils/presence.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/utils/schema.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/utils/settings.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/utils/translation.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule/utils/validation.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule.egg-info/SOURCES.txt +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule.egg-info/dependency_links.txt +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule.egg-info/not-zip-safe +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule.egg-info/top_level.txt +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule_commands/__init__.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule_commands/setup.cfg +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule_commands/setup.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule_commands/translate.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule_test/__init__.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule_test/alert.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule_test/connection_status.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule_test/core.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule_test/database.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule_test/eventlistener.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule_test/files.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule_test/gate.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule_test/health.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule_test/interrupt.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule_test/io_simulator.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule_test/package_reader.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule_test/presence.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule_test/requirements.txt +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule_test/rpc.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule_test/settings.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule_test/setup.cfg +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule_test/setup.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule_test/utils.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/openmodule_test/zeromq.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/setup.cfg +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/setup.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/test-requirements.txt +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/__init__.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/config.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/database_models_migration.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/database_models_test.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/invalid_database/alembic/README +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/invalid_database/alembic/__init__.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/invalid_database/alembic/env.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/invalid_database/alembic/script.py.mako +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/invalid_database/alembic/versions/ff26e54332f9_datetime_models.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/invalid_database/alembic.ini +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/invalid_database/makemigration.sh +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/migration_double_column_delete_error/alembic/__init__.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/migration_double_column_delete_error/alembic/env.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/migration_double_column_delete_error/alembic/script.py.mako +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/migration_double_column_delete_error/alembic/versions/812a3e5b8517_initial.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/migration_double_column_delete_error/alembic/versions/a7ea100a784f_key_error.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/migration_double_column_delete_error/alembic.ini +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/migration_double_column_delete_error/makemigration.sh +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/migration_no_such_table_error/alembic/__init__.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/migration_no_such_table_error/alembic/env.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/migration_no_such_table_error/alembic/script.py.mako +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/migration_no_such_table_error/alembic/versions/812a3e5b8517_initial.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/migration_no_such_table_error/alembic/versions/a7ea100a784f_no_such_table_error.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/migration_no_such_table_error/alembic.ini +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/migration_no_such_table_error/makemigration.sh +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/migration_test_database/__init__.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/migration_test_database/alembic/__init__.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/migration_test_database/alembic/env.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/migration_test_database/alembic/script.py.mako +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/migration_test_database/alembic/versions/19789aa5361c_initial.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/migration_test_database/alembic/versions/19d887929ae7_alter.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/migration_test_database/alembic/versions/__init__.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/migration_test_database/alembic.ini +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/migration_test_database/alembic_migration_test_database.sqlite3 +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/migration_test_database/makemigration.sh +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/resources/configs/config.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/resources/configs/test_config.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/resources/configs/test_config_1.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/resources/standard_schemes/DEFAULT-10.yml +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/resources/standard_schemes/DEFAULT-20.yml +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/resources/standard_schemes/LEGACY-0.yml +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/resources/translation/locale/de/LC_MESSAGES/translation.mo +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/resources/translation/locale/de/LC_MESSAGES/translation.po +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/resources/translation/locale/en/LC_MESSAGES/translation.mo +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/resources/translation/locale/en/LC_MESSAGES/translation.po +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/resources/translation/locale/translation.pot +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/resources/translation/translate.sh +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/resources/utils_matching/A-10.yml +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/resources/utils_matching/A-20.yml +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/resources/utils_matching/DEFAULT-10.yml +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/resources/utils_matching/DEFAULT-20.yml +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/resources/utils_matching/DEFAULT-30.yml +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/resources/utils_matching/LEGACY-0.yml +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/resources/utils_matching/TEST-10.yml +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/resources/utils_matching/TEST-20.yml +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/resources/utils_matching/TEST-30.yml +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/resources/utils_matching/TEST-40.yml +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/sentry_main.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_access_service_database/alembic/__init__.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_access_service_database/alembic/env.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_access_service_database/alembic/script.py.mako +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_access_service_database/alembic/versions/7bd4fcd38fde_removed_nfc_and_pin.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_access_service_database/alembic/versions/9ca98a2e5674_added_parksettings_id.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_access_service_database/alembic/versions/c821971f9230_initial.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_access_service_database/alembic.ini +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_access_service_database/makemigration.sh +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_alembic_migrations.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_alert.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_checks.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_config.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_connection_status.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_core.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_database/alembic/__init__.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_database/alembic/env.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_database/alembic/script.py.mako +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_database/alembic/versions/32b8c728abbf_initial.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_database/alembic.ini +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_database/makemigration.sh +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_database.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_dispatcher.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_health.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_interrupt.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_io_listen.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_kv_store_database/alembic/__init__.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_kv_store_database/alembic/env.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_kv_store_database/alembic/script.py.mako +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_kv_store_database/alembic/versions/9c5c944221f4_deprecated_kv_entry_example.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_kv_store_database/alembic/versions/c55a69026a25_initial.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_kv_store_database/alembic.ini +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_kv_store_database/makemigration.sh +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_kv_store_multiple_database/alembic/README +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_kv_store_multiple_database/alembic/__init__.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_kv_store_multiple_database/alembic/env.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_kv_store_multiple_database/alembic/script.py.mako +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_kv_store_multiple_database/alembic/versions/cdb3214131a9_initial.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_kv_store_multiple_database/alembic.ini +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_kv_store_multiple_database/makemigration.sh +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_logging.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_messaging.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_mockrpcclient.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_model.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_rpc.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_schema.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_test_alert.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_test_gate.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_test_zeromq.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_utils_access_service.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_utils_charset.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_utils_cleanup.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_utils_csv_export.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_utils_databox.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_utils_eventlog.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_utils_kv_store.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_utils_kv_store_multiple.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_utils_matching.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_utils_misc_functions.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_utils_package_reader.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_utils_presence.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_utils_settings.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_utils_validation.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tests/test_utils_vehicle.py +0 -0
- {openmodule-14.0.1 → openmodule-14.0.2}/tox.ini +0 -0
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
CHANGES
|
|
2
2
|
=======
|
|
3
3
|
|
|
4
|
+
v14.0.2
|
|
5
|
+
-------
|
|
6
|
+
|
|
7
|
+
* Sentry improvements
|
|
8
|
+
|
|
4
9
|
v14.0.1
|
|
5
10
|
-------
|
|
6
11
|
|
|
@@ -162,7 +167,6 @@ v12.0.0.rc0
|
|
|
162
167
|
* made gate\_control/day\_mode have no scope
|
|
163
168
|
* schedule exports utility
|
|
164
169
|
* SettingsProvider docs
|
|
165
|
-
* SettingsProvider docs
|
|
166
170
|
|
|
167
171
|
v11.1.1
|
|
168
172
|
-------
|
|
@@ -202,9 +206,3 @@ v10.0.5
|
|
|
202
206
|
v10.0.4
|
|
203
207
|
-------
|
|
204
208
|
|
|
205
|
-
* Improvements for backend and package reader
|
|
206
|
-
|
|
207
|
-
v10.0.3
|
|
208
|
-
-------
|
|
209
|
-
|
|
210
|
-
* added freezegun and fakeredis to openmodule requirements
|
|
@@ -24,6 +24,10 @@ for your project that tells the SDK where to send the events. You can find the D
|
|
|
24
24
|
* You can provide additional [sentry options](https://docs.sentry.io/platforms/python/configuration/options/) as keyword
|
|
25
25
|
arguments to the `init_openmodule` function (`server_name` and `environment` cannot be overriden).
|
|
26
26
|
* the `extras` keyword argument can be used to provide additional data to the Sentry SDK
|
|
27
|
+
* the `topics_to_ignore` keyword argument can be used to provide a list of topics that should not be captured by Sentry.
|
|
28
|
+
You should also check that no trace will be started for every message from that topic. (defaults to `["io"]`)
|
|
29
|
+
* the `functions_to_ignore` keyword argument can be used to provide a list of span names (auto generated for functions)
|
|
30
|
+
that should not be captured by Sentry. (defaults to `[]`)
|
|
27
31
|
|
|
28
32
|
```python
|
|
29
33
|
def main():
|
|
@@ -75,6 +79,8 @@ with sentry.trace("my_block"):
|
|
|
75
79
|
|
|
76
80
|
You can add context to the current transaction using one of the following methods:
|
|
77
81
|
|
|
82
|
+
* Adding the data as kwargs to the `sentry.trace` function.
|
|
83
|
+
* `sentry.trace("my_block", extras={"key": "value"}, tags={"key": "value"}, context={"key": "value"})`
|
|
78
84
|
* `sentry_sdk.set_tag(key: str, value: str)`: Adds
|
|
79
85
|
a [tag](https://docs.sentry.io/platforms/python/enriching-events/tags/) to the current transaction.
|
|
80
86
|
* `sentry_sdk.set_tags(**key_value_pairs: str)`:
|
|
@@ -44,7 +44,7 @@ class Listener:
|
|
|
44
44
|
def __init__(self, message_class: Type[ZMQMessage], type: Optional[str], filter: Optional[Callable],
|
|
45
45
|
handler: Callable):
|
|
46
46
|
self.filter = filter
|
|
47
|
-
self.handler = handler
|
|
47
|
+
self.handler = sentry.trace(f"message_handler.{qualname_from_function(handler)}")(handler)
|
|
48
48
|
self.type = type
|
|
49
49
|
self.message_class = message_class
|
|
50
50
|
|
|
@@ -110,6 +110,7 @@ class MessageDispatcher:
|
|
|
110
110
|
self.raise_validation_errors = raise_validation_errors
|
|
111
111
|
self.raise_handler_errors = raise_handler_errors
|
|
112
112
|
self.executor = executor or DummyExecutor()
|
|
113
|
+
self._new_transactions = not isinstance(self.executor, DummyExecutor)
|
|
113
114
|
self._shutdown = False
|
|
114
115
|
self._shutdown_lock = threading.Lock()
|
|
115
116
|
|
|
@@ -201,10 +202,12 @@ class MessageDispatcher:
|
|
|
201
202
|
listeners = self.listeners.get(topic, [])
|
|
202
203
|
for listener in listeners:
|
|
203
204
|
if listener.matches(message):
|
|
205
|
+
message.update(sentry.get_trace_headers())
|
|
204
206
|
self.executor.submit(self.execute, topic, listener, message)
|
|
205
207
|
|
|
206
208
|
def execute(self, topic: str, listener: Listener, message: Dict):
|
|
207
|
-
with sentry.continue_trace_zmq_message_process(
|
|
209
|
+
with sentry.continue_trace_zmq_message_process(
|
|
210
|
+
topic, message, force_new_transaction=self._new_transactions):
|
|
208
211
|
try:
|
|
209
212
|
parsed_message = parse_obj_as(listener.message_class, message)
|
|
210
213
|
except ValidationError as e:
|
|
@@ -214,8 +217,7 @@ class MessageDispatcher:
|
|
|
214
217
|
self.log.exception("Invalid message received")
|
|
215
218
|
else:
|
|
216
219
|
try:
|
|
217
|
-
|
|
218
|
-
listener.handler(parsed_message)
|
|
220
|
+
listener.handler(parsed_message)
|
|
219
221
|
except zmq.ContextTerminated:
|
|
220
222
|
raise
|
|
221
223
|
except Exception as e:
|
|
@@ -77,6 +77,7 @@ class RPCServer(object):
|
|
|
77
77
|
self.thread = None
|
|
78
78
|
self.resource = None
|
|
79
79
|
self.executor = executor or DummyExecutor()
|
|
80
|
+
self._new_transactions = not isinstance(self.executor, DummyExecutor)
|
|
80
81
|
# since zmq does prefix matching we keep a list of unique channel names here
|
|
81
82
|
# so we do not log a warning "unknown handler" if our channel is a prefix of a different channel
|
|
82
83
|
self.registered_channels = set()
|
|
@@ -129,7 +130,8 @@ class RPCServer(object):
|
|
|
129
130
|
|
|
130
131
|
self.log.debug("register handler {}:{} -> {}".format(channel, type, handler))
|
|
131
132
|
self.sub.subscribe(channel_to_request_topic(channel).encode("utf8"))
|
|
132
|
-
|
|
133
|
+
traced_handler = sentry.trace(f"rpc_handler.{qualname_from_function(handler)}")(handler)
|
|
134
|
+
self.handlers[(channel, type)] = HandlerEntry(request_class, response_class, traced_handler)
|
|
133
135
|
self.registered_channels = set(x[0] for x in self.handlers.keys())
|
|
134
136
|
if register_schema:
|
|
135
137
|
Schema.save_rpc(channel, type, request_class, response_class, handler)
|
|
@@ -194,15 +196,14 @@ class RPCServer(object):
|
|
|
194
196
|
if settings.LOG_LEVEL != logging.DEBUG:
|
|
195
197
|
self.log.info("received RPC channel: %s, type: %s", channel, message.type)
|
|
196
198
|
try:
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
if
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
return self._response_to_dict(response)
|
|
199
|
+
response = handler.handler(request, message)
|
|
200
|
+
if isinstance(response, handler.response_class):
|
|
201
|
+
# shortcut prevent serialization and de-serialization if the correct response
|
|
202
|
+
# is already returned
|
|
203
|
+
return self._response_to_dict(response)
|
|
204
|
+
else:
|
|
205
|
+
response = parse_obj_as(handler.response_class, response or {})
|
|
206
|
+
return self._response_to_dict(response)
|
|
206
207
|
except Exception as e:
|
|
207
208
|
self.log.exception("exception in handler {}:{}".format(channel, message.type))
|
|
208
209
|
return {"status": RPCServerError.handler_error, "exception": str(e)}
|
|
@@ -211,7 +212,8 @@ class RPCServer(object):
|
|
|
211
212
|
return None
|
|
212
213
|
|
|
213
214
|
def _process_rpc_message(self, topic: str, message: dict):
|
|
214
|
-
with sentry.continue_trace_zmq_message_process(
|
|
215
|
+
with sentry.continue_trace_zmq_message_process(
|
|
216
|
+
topic, message, force_new_transaction=self._new_transactions):
|
|
215
217
|
try:
|
|
216
218
|
channel = self._channel_from_topic(topic)
|
|
217
219
|
|
|
@@ -262,6 +264,7 @@ class RPCServer(object):
|
|
|
262
264
|
continue
|
|
263
265
|
if self.running:
|
|
264
266
|
# someone may have stopped our server while we were receiving a message
|
|
267
|
+
message.update(sentry.get_trace_headers())
|
|
265
268
|
self.executor.submit(self._process_rpc_message, topic, message)
|
|
266
269
|
except zmq.ContextTerminated:
|
|
267
270
|
pass
|
|
@@ -5,13 +5,13 @@ import logging
|
|
|
5
5
|
import os.path
|
|
6
6
|
import time
|
|
7
7
|
from contextlib import contextmanager
|
|
8
|
-
from typing import Union, Callable, overload, Generator, Optional, Tuple, Any
|
|
8
|
+
from typing import Union, Callable, overload, Generator, Optional, Tuple, Any, List
|
|
9
9
|
|
|
10
10
|
import orjson
|
|
11
11
|
import requests
|
|
12
|
+
import sentry_sdk.integrations.logging
|
|
12
13
|
import sentry_sdk.tracing
|
|
13
14
|
import sentry_sdk.tracing_utils
|
|
14
|
-
import sentry_sdk.integrations.logging
|
|
15
15
|
import urllib3.exceptions
|
|
16
16
|
from sentry_sdk.consts import EndpointType
|
|
17
17
|
from sentry_sdk.envelope import Envelope
|
|
@@ -20,26 +20,37 @@ from sentry_sdk.utils import qualname_from_function
|
|
|
20
20
|
from openmodule.config import settings
|
|
21
21
|
|
|
22
22
|
_log = logging.getLogger("OmSentry")
|
|
23
|
+
_topics_to_ignore: List[str] = ["io"]
|
|
24
|
+
_functions_to_ignore: List[str] = ["message_handler.openmodule.utils.io.IoListener._on_io_message"]
|
|
25
|
+
|
|
23
26
|
|
|
27
|
+
@contextmanager
|
|
28
|
+
def noop_context():
|
|
29
|
+
yield
|
|
24
30
|
|
|
25
|
-
|
|
31
|
+
|
|
32
|
+
def continue_trace_zmq_message_receive(topic: str, message: dict, **kwargs):
|
|
26
33
|
"""
|
|
27
34
|
Continues a sentry trace for a received zmq message. (If already in a transaction, it will create a scope instead)
|
|
28
35
|
Our ZMQMessage class contains the baggage and sentry-trace fields required for this, so the dict must contain these.
|
|
29
36
|
:param topic: The topic of the message (as received from the ZMQ socket and decoded)
|
|
30
37
|
:param message: The ZMQMessage as a dict (as received from the ZMQ socket and json loaded)
|
|
31
38
|
"""
|
|
32
|
-
|
|
39
|
+
if topic in _topics_to_ignore:
|
|
40
|
+
return noop_context()
|
|
41
|
+
return _continue_trace_zmq_message(topic, message, "topic.receive", **kwargs)
|
|
33
42
|
|
|
34
43
|
|
|
35
|
-
def continue_trace_zmq_message_process(topic: str, message: dict):
|
|
44
|
+
def continue_trace_zmq_message_process(topic: str, message: dict, **kwargs):
|
|
36
45
|
"""
|
|
37
46
|
Continues a sentry trace for a zmq message executor. (If already in a transaction, it will create a scope instead)
|
|
38
47
|
Our ZMQMessage class contains the baggage and sentry-trace fields required for this, so the dict must contain these.
|
|
39
48
|
:param topic: The topic of the message (as received from the ZMQ socket and decoded)
|
|
40
49
|
:param message: The ZMQMessage as a dict (as received from the ZMQ socket and json loaded)
|
|
41
50
|
"""
|
|
42
|
-
|
|
51
|
+
if topic in _topics_to_ignore:
|
|
52
|
+
return noop_context()
|
|
53
|
+
return _continue_trace_zmq_message(topic, message, "topic.process", **kwargs)
|
|
43
54
|
|
|
44
55
|
|
|
45
56
|
@overload # pragma: no cover
|
|
@@ -109,6 +120,14 @@ def get_baggage() -> Optional[str]:
|
|
|
109
120
|
get_traceparent = sentry_sdk.get_traceparent
|
|
110
121
|
|
|
111
122
|
|
|
123
|
+
def get_trace_headers(empty_if_not_sampled: bool = False) -> dict:
|
|
124
|
+
if empty_if_not_sampled:
|
|
125
|
+
span = sentry_sdk.get_current_span()
|
|
126
|
+
if span and not span.sampled:
|
|
127
|
+
return {}
|
|
128
|
+
return {"sentry-trace": sentry_sdk.get_traceparent(), "baggage": sentry_sdk.get_baggage()}
|
|
129
|
+
|
|
130
|
+
|
|
112
131
|
class _Trace:
|
|
113
132
|
"""
|
|
114
133
|
Context manager for sentry tracing.
|
|
@@ -130,6 +149,20 @@ class _Trace:
|
|
|
130
149
|
Otherwise, start a new span.
|
|
131
150
|
If given a trace_headers dict, it will continue the trace with the given headers.
|
|
132
151
|
"""
|
|
152
|
+
if self.span_kwargs.get("name") in _functions_to_ignore:
|
|
153
|
+
yield
|
|
154
|
+
return
|
|
155
|
+
|
|
156
|
+
def set_context():
|
|
157
|
+
for key, value in extras.items():
|
|
158
|
+
sentry_sdk.set_extra(key, value)
|
|
159
|
+
sentry_sdk.set_tags(tags)
|
|
160
|
+
for key, value in contexts.items():
|
|
161
|
+
sentry_sdk.set_context(key, value)
|
|
162
|
+
|
|
163
|
+
extras = self.span_kwargs.pop("extras", {})
|
|
164
|
+
tags = self.span_kwargs.pop("tags", {})
|
|
165
|
+
contexts = self.span_kwargs.pop("contexts", {})
|
|
133
166
|
span = sentry_sdk.get_current_span()
|
|
134
167
|
if span is None or self.force_new_transaction:
|
|
135
168
|
with sentry_sdk.isolation_scope():
|
|
@@ -139,12 +172,15 @@ class _Trace:
|
|
|
139
172
|
with sentry_sdk.start_transaction(transaction=transaction, **self.span_kwargs) as transaction:
|
|
140
173
|
if transaction:
|
|
141
174
|
transaction.description = transaction.name
|
|
175
|
+
set_context()
|
|
142
176
|
yield
|
|
143
177
|
elif span.sampled:
|
|
144
178
|
self.span_kwargs.pop("source", None)
|
|
145
179
|
with sentry_sdk.start_span(**self.span_kwargs):
|
|
180
|
+
set_context()
|
|
146
181
|
yield
|
|
147
182
|
else: # No need to start a span if the parent is not sampled
|
|
183
|
+
set_context()
|
|
148
184
|
yield
|
|
149
185
|
|
|
150
186
|
def __enter__(self) -> None:
|
|
@@ -179,9 +215,9 @@ class _Trace:
|
|
|
179
215
|
return func_with_tracing
|
|
180
216
|
|
|
181
217
|
|
|
182
|
-
def _continue_trace_zmq_message(topic: str, message: dict, op: str):
|
|
218
|
+
def _continue_trace_zmq_message(topic: str, message: dict, op: str, **kwargs):
|
|
183
219
|
name = f"{topic}/{message.get('type', '')}"
|
|
184
|
-
return _Trace(trace_headers=message, op=op, name=name, source="zmq", origin="auto.zmq")
|
|
220
|
+
return _Trace(trace_headers=message, op=op, name=name, source="zmq", origin="auto.zmq", **kwargs)
|
|
185
221
|
|
|
186
222
|
|
|
187
223
|
class StoringTransport(sentry_sdk.transport.HttpTransport):
|
|
@@ -349,6 +385,11 @@ def _patch_sentry_method():
|
|
|
349
385
|
|
|
350
386
|
def _update_sentry_config(kwargs: dict):
|
|
351
387
|
# Set default values
|
|
388
|
+
global _topics_to_ignore, _functions_to_ignore
|
|
389
|
+
_topics_to_ignore = kwargs.pop("topics_to_ignore", ["io"])
|
|
390
|
+
_functions_to_ignore = kwargs.pop(
|
|
391
|
+
"functions_to_ignore", ["message_handler.openmodule.utils.io.IoListener._on_io_message"])
|
|
392
|
+
|
|
352
393
|
if "traces_sampler" not in kwargs:
|
|
353
394
|
kwargs.setdefault("traces_sample_rate", 0.0001)
|
|
354
395
|
if "profiles_sampler" not in kwargs:
|
|
@@ -371,6 +412,8 @@ def _update_sentry_config(kwargs: dict):
|
|
|
371
412
|
kwargs["extras"]["name"] = settings.NAME
|
|
372
413
|
if hasattr(settings, "GATE"):
|
|
373
414
|
kwargs["extras"]["gate"] = settings.GATE
|
|
415
|
+
kwargs.setdefault("contexts", {})
|
|
416
|
+
kwargs["contexts"]["device"] = {"name": settings.RESOURCE, "model": settings.RESOURCE}
|
|
374
417
|
|
|
375
418
|
|
|
376
419
|
def init_sentry(dsn: str, **kwargs):
|
|
@@ -388,12 +431,17 @@ def init_sentry(dsn: str, **kwargs):
|
|
|
388
431
|
|
|
389
432
|
_update_sentry_config(kwargs)
|
|
390
433
|
extras = kwargs.pop("extras", {})
|
|
434
|
+
contexts = kwargs.pop("contexts", {})
|
|
435
|
+
tags = kwargs.pop("tags", {})
|
|
391
436
|
sentry_sdk.init(dsn=dsn, **kwargs)
|
|
392
437
|
|
|
393
438
|
_patch_requests_library()
|
|
394
439
|
_patch_sentry_method()
|
|
395
440
|
for key, value in extras.items():
|
|
396
441
|
sentry_sdk.get_global_scope().set_extra(key, value)
|
|
442
|
+
sentry_sdk.get_global_scope().set_tags(tags)
|
|
443
|
+
for key, value in contexts.items():
|
|
444
|
+
sentry_sdk.get_global_scope().set_context(key, value)
|
|
397
445
|
|
|
398
446
|
|
|
399
447
|
def deinit_sentry():
|
|
@@ -137,7 +137,6 @@ class IoListener:
|
|
|
137
137
|
return x if x else [IoState(pin="", gateway=Gateway(gate="", direction=""), type="", value=0, physical=0,
|
|
138
138
|
inverted=False, last_timestamp=datetime.fromtimestamp(0))]
|
|
139
139
|
|
|
140
|
-
@sentry.trace
|
|
141
140
|
def _on_io_message(self, message: IoMessage):
|
|
142
141
|
"""
|
|
143
142
|
This handler receives all IO Messages, saves any changes and calls any listeners registered in the IoListener
|
|
@@ -170,18 +169,20 @@ class IoListener:
|
|
|
170
169
|
self.current_states[message.pin].last_timestamp = message.timestamp
|
|
171
170
|
|
|
172
171
|
message = message.dict()
|
|
173
|
-
for listener in self.listeners
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
172
|
+
matched_listeners = [listener for listener in self.listeners if listener.matches(message)]
|
|
173
|
+
if matched_listeners:
|
|
174
|
+
with sentry.continue_trace_zmq_message_process("io", message):
|
|
175
|
+
for listener in matched_listeners:
|
|
176
|
+
"""
|
|
177
|
+
Handles the registered listeners the same as the dispatcher.
|
|
178
|
+
Is copied here because all messages are needed to keep current_states up to date.
|
|
179
|
+
"""
|
|
180
|
+
try:
|
|
181
|
+
listener.handler(self.current_states[message["pin"]])
|
|
182
|
+
except zmq.ContextTerminated:
|
|
183
|
+
raise
|
|
184
|
+
except Exception as e:
|
|
185
|
+
if self.raise_handler_errors:
|
|
186
|
+
raise e from None
|
|
187
|
+
else:
|
|
188
|
+
self.log.exception("Error in message handler")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"git_version": "3399243", "is_release": true}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import threading
|
|
1
2
|
from typing import List
|
|
2
3
|
from unittest import TestCase, mock
|
|
3
4
|
|
|
@@ -16,15 +17,18 @@ class SentryTestTransport(sentry_sdk.transport.Transport):
|
|
|
16
17
|
def __init__(self, options=None):
|
|
17
18
|
super().__init__(options)
|
|
18
19
|
self.envelopes: List[Envelope] = []
|
|
20
|
+
self.envelopes_lock = threading.Lock()
|
|
19
21
|
|
|
20
22
|
def capture_envelope(self, envelope: Envelope):
|
|
21
|
-
self.
|
|
23
|
+
with self.envelopes_lock:
|
|
24
|
+
self.envelopes.append(envelope)
|
|
22
25
|
|
|
23
26
|
def get_envelopes(self, clear: bool = True) -> List[Envelope]:
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
with self.envelopes_lock:
|
|
28
|
+
envelopes = self.envelopes
|
|
29
|
+
if clear:
|
|
30
|
+
self.envelopes = []
|
|
31
|
+
return envelopes
|
|
28
32
|
|
|
29
33
|
|
|
30
34
|
class SentryTestMixin(TestCase):
|
|
@@ -56,10 +60,8 @@ class SentryTestMixin(TestCase):
|
|
|
56
60
|
return transport
|
|
57
61
|
|
|
58
62
|
def _get_envelopes(self) -> List[Envelope]:
|
|
59
|
-
return self.sentry_transport.
|
|
63
|
+
return self.sentry_transport.get_envelopes(clear=False)
|
|
60
64
|
|
|
61
65
|
def get_sent_envelopes(self, timeout: float = 0, clear: bool = True) -> List[Envelope]:
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
self.sentry_transport.envelopes = []
|
|
65
|
-
return envelopes
|
|
66
|
+
wait_for_value(self._get_envelopes, target=[], invert_target=True, timeout=timeout)
|
|
67
|
+
return self.sentry_transport.get_envelopes(clear=clear)
|
|
@@ -10,8 +10,10 @@ import random
|
|
|
10
10
|
import signal
|
|
11
11
|
import subprocess
|
|
12
12
|
import sys
|
|
13
|
+
import threading
|
|
13
14
|
import time
|
|
14
15
|
import unittest
|
|
16
|
+
from concurrent.futures.thread import ThreadPoolExecutor
|
|
15
17
|
from contextlib import contextmanager
|
|
16
18
|
from io import BytesIO
|
|
17
19
|
from pathlib import Path
|
|
@@ -30,9 +32,12 @@ import openmodule.logging
|
|
|
30
32
|
from openmodule import sentry
|
|
31
33
|
from openmodule.config import settings, override_settings
|
|
32
34
|
from openmodule.core import init_openmodule, shutdown_openmodule
|
|
33
|
-
from openmodule.
|
|
35
|
+
from openmodule.dispatcher import MessageDispatcher
|
|
36
|
+
from openmodule.models.base import ZMQMessage, Gateway, Direction
|
|
37
|
+
from openmodule.models.io import IoMessage
|
|
34
38
|
from openmodule.rpc import RPCServer
|
|
35
39
|
from openmodule.sentry import init_sentry, deinit_sentry
|
|
40
|
+
from openmodule.utils.io import IoListener
|
|
36
41
|
from openmodule_test.sentry import SentryTestMixin
|
|
37
42
|
from openmodule_test.utils import wait_for_value
|
|
38
43
|
from openmodule_test.zeromq import ZMQTestMixin
|
|
@@ -149,18 +154,25 @@ class SentryInitTestCase(ZMQTestMixin):
|
|
|
149
154
|
self.assertEqual(str(e.exception), "sentry DSN is required")
|
|
150
155
|
self.assertFalse(openmodule.core._core_thread.sentry_was_initialized)
|
|
151
156
|
|
|
157
|
+
@override_settings(GATE="einfahrt")
|
|
152
158
|
def test_sentry_init(self):
|
|
153
159
|
config = self.zmq_config()
|
|
154
160
|
init_openmodule(config, context=self.zmq_context(), sentry=True, dsn="http://test@test/1")
|
|
155
161
|
self.assertTrue(openmodule.core._core_thread.sentry_was_initialized)
|
|
156
|
-
|
|
157
|
-
self.assertIsInstance(
|
|
158
|
-
self.
|
|
159
|
-
self.assertEqual(
|
|
160
|
-
self.assertEqual(
|
|
161
|
-
self.assertEqual(
|
|
162
|
-
self.assertEqual(
|
|
163
|
-
self.assertEqual(
|
|
162
|
+
scope = sentry_sdk.get_global_scope()
|
|
163
|
+
self.assertIsInstance(scope.client, sentry_sdk.client.Client)
|
|
164
|
+
self.assertIsInstance(scope.client.transport, sentry.StoringTransport)
|
|
165
|
+
self.assertEqual(scope.client.options["release"], "test@test-version")
|
|
166
|
+
self.assertEqual(scope.client.options["server_name"], "test-resource")
|
|
167
|
+
self.assertEqual(scope.client.options["environment"], "staging")
|
|
168
|
+
self.assertEqual(scope.client.options["dsn"], "http://test@test/1")
|
|
169
|
+
self.assertEqual(scope.client.options["traces_sample_rate"], 0.0001)
|
|
170
|
+
self.assertEqual(scope.client.options["profiles_sample_rate"], 0.001)
|
|
171
|
+
self.assertEqual(scope._extras, {"name": "test", "gate": "einfahrt"})
|
|
172
|
+
self.assertEqual(scope._contexts, {'device': {'model': 'test-resource', 'name': 'test-resource'}})
|
|
173
|
+
self.assertEqual(sentry._topics_to_ignore, ["io"])
|
|
174
|
+
self.assertEqual(sentry._functions_to_ignore, ["message_handler.openmodule.utils.io.IoListener._on_io_message"])
|
|
175
|
+
|
|
164
176
|
|
|
165
177
|
@override_settings(NAME="test")
|
|
166
178
|
def test_service_name_generation(self):
|
|
@@ -184,6 +196,18 @@ class SentryInitTestCase(ZMQTestMixin):
|
|
|
184
196
|
sentry._update_sentry_config(kwargs)
|
|
185
197
|
self.assertEqual(kwargs["release"], "service-test@test-version")
|
|
186
198
|
|
|
199
|
+
def test_sentry_ignore_topics(self):
|
|
200
|
+
self.assertEqual(sentry._topics_to_ignore, ["io"])
|
|
201
|
+
init_openmodule(self.zmq_config(), context=self.zmq_context(), sentry=True, dsn="http://test@test/1",
|
|
202
|
+
topics_to_ignore=["test"])
|
|
203
|
+
self.assertEqual(sentry._topics_to_ignore, ["test"])
|
|
204
|
+
|
|
205
|
+
def test_sentry_ignore_functions(self):
|
|
206
|
+
self.assertEqual(sentry._functions_to_ignore, ["message_handler.openmodule.utils.io.IoListener._on_io_message"])
|
|
207
|
+
init_openmodule(self.zmq_config(), context=self.zmq_context(), sentry=True, dsn="http://test@test/1",
|
|
208
|
+
functions_to_ignore=["test"])
|
|
209
|
+
self.assertEqual(sentry._functions_to_ignore, ["test"])
|
|
210
|
+
|
|
187
211
|
|
|
188
212
|
class SentryTestCase(SentryTestMixin):
|
|
189
213
|
def setUp(self):
|
|
@@ -404,6 +428,94 @@ class SentryTestCase(SentryTestMixin):
|
|
|
404
428
|
ExampleClass.method()
|
|
405
429
|
self.assert_spans(span_recorder, ["func"])
|
|
406
430
|
|
|
431
|
+
def test_io_message_not_traced(self):
|
|
432
|
+
with sentry.continue_trace_zmq_message_receive("io", {}):
|
|
433
|
+
pass
|
|
434
|
+
with sentry.continue_trace_zmq_message_receive("not-io", {}):
|
|
435
|
+
pass
|
|
436
|
+
envelopes = self.get_sent_envelopes()
|
|
437
|
+
self.assertEqual(len(envelopes), 1)
|
|
438
|
+
self.assertEqual(len(envelopes[0].items), 1)
|
|
439
|
+
self.assertEqual(envelopes[0].items[0].payload.json["transaction"], "not-io/")
|
|
440
|
+
|
|
441
|
+
def test_ignored_function(self):
|
|
442
|
+
sentry._functions_to_ignore = ["test-ignore"]
|
|
443
|
+
with sentry.trace("test-ignore"):
|
|
444
|
+
pass
|
|
445
|
+
with sentry.trace("not-test-ignore"):
|
|
446
|
+
pass
|
|
447
|
+
envelopes = self.get_sent_envelopes()
|
|
448
|
+
self.assertEqual(len(envelopes), 1)
|
|
449
|
+
self.assertEqual(len(envelopes[0].items), 1)
|
|
450
|
+
self.assertEqual(envelopes[0].items[0].payload.json["transaction"], "not-test-ignore")
|
|
451
|
+
|
|
452
|
+
class SentryInDispatcherTestCase(SentryTestMixin):
|
|
453
|
+
def setUp(self):
|
|
454
|
+
super().setUp()
|
|
455
|
+
init_sentry("http://test@test/1")
|
|
456
|
+
sentry_sdk.get_client().options["traces_sample_rate"] = 1.0
|
|
457
|
+
self.dispatcher = None
|
|
458
|
+
|
|
459
|
+
def tearDown(self):
|
|
460
|
+
if self.dispatcher:
|
|
461
|
+
self.dispatcher.shutdown()
|
|
462
|
+
super().tearDown()
|
|
463
|
+
deinit_sentry()
|
|
464
|
+
|
|
465
|
+
def test_dispatcher(self):
|
|
466
|
+
def handler(*_):
|
|
467
|
+
pass
|
|
468
|
+
|
|
469
|
+
self.dispatcher = MessageDispatcher()
|
|
470
|
+
self.dispatcher.register_handler("test", ZMQMessage, handler, match_type=False, register_schema=False)
|
|
471
|
+
with sentry.trace("parent", sampled=True):
|
|
472
|
+
self.dispatcher.dispatch("test", ZMQMessage(type="test").dict())
|
|
473
|
+
|
|
474
|
+
envelopes = self.get_sent_envelopes()
|
|
475
|
+
self.assertEqual(len(envelopes), 1)
|
|
476
|
+
self.assertEqual(len(envelopes[0].items), 1)
|
|
477
|
+
self.assertEqual(envelopes[0].items[0].payload.json["transaction"], "parent")
|
|
478
|
+
self.assertEqual(len(envelopes[0].items[0].payload.json["spans"]), 2)
|
|
479
|
+
span_names = [span["description"] for span in envelopes[0].items[0].payload.json["spans"]]
|
|
480
|
+
handler_name = "message_handler.tests.test_sentry.SentryInDispatcherTestCase.test_dispatcher.<locals>.handler"
|
|
481
|
+
self.assertEqual(span_names, ["test/test", handler_name])
|
|
482
|
+
|
|
483
|
+
def test_io_handler_not_traced(self):
|
|
484
|
+
self.dispatcher = MessageDispatcher()
|
|
485
|
+
IoListener(self.dispatcher)
|
|
486
|
+
self.dispatcher.dispatch("io", IoMessage(edge=1, gateway=Gateway(gate="test", direction=Direction.IN),
|
|
487
|
+
type="io", pin="1", value=1).dict())
|
|
488
|
+
with self.assertRaises(TimeoutError):
|
|
489
|
+
self.get_sent_envelopes()
|
|
490
|
+
|
|
491
|
+
def test_multi_worker_dispatcher(self):
|
|
492
|
+
def handler(*_):
|
|
493
|
+
envelopes_got.wait(1)
|
|
494
|
+
handled.set()
|
|
495
|
+
|
|
496
|
+
handled = threading.Event()
|
|
497
|
+
envelopes_got = threading.Event()
|
|
498
|
+
self.dispatcher = MessageDispatcher(executor=ThreadPoolExecutor(max_workers=20))
|
|
499
|
+
self.dispatcher.register_handler("test", ZMQMessage, handler, match_type=False, register_schema=False)
|
|
500
|
+
with sentry.trace("parent", sampled=True):
|
|
501
|
+
self.dispatcher.dispatch("test", ZMQMessage(type="test").dict())
|
|
502
|
+
first_envelopes = self.get_sent_envelopes()
|
|
503
|
+
envelopes_got.set()
|
|
504
|
+
self.assertTrue(handled.wait(timeout=1))
|
|
505
|
+
second_envelopes = self.get_sent_envelopes(timeout=1)
|
|
506
|
+
self.assertEqual(len(first_envelopes), 1)
|
|
507
|
+
self.assertEqual(len(first_envelopes[0].items), 1)
|
|
508
|
+
self.assertEqual(first_envelopes[0].items[0].payload.json["transaction"], "parent")
|
|
509
|
+
self.assertEqual(len(first_envelopes[0].items[0].payload.json["spans"]), 0)
|
|
510
|
+
|
|
511
|
+
self.assertEqual(len(second_envelopes), 1)
|
|
512
|
+
self.assertEqual(len(second_envelopes[0].items), 1)
|
|
513
|
+
self.assertEqual(second_envelopes[0].items[0].payload.json["transaction"], "test/test")
|
|
514
|
+
self.assertEqual(len(second_envelopes[0].items[0].payload.json["spans"]), 1)
|
|
515
|
+
handler_name = ("message_handler.tests.test_sentry.SentryInDispatcherTestCase."
|
|
516
|
+
"test_multi_worker_dispatcher.<locals>.handler")
|
|
517
|
+
self.assertEqual(second_envelopes[0].items[0].payload.json["spans"][0]["description"], handler_name)
|
|
518
|
+
|
|
407
519
|
|
|
408
520
|
class SentryUtilsTestCase(SentryTestMixin):
|
|
409
521
|
@classmethod
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"git_version": "18fe816", "is_release": true}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|