openmodule 13.6.0__tar.gz → 14.0.1__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-13.6.0 → openmodule-14.0.1}/ChangeLog +12 -14
- {openmodule-13.6.0/openmodule.egg-info → openmodule-14.0.1}/PKG-INFO +1 -1
- {openmodule-13.6.0 → openmodule-14.0.1}/docs/getting_started.md +6 -4
- {openmodule-13.6.0 → openmodule-14.0.1}/docs/known_issues.md +3 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/docs/migrations.md +11 -0
- openmodule-14.0.1/docs/sentry.md +93 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/docs/settings.md +6 -6
- {openmodule-13.6.0 → openmodule-14.0.1}/docs/testing.md +53 -7
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/config.py +0 -8
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/connection_status.py +2 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/core.py +17 -17
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/dispatcher.py +20 -16
- openmodule-14.0.1/openmodule/logging.py +34 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/messaging.py +13 -6
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/models/base.py +3 -1
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/rpc/client.py +20 -16
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/rpc/server.py +60 -54
- openmodule-14.0.1/openmodule/sentry.py +412 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/utils/access_service.py +3 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/utils/csv_export.py +2 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/utils/databox.py +2 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/utils/eventlog.py +2 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/utils/io.py +2 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/utils/kv_store.py +8 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/utils/package_reader.py +6 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/utils/presence.py +7 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/utils/settings.py +3 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/utils/validation.py +2 -0
- {openmodule-13.6.0 → openmodule-14.0.1/openmodule.egg-info}/PKG-INFO +1 -1
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule.egg-info/SOURCES.txt +3 -0
- openmodule-14.0.1/openmodule.egg-info/pbr.json +1 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule.egg-info/requires.txt +1 -2
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule_test/interrupt.py +0 -1
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule_test/requirements.txt +0 -1
- openmodule-14.0.1/openmodule_test/sentry.py +65 -0
- openmodule-14.0.1/openmodule_test/utils.py +36 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/requirements.txt +1 -2
- {openmodule-13.6.0 → openmodule-14.0.1}/test-requirements.txt +0 -1
- openmodule-14.0.1/tests/sentry_main.py +32 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_core.py +26 -33
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_health.py +0 -1
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_interrupt.py +8 -8
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_logging.py +14 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_messaging.py +8 -4
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_mockrpcclient.py +0 -1
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_model.py +3 -2
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_rpc.py +16 -10
- openmodule-14.0.1/tests/test_sentry.py +747 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tox.ini +1 -1
- openmodule-13.6.0/openmodule/logging.py +0 -12
- openmodule-13.6.0/openmodule/sentry.py +0 -103
- openmodule-13.6.0/openmodule.egg-info/pbr.json +0 -1
- openmodule-13.6.0/openmodule_test/utils.py +0 -9
- openmodule-13.6.0/tests/test_sentry.py +0 -175
- {openmodule-13.6.0 → openmodule-14.0.1}/.gitlab-ci.yml +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/AUTHORS +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/LICENSE +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/README.md +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/docs/access_service.md +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/docs/anonymization.md +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/docs/cleanup.md +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/docs/coding_standard.md +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/docs/commands.md +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/docs/connection_status_listener.md +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/docs/csv_export.md +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/docs/database.md +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/docs/deprecated.md +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/docs/deprecated_code/README.md +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/docs/deprecated_code/access_service/openmodule/models/access_service.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/docs/deprecated_code/access_service/openmodule/utils/access_service.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/docs/deprecated_code/access_service/openmodule_test/access_service.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/docs/deprecated_code/access_service/tests/test_utils_access_service.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/docs/deprecated_code/api/openmodule/utils/api.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/docs/deprecated_code/api/openmodule_test/api.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/docs/deprecated_code/api/tests/test_utils_api.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/docs/deprecated_code/package_reader/openmodule/utils/package_reader.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/docs/deprecated_code/package_reader/openmodule_test/fake_package_creator.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/docs/deprecated_code/package_reader/tests/test_package_reader.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/docs/event_sending.md +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/docs/health.md +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/docs/images/broker.drawio.png +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/docs/package_reader.md +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/docs/rpc.md +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/docs/settings_provider.md +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/docs/translation.md +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/docs/utils.md +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/__init__.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/alert.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/database/custom_types.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/database/database.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/database/env.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/database/migration.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/health.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/models/__init__.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/models/access_service.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/models/alert.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/models/io.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/models/kv_store.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/models/presence.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/models/privacy.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/models/rpc.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/models/settings.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/models/validation.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/models/vehicle.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/rpc/__init__.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/rpc/common.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/threading.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/utils/__init__.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/utils/charset.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/utils/cleanup.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/utils/db_helper.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/utils/matching.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/utils/misc_functions.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/utils/schema.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule/utils/translation.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule.egg-info/dependency_links.txt +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule.egg-info/not-zip-safe +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule.egg-info/top_level.txt +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule_commands/__init__.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule_commands/setup.cfg +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule_commands/setup.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule_commands/translate.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule_test/__init__.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule_test/alert.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule_test/connection_status.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule_test/core.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule_test/database.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule_test/eventlistener.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule_test/files.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule_test/gate.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule_test/health.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule_test/io_simulator.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule_test/package_reader.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule_test/presence.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule_test/rpc.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule_test/settings.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule_test/setup.cfg +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule_test/setup.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/openmodule_test/zeromq.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/setup.cfg +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/setup.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/__init__.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/config.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/database_models_migration.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/database_models_test.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/invalid_database/alembic/README +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/invalid_database/alembic/__init__.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/invalid_database/alembic/env.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/invalid_database/alembic/script.py.mako +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/invalid_database/alembic/versions/ff26e54332f9_datetime_models.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/invalid_database/alembic.ini +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/invalid_database/makemigration.sh +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/migration_double_column_delete_error/alembic/__init__.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/migration_double_column_delete_error/alembic/env.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/migration_double_column_delete_error/alembic/script.py.mako +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/migration_double_column_delete_error/alembic/versions/812a3e5b8517_initial.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/migration_double_column_delete_error/alembic/versions/a7ea100a784f_key_error.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/migration_double_column_delete_error/alembic.ini +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/migration_double_column_delete_error/makemigration.sh +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/migration_no_such_table_error/alembic/__init__.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/migration_no_such_table_error/alembic/env.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/migration_no_such_table_error/alembic/script.py.mako +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/migration_no_such_table_error/alembic/versions/812a3e5b8517_initial.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/migration_no_such_table_error/alembic/versions/a7ea100a784f_no_such_table_error.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/migration_no_such_table_error/alembic.ini +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/migration_no_such_table_error/makemigration.sh +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/migration_test_database/__init__.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/migration_test_database/alembic/__init__.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/migration_test_database/alembic/env.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/migration_test_database/alembic/script.py.mako +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/migration_test_database/alembic/versions/19789aa5361c_initial.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/migration_test_database/alembic/versions/19d887929ae7_alter.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/migration_test_database/alembic/versions/__init__.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/migration_test_database/alembic.ini +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/migration_test_database/alembic_migration_test_database.sqlite3 +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/migration_test_database/makemigration.sh +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/resources/configs/config.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/resources/configs/test_config.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/resources/configs/test_config_1.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/resources/standard_schemes/DEFAULT-10.yml +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/resources/standard_schemes/DEFAULT-20.yml +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/resources/standard_schemes/LEGACY-0.yml +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/resources/translation/locale/de/LC_MESSAGES/translation.mo +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/resources/translation/locale/de/LC_MESSAGES/translation.po +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/resources/translation/locale/en/LC_MESSAGES/translation.mo +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/resources/translation/locale/en/LC_MESSAGES/translation.po +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/resources/translation/locale/translation.pot +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/resources/translation/translate.sh +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/resources/utils_matching/A-10.yml +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/resources/utils_matching/A-20.yml +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/resources/utils_matching/DEFAULT-10.yml +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/resources/utils_matching/DEFAULT-20.yml +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/resources/utils_matching/DEFAULT-30.yml +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/resources/utils_matching/LEGACY-0.yml +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/resources/utils_matching/TEST-10.yml +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/resources/utils_matching/TEST-20.yml +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/resources/utils_matching/TEST-30.yml +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/resources/utils_matching/TEST-40.yml +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_access_service_database/alembic/__init__.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_access_service_database/alembic/env.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_access_service_database/alembic/script.py.mako +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_access_service_database/alembic/versions/7bd4fcd38fde_removed_nfc_and_pin.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_access_service_database/alembic/versions/9ca98a2e5674_added_parksettings_id.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_access_service_database/alembic/versions/c821971f9230_initial.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_access_service_database/alembic.ini +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_access_service_database/makemigration.sh +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_alembic_migrations.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_alert.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_checks.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_config.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_connection_status.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_database/alembic/__init__.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_database/alembic/env.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_database/alembic/script.py.mako +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_database/alembic/versions/32b8c728abbf_initial.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_database/alembic.ini +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_database/makemigration.sh +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_database.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_dispatcher.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_io_listen.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_kv_store_database/alembic/__init__.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_kv_store_database/alembic/env.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_kv_store_database/alembic/script.py.mako +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_kv_store_database/alembic/versions/9c5c944221f4_deprecated_kv_entry_example.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_kv_store_database/alembic/versions/c55a69026a25_initial.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_kv_store_database/alembic.ini +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_kv_store_database/makemigration.sh +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_kv_store_multiple_database/alembic/README +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_kv_store_multiple_database/alembic/__init__.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_kv_store_multiple_database/alembic/env.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_kv_store_multiple_database/alembic/script.py.mako +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_kv_store_multiple_database/alembic/versions/cdb3214131a9_initial.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_kv_store_multiple_database/alembic.ini +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_kv_store_multiple_database/makemigration.sh +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_schema.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_test_alert.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_test_gate.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_test_zeromq.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_utils_access_service.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_utils_charset.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_utils_cleanup.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_utils_csv_export.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_utils_databox.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_utils_eventlog.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_utils_kv_store.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_utils_kv_store_multiple.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_utils_matching.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_utils_misc_functions.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_utils_package_reader.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_utils_presence.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_utils_settings.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_utils_validation.py +0 -0
- {openmodule-13.6.0 → openmodule-14.0.1}/tests/test_utils_vehicle.py +0 -0
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
CHANGES
|
|
2
2
|
=======
|
|
3
3
|
|
|
4
|
+
v14.0.1
|
|
5
|
+
-------
|
|
6
|
+
|
|
7
|
+
* fixed sentry release name
|
|
8
|
+
|
|
9
|
+
v14.0.0
|
|
10
|
+
-------
|
|
11
|
+
|
|
12
|
+
* Add breaking changes to docs
|
|
13
|
+
* OM-693 Openmodule sentry v2
|
|
14
|
+
* Update known\_issues.md [skip ci]
|
|
15
|
+
|
|
4
16
|
v13.6.0
|
|
5
17
|
-------
|
|
6
18
|
|
|
@@ -151,9 +163,6 @@ v12.0.0.rc0
|
|
|
151
163
|
* schedule exports utility
|
|
152
164
|
* SettingsProvider docs
|
|
153
165
|
* SettingsProvider docs
|
|
154
|
-
* added settings\_models requirement, marking Test\* classes that are not tests with \_\_test\_\_ = False
|
|
155
|
-
* AAAAAAAABBBBBBBBBBBBBBMerge branch 'master' into DEV-5415
|
|
156
|
-
* [skip ci] Broken until settings\_model pip package is fixed. Removed deprecated features for v12. Using settings\_models in SettingsProvider
|
|
157
166
|
|
|
158
167
|
v11.1.1
|
|
159
168
|
-------
|
|
@@ -199,14 +208,3 @@ v10.0.3
|
|
|
199
208
|
-------
|
|
200
209
|
|
|
201
210
|
* added freezegun and fakeredis to openmodule requirements
|
|
202
|
-
|
|
203
|
-
v10.0.2
|
|
204
|
-
-------
|
|
205
|
-
|
|
206
|
-
* touching a filer, since the tag's job is skipped because the commit mentioned 'sk\_ip ci'
|
|
207
|
-
|
|
208
|
-
v10.0.2.rc2
|
|
209
|
-
-----------
|
|
210
|
-
|
|
211
|
-
* added more documentation [skip ci]
|
|
212
|
-
* fixes an issue in the multiprocessing\_logging package in testcases
|
|
@@ -12,7 +12,7 @@ All device services connect to the broker. Device services use the `SUB` port of
|
|
|
12
12
|
and the `PUB` port to receive messages.
|
|
13
13
|
|
|
14
14
|
We are send [multipart messages](https://zguide.zeromq.org/docs/chapter2/#Multipart-Messages) to the broker.
|
|
15
|
-
The multipart message consists of a `topic` and a `payload`. The `topic` is used to route the message to possible
|
|
15
|
+
The multipart message consists of a `topic` and a `payload`. The `topic` is used to route the message to possible
|
|
16
16
|
multiple device services (Broadcast). The `payload` is a JSON string containing the actual data.
|
|
17
17
|
|
|
18
18
|

|
|
@@ -75,6 +75,7 @@ The Openmodule will raise an `AssertionError` if the validator is missing.
|
|
|
75
75
|
### Project Structure
|
|
76
76
|
|
|
77
77
|
The Openmodule is structured in the following way:
|
|
78
|
+
|
|
78
79
|
```
|
|
79
80
|
openmodule/
|
|
80
81
|
├── openmodule/
|
|
@@ -97,6 +98,7 @@ The `openmodule_commands` folder contains some utility commands like for example
|
|
|
97
98
|
### Project Structure of a Device Service
|
|
98
99
|
|
|
99
100
|
A typical device service has the following structure:
|
|
101
|
+
|
|
100
102
|
```
|
|
101
103
|
device-service/
|
|
102
104
|
├── docker/
|
|
@@ -121,7 +123,7 @@ The YAML file `default.yml` is an optional additional config file if you need a
|
|
|
121
123
|
|
|
122
124
|
The `src` folder contains the actual source code of the device service. The `app.py` file contains the main function
|
|
123
125
|
of the device service. An example of the `app.py` is shown in the section
|
|
124
|
-
[Create a Openmodule Instance](getting_started.md#create-a-openmodule-instance).
|
|
126
|
+
[Create a Openmodule Instance](getting_started.md#create-a-openmodule-instance).
|
|
125
127
|
This example of the `app.py` file was copied from our template project.
|
|
126
128
|
The `config.py` file contains the configuration of the device service. The `models.py` file
|
|
127
129
|
should hold all models that are used in the device service.
|
|
@@ -184,7 +186,7 @@ To solve this migrate your model definition and the YAML initialization
|
|
|
184
186
|
|
|
185
187
|
The first step that are you have to do is to create an instance of the Openmodule class.
|
|
186
188
|
Below you see an example of the main Python file `app.py`. This file was copied from our template project and
|
|
187
|
-
you do not have to manually create it.
|
|
189
|
+
you do not have to manually create it. You also need to provide a Sentry DSN to the Openmodule.
|
|
188
190
|
|
|
189
191
|
```python
|
|
190
192
|
import logging
|
|
@@ -204,7 +206,7 @@ def main_wrapper():
|
|
|
204
206
|
|
|
205
207
|
|
|
206
208
|
def main():
|
|
207
|
-
core = init_openmodule(settings)
|
|
209
|
+
core = init_openmodule(settings, dsn="https://<key>@debug.acc.si/<project>")
|
|
208
210
|
try:
|
|
209
211
|
while True:
|
|
210
212
|
time.sleep(1)
|
|
@@ -5,6 +5,9 @@ version. The changelog may contain many other notes aswell.
|
|
|
5
5
|
|
|
6
6
|
The version numbers below always note the _version through which the issue was fixed_.
|
|
7
7
|
|
|
8
|
+
## 13.6.0
|
|
9
|
+
* fixed message dispatcher trying to handle messages after shutdown was called
|
|
10
|
+
|
|
8
11
|
## 13.1.2
|
|
9
12
|
|
|
10
13
|
* fixed error output on RPCs not sent by this RPCClient
|
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Breaking Version Changes
|
|
2
2
|
|
|
3
|
+
## 14.0.0
|
|
4
|
+
* sentry_sdk version was updated
|
|
5
|
+
* redis was removed
|
|
6
|
+
* The `RPCServer` does no longer call `os._exit` if `"status"` is in the handler return value.
|
|
7
|
+
It raises a `ValueError` instead.
|
|
8
|
+
* The `init_openmodule` now takes a sentry `dsn` as an argument. This is required if sentry is enabled
|
|
9
|
+
(is enabled by default if not `TESTING` and not `DEBUG`).
|
|
10
|
+
* The `receive_message_from_socket` is now a context manager and should be used with a `with` statement.
|
|
11
|
+
This was done, so that any received zmq message automatically continues an existing sentry trace.
|
|
12
|
+
* Example: `with receive_message_from_socket(socket) as (topic, message):`
|
|
13
|
+
|
|
3
14
|
## 13.6.0
|
|
4
15
|
* messaging:
|
|
5
16
|
* the `get_pub_socket` now raises an AssertionError because we no longer support multiple publishers.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
from openmodule.core import init_openmodule
|
|
2
|
+
|
|
3
|
+
# Sentry
|
|
4
|
+
|
|
5
|
+
[TOC]
|
|
6
|
+
|
|
7
|
+
## Introduction
|
|
8
|
+
|
|
9
|
+
Sentry is a service that helps us monitor and fix errors in our applications. It provides real-time error tracking and
|
|
10
|
+
notifications.
|
|
11
|
+
|
|
12
|
+
The Python Sentry SDK automatically creates events from uncaught exceptions and logs of level `error` and above.
|
|
13
|
+
All error logs and exceptions are part of a transaction, even if no trace is created. So adding additional context to a
|
|
14
|
+
transaction will also apply to the error logs and exceptions.
|
|
15
|
+
|
|
16
|
+
It also provides tools for tracing process flows and diagnosing performance issues.
|
|
17
|
+
|
|
18
|
+
## Initialization
|
|
19
|
+
|
|
20
|
+
To use Sentry, you need to provide the DSN to the OpenModuleCore initialization function. The DSN is a unique identifier
|
|
21
|
+
for your project that tells the SDK where to send the events. You can find the DSN in the Sentry project settings.
|
|
22
|
+
|
|
23
|
+
* During Testing and Development, sentry will not be initialized, and no events will be sent.
|
|
24
|
+
* You can provide additional [sentry options](https://docs.sentry.io/platforms/python/configuration/options/) as keyword
|
|
25
|
+
arguments to the `init_openmodule` function (`server_name` and `environment` cannot be overriden).
|
|
26
|
+
* the `extras` keyword argument can be used to provide additional data to the Sentry SDK
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
def main():
|
|
30
|
+
core = init_openmodule(settings, dsn="https://<key>@debug.acc.si/<project>")
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Errors & Exceptions
|
|
34
|
+
|
|
35
|
+
Uncaught exceptions and `logging.exception(...)` calls are automatically captured by Sentry and turned into issues with
|
|
36
|
+
a stack trace. `logging.error(...)` calls are also captured, but without a stack trace, so it's better to use
|
|
37
|
+
`logging.exception(...)` when possible.
|
|
38
|
+
|
|
39
|
+
### requests raise_for_status
|
|
40
|
+
|
|
41
|
+
When using the `requests` library, you can use the `raise_for_status` method to raise an exception if the request was
|
|
42
|
+
unsuccessful. This will cause sentry to automatically add the response body to the current transaction.
|
|
43
|
+
|
|
44
|
+
## Tracing
|
|
45
|
+
|
|
46
|
+
Openmodule provides the `sentry.trace` function that can be used as a decorator to trace a function or as a context
|
|
47
|
+
manager to trace a block of code. This will create a new span for the function or block of code and record its duration.
|
|
48
|
+
If no transaction is active, a new transaction will be created before the span.
|
|
49
|
+
|
|
50
|
+
* When using the decorator, the span will have the (qual)name of the function (if none is provided).
|
|
51
|
+
* When using the context manager, you **should** provide a name for the span.
|
|
52
|
+
* In addition to name, the op parameter can be used to specify the operation type of the span.
|
|
53
|
+
(default is `function` and should be sufficient for most cases, others can be found
|
|
54
|
+
[here](https://develop.sentry.dev/sdk/telemetry/traces/span-operations/).)
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
from openmodule import sentry
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@sentry.trace
|
|
61
|
+
def my_function():
|
|
62
|
+
pass
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
@sentry.trace(name="other_function")
|
|
66
|
+
def my_function2():
|
|
67
|
+
pass
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
with sentry.trace("my_block"):
|
|
71
|
+
pass
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Adding Additional Information
|
|
75
|
+
|
|
76
|
+
You can add context to the current transaction using one of the following methods:
|
|
77
|
+
|
|
78
|
+
* `sentry_sdk.set_tag(key: str, value: str)`: Adds
|
|
79
|
+
a [tag](https://docs.sentry.io/platforms/python/enriching-events/tags/) to the current transaction.
|
|
80
|
+
* `sentry_sdk.set_tags(**key_value_pairs: str)`:
|
|
81
|
+
Adds [tags](https://docs.sentry.io/platforms/python/enriching-events/tags/) to the current transaction.
|
|
82
|
+
* `sentry_sdk.set_context(key: str, value: Any)`: Adds
|
|
83
|
+
a [context](https://docs.sentry.io/platforms/python/enriching-events/context/) to the current transaction.
|
|
84
|
+
* `sentry_sdk.set_extra(key: str, value: Any)`: Adds extra data to the current transaction. (similar to tags, but not
|
|
85
|
+
indexed for searching and more free-form)
|
|
86
|
+
|
|
87
|
+
```python
|
|
88
|
+
with sentry.trace("my_block"):
|
|
89
|
+
sentry_sdk.set_tag("key", "value")
|
|
90
|
+
sentry_sdk.set_tags({"key1": "value1", "key2": "value2"})
|
|
91
|
+
sentry_sdk.set_context("key", {"whatever": "you want"})
|
|
92
|
+
sentry_sdk.set_extra("key", "value")
|
|
93
|
+
```
|
|
@@ -47,14 +47,14 @@ class GlobalSettings:
|
|
|
47
47
|
BROKER_SUB = broker_sub()
|
|
48
48
|
BROKER_PUB = broker_pub()
|
|
49
49
|
|
|
50
|
-
LOCAL_DEVELOPMENT = bool("LOCAL_DEVELOPMENT", False)
|
|
51
50
|
is_bridged_slave = is_bridged_slave()
|
|
52
51
|
DIST_FOLDER = dist_folder()
|
|
53
52
|
DEV_DEVICE = dev_device()
|
|
54
53
|
|
|
55
|
-
#
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
54
|
+
# translation
|
|
55
|
+
LOCALE_DIR = locale_dir()
|
|
56
|
+
LANGUAGE = "" if testing() else string("LANGUAGE", "de").lower()
|
|
57
|
+
|
|
58
|
+
# databox
|
|
59
|
+
DATABOX_UPLOAD_DIR = string("DATABOX_UPLOAD_DIR", "/upload")
|
|
60
60
|
```
|
|
@@ -154,8 +154,8 @@ Mixin for testing alembic migrations. Tests start with a clean database without
|
|
|
154
154
|
|
|
155
155
|
You can also provide your own sqlite3 database that will be copied for each test.
|
|
156
156
|
|
|
157
|
-
**⚠ Do not use the database models defined in your app for these tests.**
|
|
158
|
-
Instead use the `AlembicMigrationTestMixin.get_model`method to get the model from the database schema.
|
|
157
|
+
**⚠ Do not use the database models defined in your app for these tests.**
|
|
158
|
+
Instead use the `AlembicMigrationTestMixin.get_model`method to get the model from the database schema.
|
|
159
159
|
Your Source code will not work with models from a different database revision. Do not call any functions that rely on
|
|
160
160
|
the database models in your tests.
|
|
161
161
|
|
|
@@ -326,7 +326,8 @@ shut down within 3 seconds and print that it hase received a KeyboardInterrupt.
|
|
|
326
326
|
|
|
327
327
|
Since main tests are somewhat complex, we provide some examples for different use cases.
|
|
328
328
|
|
|
329
|
-
**Wait for an RPC server to be started, and send a test RPC. Also ensure that the service sends a specific message on
|
|
329
|
+
**Wait for an RPC server to be started, and send a test RPC. Also ensure that the service sends a specific message on
|
|
330
|
+
start and stop (basic backend test case).**
|
|
330
331
|
|
|
331
332
|
```python
|
|
332
333
|
class MainTest(RPCServerTestMixin, MainTestMixin):
|
|
@@ -340,12 +341,16 @@ class MainTest(RPCServerTestMixin, MainTestMixin):
|
|
|
340
341
|
self.assertEqual("register", register_request.get("type"))
|
|
341
342
|
|
|
342
343
|
# wait for the rpc server to become responsive
|
|
343
|
-
self.wait_for_rpc_response("backend", "auth",
|
|
344
|
+
self.wait_for_rpc_response("backend", "auth",
|
|
345
|
+
AccessRequest(name=settings.NAME, medium_id="GARIVO1", medium_type="lpr"),
|
|
346
|
+
AccessResponse)
|
|
344
347
|
|
|
345
348
|
# make a test request
|
|
346
|
-
response = self.rpc("backend", "auth",
|
|
349
|
+
response = self.rpc("backend", "auth",
|
|
350
|
+
AccessRequest(name=settings.NAME, medium_id="GARIVO1", medium_type="lpr"),
|
|
351
|
+
AccessResponse)
|
|
347
352
|
self.assertEqual("GARIVO1", response.medium_id)
|
|
348
|
-
|
|
353
|
+
|
|
349
354
|
finally:
|
|
350
355
|
self.send_signal_to_process(process, signal.SIGTERM)
|
|
351
356
|
self.assertCleanShutdown(process)
|
|
@@ -445,8 +450,49 @@ finally:
|
|
|
445
450
|
Another fix is setting the `log_config` to `None`, but with this setting the Uvicorn log output is disabled
|
|
446
451
|
for `python -m tox` command.
|
|
447
452
|
|
|
453
|
+
## Utils
|
|
454
|
+
|
|
455
|
+
### DeveloperError
|
|
456
|
+
|
|
457
|
+
Can be used to raise an error in the test code (e.g. when mocking a function and wanting an unimplemented error)
|
|
458
|
+
|
|
459
|
+
```python
|
|
460
|
+
def test():
|
|
461
|
+
def mocker():
|
|
462
|
+
raise DeveloperError("This function should not be called")
|
|
463
|
+
|
|
464
|
+
with mock.patch("module.func", mocker):
|
|
465
|
+
with self.assertRaises(DeveloperError):
|
|
466
|
+
module.function_that_calls_func()
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
### wait_for_value
|
|
470
|
+
|
|
471
|
+
This function waits until the given `getter` function returns the expected value or the timeout is reached.
|
|
472
|
+
That is useful when you want to wait for a value to change in another thread.
|
|
473
|
+
|
|
474
|
+
If no `target` is given, it waits until the `getter` function returns a value that is different from the initial value.
|
|
475
|
+
**warning**: The getter function might return the 'changed' value in the initial call, which would lead to no change
|
|
476
|
+
happening.
|
|
477
|
+
|
|
478
|
+
`invert_target` can be set to True to wait for the getter function to return a value that is different from the target.
|
|
479
|
+
|
|
480
|
+
```python
|
|
481
|
+
class Test(TestCase):
|
|
482
|
+
def get_value(self):
|
|
483
|
+
return self.whatever
|
|
484
|
+
|
|
485
|
+
def change_value(self):
|
|
486
|
+
time.sleep(1)
|
|
487
|
+
self.whatever = 2
|
|
488
|
+
|
|
489
|
+
def test(self):
|
|
490
|
+
self.whatever = 1
|
|
491
|
+
threading.Thread(target=self.change_value).start()
|
|
492
|
+
self.whatever = wait_for_value(self.get_value, 2)
|
|
493
|
+
```
|
|
494
|
+
|
|
448
495
|
## Exit with Error 112
|
|
449
496
|
|
|
450
497
|
Whenever the RPCServer finds a RPCResponse model containing a `status` field, a log line is printed and the process is
|
|
451
498
|
terminated with error code 112. The log line might not be printed in some cases, so watch out for 112
|
|
452
|
-
|
|
@@ -483,19 +483,11 @@ class GlobalSettings:
|
|
|
483
483
|
BROKER_SUB = broker_sub()
|
|
484
484
|
BROKER_PUB = broker_pub()
|
|
485
485
|
|
|
486
|
-
LOCAL_DEVELOPMENT = bool("LOCAL_DEVELOPMENT", False)
|
|
487
486
|
COMPUTE_ID = compute_id()
|
|
488
487
|
DAEMON = bool("DAEMON", False)
|
|
489
488
|
DIST_FOLDER = dist_folder()
|
|
490
489
|
DEV_DEVICE = dev_device()
|
|
491
490
|
|
|
492
|
-
# redis
|
|
493
|
-
REDIS_HOST = string("REDIS_HOST", "localhost")
|
|
494
|
-
REDIS_PASSWORD = string("REDIS_PASSWORD", "") or None
|
|
495
|
-
REDIS_PORT = int("REDIS_PORT", 6379)
|
|
496
|
-
REDIS_DB = int("REDIS_DB", 0)
|
|
497
|
-
REDIS_CONNECTION_STATUS_KEY = string("REDIS_CONNECTION_STATUS_KEY", "device_connection_status")
|
|
498
|
-
|
|
499
491
|
# translation
|
|
500
492
|
LOCALE_DIR = locale_dir()
|
|
501
493
|
LANGUAGE = "" if testing() else string("LANGUAGE", "de").lower()
|
|
@@ -4,6 +4,7 @@ import time
|
|
|
4
4
|
from enum import Enum
|
|
5
5
|
from typing import Optional, Set
|
|
6
6
|
|
|
7
|
+
from openmodule import sentry
|
|
7
8
|
from openmodule.dispatcher import MessageDispatcher
|
|
8
9
|
from openmodule.models.base import ZMQMessage, OpenModuleModel
|
|
9
10
|
|
|
@@ -98,6 +99,7 @@ class ConnectionStatusListener:
|
|
|
98
99
|
self._log.debug("Connection status message timeout")
|
|
99
100
|
self._set(ConnectionStatus.shutdown)
|
|
100
101
|
|
|
102
|
+
@sentry.trace
|
|
101
103
|
def get_current_status(self) -> ConnectionRPCResponse:
|
|
102
104
|
"""Checks the current_status by sending an RPC to om_rpc_client"""
|
|
103
105
|
try:
|
|
@@ -9,6 +9,7 @@ from concurrent.futures.thread import ThreadPoolExecutor
|
|
|
9
9
|
import zmq
|
|
10
10
|
from typing import Optional
|
|
11
11
|
|
|
12
|
+
from openmodule import sentry
|
|
12
13
|
from openmodule.alert import AlertHandler
|
|
13
14
|
from openmodule.config import validate_config_module
|
|
14
15
|
from openmodule.dispatcher import ZMQMessageDispatcher
|
|
@@ -71,9 +72,9 @@ class OpenModuleCore(threading.Thread):
|
|
|
71
72
|
def _run(self):
|
|
72
73
|
try:
|
|
73
74
|
while True:
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
with receive_message_from_socket(self.sub_socket) as (topic, message):
|
|
76
|
+
if topic is not None:
|
|
77
|
+
self.messages.dispatch(topic, message)
|
|
77
78
|
except zmq.ContextTerminated:
|
|
78
79
|
self.log.debug("context terminated, core shutting down")
|
|
79
80
|
finally:
|
|
@@ -84,15 +85,16 @@ class OpenModuleCore(threading.Thread):
|
|
|
84
85
|
def _run_internal(self):
|
|
85
86
|
try:
|
|
86
87
|
while True:
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
88
|
+
with receive_message_from_socket(self.sub_socket_internal) as (topic, message):
|
|
89
|
+
if topic is not None:
|
|
90
|
+
self._messages_internal.dispatch(topic, message)
|
|
91
|
+
self.connection_listener.check_timeout()
|
|
91
92
|
except zmq.ContextTerminated:
|
|
92
93
|
pass
|
|
93
94
|
finally:
|
|
94
95
|
self.sub_socket_internal.close()
|
|
95
96
|
|
|
97
|
+
@sentry.trace(op="topic.send")
|
|
96
98
|
def publish(self, message: ZMQMessage, topic: str):
|
|
97
99
|
assert isinstance(topic, str), "topic must be a string"
|
|
98
100
|
|
|
@@ -134,10 +136,10 @@ def print_environment(core: OpenModuleCore):
|
|
|
134
136
|
)
|
|
135
137
|
|
|
136
138
|
|
|
137
|
-
def init_openmodule(config, sentry=None, logging=True, dsgvo=True,
|
|
139
|
+
def init_openmodule(config, *, dsn: str = None, sentry=None, logging=True, dsgvo=True,
|
|
138
140
|
health_handler: Optional[HealthHandlerType] = None,
|
|
139
141
|
context=None, database=False, catch_sigterm=True,
|
|
140
|
-
dispatcher_max_threads=1, wait_for_broker=True) -> OpenModuleCore:
|
|
142
|
+
dispatcher_max_threads=1, wait_for_broker=True, **sentry_kwargs) -> OpenModuleCore:
|
|
141
143
|
if health_handler:
|
|
142
144
|
warnings.warn(
|
|
143
145
|
"health_handler is deprecated, and will simply be ignored. Please use metrics "
|
|
@@ -172,18 +174,16 @@ def init_openmodule(config, sentry=None, logging=True, dsgvo=True,
|
|
|
172
174
|
# we activate sentry if
|
|
173
175
|
# -> sentry=None (default) -> then we only activate in production
|
|
174
176
|
# -> sentry=True/False this overrides and we activate/deactivate as desired
|
|
175
|
-
activate_sentry = False
|
|
176
177
|
if sentry is None:
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
else:
|
|
178
|
+
sentry = should_activate_sentry()
|
|
179
|
+
if not sentry:
|
|
180
180
|
_core_thread.log.info("not activating sentry in debug or test mode")
|
|
181
|
-
else:
|
|
182
|
-
activate_sentry = sentry
|
|
183
181
|
|
|
184
|
-
if
|
|
182
|
+
if sentry:
|
|
183
|
+
if dsn is None:
|
|
184
|
+
raise ValueError("sentry DSN is required")
|
|
185
|
+
init_sentry(dsn, **sentry_kwargs)
|
|
185
186
|
_core_thread.sentry_was_initialized = True
|
|
186
|
-
init_sentry(_core_thread)
|
|
187
187
|
|
|
188
188
|
if dsgvo:
|
|
189
189
|
init_dsgvo_config()
|
|
@@ -12,7 +12,9 @@ from typing import Union, Optional, Callable, DefaultDict, List, Dict, TypeVar,
|
|
|
12
12
|
|
|
13
13
|
import zmq
|
|
14
14
|
from pydantic import ValidationError, BaseModel, parse_obj_as
|
|
15
|
+
from sentry_sdk.utils import qualname_from_function
|
|
15
16
|
|
|
17
|
+
from openmodule import sentry
|
|
16
18
|
from openmodule.config import settings
|
|
17
19
|
from openmodule.models.base import ZMQMessage
|
|
18
20
|
from openmodule.utils.schema import Schema
|
|
@@ -199,26 +201,28 @@ class MessageDispatcher:
|
|
|
199
201
|
listeners = self.listeners.get(topic, [])
|
|
200
202
|
for listener in listeners:
|
|
201
203
|
if listener.matches(message):
|
|
202
|
-
self.executor.submit(self.execute, listener, message)
|
|
204
|
+
self.executor.submit(self.execute, topic, listener, message)
|
|
203
205
|
|
|
204
|
-
def execute(self, listener: Listener, message: Dict):
|
|
205
|
-
|
|
206
|
-
parsed_message = parse_obj_as(listener.message_class, message)
|
|
207
|
-
except ValidationError as e:
|
|
208
|
-
if self.raise_validation_errors:
|
|
209
|
-
raise e from None
|
|
210
|
-
else:
|
|
211
|
-
self.log.exception("Invalid message received")
|
|
212
|
-
else:
|
|
206
|
+
def execute(self, topic: str, listener: Listener, message: Dict):
|
|
207
|
+
with sentry.continue_trace_zmq_message_process(topic, message):
|
|
213
208
|
try:
|
|
214
|
-
listener.
|
|
215
|
-
except
|
|
216
|
-
|
|
217
|
-
except Exception as e:
|
|
218
|
-
if self.raise_handler_errors:
|
|
209
|
+
parsed_message = parse_obj_as(listener.message_class, message)
|
|
210
|
+
except ValidationError as e:
|
|
211
|
+
if self.raise_validation_errors:
|
|
219
212
|
raise e from None
|
|
220
213
|
else:
|
|
221
|
-
self.log.exception("
|
|
214
|
+
self.log.exception("Invalid message received")
|
|
215
|
+
else:
|
|
216
|
+
try:
|
|
217
|
+
with sentry.trace(f"message_handler.{qualname_from_function(listener.handler)}"):
|
|
218
|
+
listener.handler(parsed_message)
|
|
219
|
+
except zmq.ContextTerminated:
|
|
220
|
+
raise
|
|
221
|
+
except Exception as e:
|
|
222
|
+
if self.raise_handler_errors:
|
|
223
|
+
raise e from None
|
|
224
|
+
else:
|
|
225
|
+
self.log.exception("Error in message handler")
|
|
222
226
|
|
|
223
227
|
|
|
224
228
|
class SubscribingMessageDispatcher(MessageDispatcher):
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
import requests
|
|
5
|
+
|
|
6
|
+
_patched_exceptions = set()
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def _patch_requests_library():
|
|
10
|
+
"""Adds the response text to the string representation of a requests.RequestException"""
|
|
11
|
+
if requests.RequestException in _patched_exceptions:
|
|
12
|
+
return
|
|
13
|
+
_patched_exceptions.add(requests.RequestException)
|
|
14
|
+
|
|
15
|
+
original_exception_string = requests.RequestException.__str__
|
|
16
|
+
|
|
17
|
+
def new_exception_string(self: requests.RequestException):
|
|
18
|
+
ret_str = original_exception_string(self)
|
|
19
|
+
if self.response is not None:
|
|
20
|
+
ret_str = f"{ret_str}: {self.response.text[:1000]}"
|
|
21
|
+
return ret_str
|
|
22
|
+
|
|
23
|
+
setattr(requests.RequestException, "__str__", new_exception_string)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def init_logging(core):
|
|
27
|
+
assert hasattr(core.config, "LOG_LEVEL"), (
|
|
28
|
+
"LOG_LEVEL setting not found in your config. In order to use logging please add \n"
|
|
29
|
+
"> LOG_LEVEL = config.log_level()\n"
|
|
30
|
+
"to your config.py"
|
|
31
|
+
)
|
|
32
|
+
_patch_requests_library()
|
|
33
|
+
logging.basicConfig(level=core.config.LOG_LEVEL, stream=sys.stdout)
|
|
34
|
+
logging.captureWarnings(True)
|
|
@@ -3,11 +3,13 @@ import logging
|
|
|
3
3
|
import random
|
|
4
4
|
import string
|
|
5
5
|
import time
|
|
6
|
+
from contextlib import contextmanager
|
|
6
7
|
from typing import Optional, Tuple, Dict
|
|
7
8
|
|
|
8
9
|
import orjson
|
|
9
10
|
import zmq
|
|
10
11
|
|
|
12
|
+
from openmodule import sentry
|
|
11
13
|
from openmodule.dispatcher import MessageDispatcher
|
|
12
14
|
from openmodule.models.base import ZMQMessage
|
|
13
15
|
|
|
@@ -80,16 +82,19 @@ def wait_for_connection(dispatcher: MessageDispatcher, pub_socket=None, pub_lock
|
|
|
80
82
|
raise TimeoutError("could not connect to the message broker in time")
|
|
81
83
|
|
|
82
84
|
|
|
85
|
+
@contextmanager
|
|
83
86
|
def receive_message_from_socket(sub_socket: zmq.Socket) -> Tuple[Optional[str], Optional[Dict]]:
|
|
84
87
|
"""
|
|
85
88
|
:param sub_socket: zmq socket to receive
|
|
86
|
-
|
|
87
|
-
|
|
89
|
+
Enters a sentry trace for the received message. For this reason, the function should be used as a context manager.
|
|
90
|
+
:yields: a tuple containing (None, None) if an invalid message was received
|
|
91
|
+
otherwise yields a tuple containing (topic: str, message: dict)
|
|
88
92
|
"""
|
|
89
93
|
parts = sub_socket.recv_multipart()
|
|
90
94
|
if len(parts) != 2:
|
|
91
95
|
logging.error(f"received a zmq message with an invalid number of parts: {len(parts)}")
|
|
92
|
-
|
|
96
|
+
yield None, None
|
|
97
|
+
return
|
|
93
98
|
|
|
94
99
|
topic, message = parts
|
|
95
100
|
|
|
@@ -97,10 +102,12 @@ def receive_message_from_socket(sub_socket: zmq.Socket) -> Tuple[Optional[str],
|
|
|
97
102
|
message_dict = orjson.loads(message)
|
|
98
103
|
except orjson.JSONDecodeError as e:
|
|
99
104
|
logging.error(f"received a zmq message with an invalid json. parsing error: {str(e)}")
|
|
100
|
-
|
|
105
|
+
yield None, None
|
|
101
106
|
else:
|
|
102
107
|
if not isinstance(message_dict, dict):
|
|
103
108
|
logging.error(f"received a zmq message which was not a dict but a {type(message)}")
|
|
104
|
-
|
|
109
|
+
yield None, None
|
|
105
110
|
else:
|
|
106
|
-
|
|
111
|
+
decoded_topic = topic.decode("utf8")
|
|
112
|
+
with sentry.continue_trace_zmq_message_receive(decoded_topic, message_dict):
|
|
113
|
+
yield decoded_topic, message_dict
|
|
@@ -13,7 +13,7 @@ from dateutil.tz import UTC
|
|
|
13
13
|
from pydantic import Field, BaseModel, validator, root_validator
|
|
14
14
|
from pydantic.main import ROOT_KEY
|
|
15
15
|
|
|
16
|
-
from openmodule import config
|
|
16
|
+
from openmodule import config, sentry
|
|
17
17
|
from openmodule.config import settings
|
|
18
18
|
|
|
19
19
|
|
|
@@ -139,6 +139,8 @@ class ZMQMessage(OpenModuleModel):
|
|
|
139
139
|
timestamp: datetime = Field(default_factory=lambda: datetime.utcnow())
|
|
140
140
|
name: str = Field(default_factory=lambda: settings.NAME)
|
|
141
141
|
type: str
|
|
142
|
+
baggage: Optional[str] = Field(default_factory=sentry.get_baggage)
|
|
143
|
+
sentry_trace: Optional[str] = Field(default_factory=sentry.get_traceparent, alias="sentry-trace")
|
|
142
144
|
|
|
143
145
|
_tz_timestamp = timezone_validator("timestamp")
|
|
144
146
|
|