feat: property-driven template composition for Spring Boot and Ktor - #520
Merged
Conversation
…emplateFactory The starters auto-configure one template for a single-candidate data source; a multi-database application had to hand-compose its templates, importing the core SPI to wire what the starter wires from properties. The starters now expose an OrmTemplateFactory bean carrying the same property-driven integration per created template: Spring-aware connection and transaction providers, SQL failure translation with the mapper created against each template's own data source, observations whose semantic conventions resolve from each data source's JDBC URL and which report the template's name as the storm.database key value, and the trace-context SQL commenter. A customize block applies application-specific composition on top. Observer composition is shared through the new StormQueryObservers, which the observation auto-configuration also builds the single template's observer with. The single-candidate condition moves from StormAutoConfiguration's class level to the template bean, so the factory is available in applications where the single template backs off.
…own template beans Multi-database applications are the common case, but a single-data-source application that customizes its template composition backs the auto-configured template off just the same, and the factory keeps the property-driven integration for it too.
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
…or the Ktor plugin The Ktor plugin selects the OpenTelemetry database semantic conventions from configuration: storm.observations.semanticConventions = otel resolves the database product from each database's own data source, with a per-database override under storm.databases.<name>. A convention registered in the dependency container keeps taking precedence. Previously a convention instance had to be registered in the container, naming the product by hand and serving every database with one value. A customize slot on the plugin and per database block applies application-specific composition, such as a template decorator, after the integration is wired; a database block inherits the plugin-level block unless it sets its own. The decorator guidance in the Ktor documentation composed a second template outside the plugin, which the plugin's repositories never used; it now goes through the slot. Observer composition is shared with the Spring Boot starters through QueryObservers in storm-micrometer, so the stacks resolve conventions and the storm.database identity the same way. The observation documents describe the storm.database key value as naming the template the observation came from, and the template factory's documentation reads from the composition's perspective rather than the application shape's.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
A default application should not need Storm's core SPI. The starters auto-configure one
ORMTemplatefor a single-candidateDataSource; an application that defines its own template beans — for several data sources, or a single one whose composition it customizes — backed that off and hand-composed everything, importingExceptionMapper,QueryObserverandSqlCommenterto wire by hand exactly what the starter wires from properties. The Ktor plugin had the mirrored gaps: OTel semantic conventions required constructing and registering a convention instance (one product for every database), and applying a template decorator meant composing a second template outside the plugin — which the plugin's repositories never used.Spring Boot:
OrmTemplateFactoryEach created template carries the property-driven integration of the auto-configured one: Spring connection/transaction providers, SQL failure translation per
storm.exception-translation.enabledwith the mapper created against the template's own data source, observations perstorm.observations.*with conventions resolved from the template's own JDBC URL and the template named as the low-cardinalitystorm.databasekey value, and the trace commenter perstorm.tracing.sql-comments. The trailing block applies application-specific composition after the integration; the single-candidate condition moves from the auto-configuration class to the template bean, so the factory exists exactly where the single template backs off.Ktor: configuration parity
storm.observations.semanticConventions = otelselects the OTel conventions from configuration, resolved per database from its own data source, overridable understorm.databases.<name>.observations.semanticConventions, validated at installation. A convention registered in the dependency container keeps taking precedence.customizeslot on the plugin and per database block applies composition such as a template decorator after the integration is wired, inheriting the plugin-level block unless the database sets its own.Shared composition
Observer composition lives in the new
QueryObserversin storm-micrometer; storm-spring'sStormQueryObserversand the Ktor plugin both delegate to it, so the stacks resolve conventions and thestorm.databaseidentity identically and cannot drift.Documentation
spring-integration.mdgains a Composing Your Own Templates section;ktor-integration.md's decorator section goes throughcustomizeand its observability section leads with the configuration key;configuration.mdlists the Ktor key. All observation and factory docs describestorm.databaseas naming the template the observation came from, written from the composition's perspective rather than any application shape.Testing
Both starters'
StormAutoConfigurationTestcover the factory (single template backs off, distinct templates per data source, customize runs);StormObservabilityTestcovers the configured conventions resolving from the database's own data source andcustomizecomposing after (and overriding) the wired integration. Full sweeps over storm-micrometer, storm-spring, storm-ktor, storm-ktor-test, both starters and the@DataStormTestparity slice pass.