mirror of
https://github.com/simonw/datasette.git
synced 2026-09-03 23:24:07 +02:00
Datasette's existing tracer times a "sql" block that wraps a good deal more than the query itself - queueing onto the thread pool, the pool wait, and result marshalling all disappear into one number. That is simonw/datasette#1730, "SQL tracing should much more closely track the SQL query execution", open since 2022. A db.query span here is the outer half of the answer; a later change adds the inner span drawn around the sqlite3 call itself, and the gap between the two is exactly the thread pool wait the current tracer folds away. The span carries OTel semantic-convention attributes (db.system, db.namespace, db.query.text) plus a few datasette.* ones. db.query.text goes through sql_attribute(), which caps it at 2048 characters, because on a public instance the SQL is attacker-supplied and unbounded. Only len(params) is recorded, never a parameter value. The existing `with trace(...)` wrapper stays exactly where it is and the new span nests inside it. This change removes nothing: ?_trace=1 and the trace_debug setting keep working unchanged. The two systems are independent code paths. Exception handling on the span is explicit rather than inherited from start_as_current_span's defaults, which would record the exception and set StatusCode.ERROR on anything passing through. That is wrong here because some SQL failures are the expected answer. ArrayFacet.suggest() runs json_type(<column>) against every column precisely to discover which ones raise "malformed JSON", and passes log_sql_errors=False to say so. Left to the defaults, a table with N text columns marks N queries per page as failed - burying genuine failures and tripping any alerting keyed on span status. Measured on a plain table page before this: 4 error spans out of 225, all expected. Suppressed errors now leave the status UNSET and set datasette.sql_error_suppressed instead, so they stay discoverable without reading as failures. QueryInterrupted still sets ERROR unconditionally. That is not quite right either - facet suggestion is designed to time out - but the fix needs its own reasoning and lands separately. Behaviour change worth calling out: time_limit_ms is hoisted out of sql_operation_in_thread so the span can record it on the event loop. It is therefore read at call time rather than at thread-execution time. Benign in practice, since ds.sql_time_limit_ms is set at startup, but it is a real change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| plugins | ||
| test_templates | ||
| __init__.py | ||
| build_small_spatialite_db.py | ||
| conftest.py | ||
| ext.c | ||
| fixtures.py | ||
| spatialite.db | ||
| test-datasette-load-plugins.sh | ||
| test_actions_sql.py | ||
| test_actor_restriction_bug.py | ||
| test_allowed_many.py | ||
| test_allowed_resources.py | ||
| test_api.py | ||
| test_api_write.py | ||
| test_auth.py | ||
| test_autocomplete.py | ||
| test_base_view.py | ||
| test_cli.py | ||
| test_cli_serve_get.py | ||
| test_cli_serve_server.py | ||
| test_column_types.py | ||
| test_config_dir.py | ||
| test_config_permission_rules.py | ||
| test_crossdb.py | ||
| test_csrf_middleware.py | ||
| test_csv.py | ||
| test_custom_pages.py | ||
| test_datasette_https_server.sh | ||
| test_debug_autocomplete.py | ||
| test_default_deny.py | ||
| test_docs.py | ||
| test_docs_plugins.py | ||
| test_error_shape.py | ||
| test_extras.py | ||
| test_facets.py | ||
| test_fd_leak.py | ||
| test_filters.py | ||
| test_fixtures.py | ||
| test_html.py | ||
| test_internal_db.py | ||
| test_internals_database.py | ||
| test_internals_datasette.py | ||
| test_internals_datasette_client.py | ||
| test_internals_request.py | ||
| test_internals_response.py | ||
| test_internals_urls.py | ||
| test_jump.py | ||
| test_label_column_for_table.py | ||
| test_lifespan.py | ||
| test_load_extensions.py | ||
| test_messages.py | ||
| test_multipart.py | ||
| test_package.py | ||
| test_permission_endpoints.py | ||
| test_permissions.py | ||
| test_playwright.py | ||
| test_plugins.py | ||
| test_publish_cloudrun.py | ||
| test_publish_heroku.py | ||
| test_pytest_autoclose_plugin.py | ||
| test_queries.py | ||
| test_restriction_sql.py | ||
| test_routes.py | ||
| test_schema_endpoints.py | ||
| test_search_tables.py | ||
| test_spatialite.py | ||
| test_stored_queries.py | ||
| test_success_envelope.py | ||
| test_table_api.py | ||
| test_table_html.py | ||
| test_telemetry.py | ||
| test_template_context.py | ||
| test_token_handler.py | ||
| test_tracer.py | ||
| test_utils.py | ||
| test_utils_check_callable.py | ||
| test_utils_permissions.py | ||
| test_utils_sql_analysis.py | ||
| test_write_sql_operation_decisions.py | ||
| test_write_wrapper.py | ||
| utils.py | ||