Instrumenting startup code - AWS X-Ray

Instrumenting startup code

The X-Ray SDK for Java automatically creates segments for incoming requests. As long as a request is in scope, you can use instrumented clients and record subsegments without issue. If you try to use an instrumented client in startup code, though, you'll get a SegmentNotFoundException.

Startup code runs outside of the standard request/response flow of a web application, so you need to create segments manually to instrument it. Scorekeep shows the instrumentation of startup code in its WebConfig files. Scorekeep calls an SQL database and Amazon SNS during startup.

Diagram showing client requests to Scorekeeper-init, which connects to SQL database and SNS.

The default WebConfig class creates an Amazon SNS subscription for notifications. To provide a segment for the X-Ray SDK to write to when the Amazon SNS client is used, Scorekeep calls beginSegment and endSegment on the global recorder.

Example src/main/java/scorekeep/WebConfig.java – Instrumented AWS SDK client in startup code
AWSXRay.beginSegment("Scorekeep-init"); if ( System.getenv("NOTIFICATION_EMAIL") != null ){ try { Sns.createSubscription(); } catch (Exception e ) { logger.warn("Failed to create subscription for email "+ System.getenv("NOTIFICATION_EMAIL")); } } AWSXRay.endSegment();

In RdsWebConfig, which Scorekeep uses when an Amazon RDS database is connected, the configuration also creates a segment for the SQL client that Hibernate uses when it applies the database schema during startup.

Example src/main/java/scorekeep/RdsWebConfig.java – Instrumented SQL database client in startup code
@PostConstruct public void schemaExport() { EntityManagerFactoryImpl entityManagerFactoryImpl = (EntityManagerFactoryImpl) localContainerEntityManagerFactoryBean.getNativeEntityManagerFactory(); SessionFactoryImplementor sessionFactoryImplementor = entityManagerFactoryImpl.getSessionFactory(); StandardServiceRegistry standardServiceRegistry = sessionFactoryImplementor.getSessionFactoryOptions().getServiceRegistry(); MetadataSources metadataSources = new MetadataSources(new BootstrapServiceRegistryBuilder().build()); metadataSources.addAnnotatedClass(GameHistory.class); MetadataImplementor metadataImplementor = (MetadataImplementor) metadataSources.buildMetadata(standardServiceRegistry); SchemaExport schemaExport = new SchemaExport(standardServiceRegistry, metadataImplementor); AWSXRay.beginSegment("Scorekeep-init"); schemaExport.create(true, true); AWSXRay.endSegment(); }

SchemaExport runs automatically and uses an SQL client. Since the client is instrumented, Scorekeep must override the default implementation and provide a segment for the SDK to use when the client is invoked.