@@ -2756,4 +2756,76 @@ public void validateGetObjectNullValues() throws Exception {
27562756 }
27572757 }
27582758 }
2759+
2760+ @ Test
2761+ public void testPerConnectionLoggingE2E () throws SQLException , IOException {
2762+ File tempDir = File .createTempFile ("bq-jdbc-e2e-logs" , "" );
2763+ tempDir .delete ();
2764+ tempDir .mkdirs ();
2765+ tempDir .deleteOnExit ();
2766+
2767+ String logPath = tempDir .getAbsolutePath ();
2768+ String targetUri = connection_uri + ";LogLevel=6;LogPath=" + logPath ;
2769+
2770+ String connectionId = null ;
2771+ try (Connection conn = DriverManager .getConnection (targetUri )) {
2772+ assertNotNull (conn );
2773+
2774+ // Extract connection ID using reflection to bypass package-private encapsulation limits in
2775+ // test
2776+ java .lang .reflect .Method method =
2777+ conn .unwrap (BigQueryConnection .class ).getClass ().getDeclaredMethod ("getConnectionId" );
2778+ method .setAccessible (true );
2779+ connectionId = (String ) method .invoke (conn .unwrap (BigQueryConnection .class ));
2780+ assertNotNull (connectionId );
2781+
2782+ // 1. Execute a local operational method (like close) which does not create cloud jobs
2783+ Statement stmt = conn .createStatement ();
2784+ stmt .close ();
2785+
2786+ // 2. Execute an empty query to trigger a local SQL syntax SQLException
2787+ assertThrows (SQLException .class , () -> stmt .executeQuery ("" ));
2788+ } catch (Exception e ) {
2789+ throw new SQLException ("Reflection lookup or E2E execution failed" , e );
2790+ } finally {
2791+ // Cleanly close and remove all file handlers from com.google.cloud.bigquery logger using
2792+ // public APIs
2793+ java .util .logging .Logger bqLogger =
2794+ java .util .logging .Logger .getLogger ("com.google.cloud.bigquery" );
2795+ for (java .util .logging .Handler h : bqLogger .getHandlers ()) {
2796+ h .close ();
2797+ bqLogger .removeHandler (h );
2798+ }
2799+
2800+ // Verify physical connection-specific log file creation
2801+ final String targetId = connectionId ;
2802+ File [] files =
2803+ tempDir .listFiles (
2804+ (dir , name ) -> targetId != null && name .endsWith ("-" + targetId + ".log" ));
2805+ assertNotNull (files );
2806+ assertEquals (1 , files .length );
2807+
2808+ File actualLog = files [0 ];
2809+ byte [] encoded = java .nio .file .Files .readAllBytes (actualLog .toPath ());
2810+ String content = new String (encoded , StandardCharsets .UTF_8 );
2811+
2812+ // Asserts that the connection ID prefix is formatted inside log entries
2813+ assertTrue (content .contains ("[" + connectionId + "]" ));
2814+ // Asserts that operational actions are logged inside the connection log
2815+ assertTrue (content .contains ("close" ));
2816+ // Asserts that the exception is connection-routed and logged
2817+ assertTrue (
2818+ content .contains ("Exception occurred during executeQuery" ),
2819+ "Log content did not contain expected exception! Content: \n " + content );
2820+
2821+ // Clean up
2822+ File [] remaining = tempDir .listFiles ();
2823+ if (remaining != null ) {
2824+ for (File f : remaining ) {
2825+ f .delete ();
2826+ }
2827+ }
2828+ tempDir .delete ();
2829+ }
2830+ }
27592831}
0 commit comments