6
6
#include "access/xact.h"
7
7
#include "utils/guc.h"
8
8
#include "utils/builtins.h"
9
+ #include "tcop/tcopprot.h"
9
10
10
11
extern PGDLLEXPORT void _PG_init (void );
11
12
@@ -16,6 +17,11 @@ static char *convertUUID(char *uuid);
16
17
static void pgfdw_xact_callback (XactEvent event , void * arg );
17
18
static void exitHook (int code , Datum arg );
18
19
20
+ /* Trace context extraction functions */
21
+ static char * extractTraceContextFromSession (void );
22
+ static char * extractTraceContextFromQueryComments (void );
23
+ static char * extractTraceContext (void );
24
+
19
25
void * serializePlanState (FdwPlanState * state );
20
26
FdwExecState * initializeExecState (void * internalstate );
21
27
// Required by postgres, doing basic checks to ensure compatibility,
@@ -103,29 +109,154 @@ static char *extractTraceContextFromSession(void)
103
109
const char * traceparent = GetConfigOption ("steampipe.traceparent" , true, false);
104
110
const char * tracestate = GetConfigOption ("steampipe.tracestate" , true, false);
105
111
char * result = NULL ;
106
-
112
+
107
113
// Format the result string for Go layer consumption
108
114
if (traceparent != NULL ) {
109
115
if (tracestate != NULL ) {
110
116
result = psprintf ("traceparent=%s;tracestate=%s" , traceparent , tracestate );
111
117
} else {
112
118
result = psprintf ("traceparent=%s" , traceparent );
113
119
}
114
-
120
+
115
121
elog (DEBUG1 , "extracted trace context: %s" , result );
116
122
} else {
117
123
elog (DEBUG2 , "no trace context found in session variables" );
118
124
}
119
-
125
+
120
126
return result ;
121
127
}
122
128
123
129
/*
124
- * Public wrapper for extractTraceContextFromSession - callable from Go
130
+ * Extract OpenTelemetry trace context from SQL query comments (SQLcommenter format)
131
+ * Parses comments like: /*traceparent='00-...',tracestate='rojo=...'*\/
132
+ * Returns a formatted string containing traceparent and tracestate, or NULL if not found
125
133
*/
126
- char * getTraceContextFromSession (void )
134
+ static char * extractTraceContextFromQueryComments (void )
127
135
{
128
- return extractTraceContextFromSession ();
136
+ const char * query_string = debug_query_string ;
137
+ char * result = NULL ;
138
+ char * traceparent = NULL ;
139
+ char * tracestate = NULL ;
140
+
141
+ if (query_string == NULL ) {
142
+ elog (DEBUG2 , "no query string available for SQLcommenter parsing" );
143
+ return NULL ;
144
+ }
145
+
146
+ elog (DEBUG2 , "parsing SQLcommenter from query: %.100s..." , query_string );
147
+
148
+ // Look for SQL comments in the format /*...*/
149
+ const char * comment_start = strstr (query_string , "/*" );
150
+ while (comment_start != NULL ) {
151
+ const char * comment_end = strstr (comment_start , "*/" );
152
+ if (comment_end == NULL ) {
153
+ break ; // Malformed comment, skip
154
+ }
155
+
156
+ // Extract the comment content
157
+ size_t comment_len = comment_end - comment_start - 2 ; // Exclude /* and */
158
+ char * comment_content = palloc (comment_len + 1 );
159
+ strncpy (comment_content , comment_start + 2 , comment_len );
160
+ comment_content [comment_len ] = '\0' ;
161
+
162
+ elog (DEBUG2 , "found SQL comment: %s" , comment_content );
163
+
164
+ // Parse key-value pairs in the comment
165
+ char * token = strtok (comment_content , "," );
166
+ while (token != NULL ) {
167
+ // Trim whitespace
168
+ while (* token == ' ' || * token == '\t' ) token ++ ;
169
+
170
+ // Look for traceparent or tracestate
171
+ if (strncmp (token , "traceparent=" , 12 ) == 0 ) {
172
+ char * value = token + 12 ;
173
+ // Remove quotes if present
174
+ if (* value == '\'' || * value == '"' ) {
175
+ char quote_char = * value ;
176
+ value ++ ;
177
+ char * end_quote = strrchr (value , quote_char );
178
+ if (end_quote ) * end_quote = '\0' ;
179
+ }
180
+ if (traceparent ) pfree (traceparent );
181
+ traceparent = pstrdup (value );
182
+ elog (DEBUG2 , "extracted traceparent from SQLcommenter: %s" , traceparent );
183
+ } else if (strncmp (token , "tracestate=" , 11 ) == 0 ) {
184
+ char * value = token + 11 ;
185
+ // Remove quotes if present
186
+ if (* value == '\'' || * value == '"' ) {
187
+ char quote_char = * value ;
188
+ value ++ ;
189
+ char * end_quote = strrchr (value , quote_char );
190
+ if (end_quote ) * end_quote = '\0' ;
191
+ }
192
+ if (tracestate ) pfree (tracestate );
193
+ tracestate = pstrdup (value );
194
+ elog (DEBUG2 , "extracted tracestate from SQLcommenter: %s" , tracestate );
195
+ }
196
+
197
+ token = strtok (NULL , "," );
198
+ }
199
+
200
+ pfree (comment_content );
201
+
202
+ // Look for next comment
203
+ comment_start = strstr (comment_end + 2 , "/*" );
204
+ }
205
+
206
+ // Format the result string for Go layer consumption
207
+ if (traceparent != NULL ) {
208
+ if (tracestate != NULL ) {
209
+ result = psprintf ("traceparent=%s;tracestate=%s" , traceparent , tracestate );
210
+ } else {
211
+ result = psprintf ("traceparent=%s" , traceparent );
212
+ }
213
+
214
+ elog (DEBUG1 , "extracted trace context from SQLcommenter: %s" , result );
215
+ } else {
216
+ elog (DEBUG2 , "no trace context found in SQL comments" );
217
+ }
218
+
219
+ // Clean up
220
+ if (traceparent ) pfree (traceparent );
221
+ if (tracestate ) pfree (tracestate );
222
+
223
+ return result ;
224
+ }
225
+
226
+ /*
227
+ * Extract trace context with fallback strategy:
228
+ * 1. Try PostgreSQL session variables first
229
+ * 2. Fall back to SQLcommenter in query comments
230
+ * 3. Return NULL if neither found
231
+ */
232
+ static char * extractTraceContext (void )
233
+ {
234
+ char * result = NULL ;
235
+
236
+ // First try session variables (primary method)
237
+ result = extractTraceContextFromSession ();
238
+ if (result != NULL ) {
239
+ elog (DEBUG1 , "using trace context from session variables" );
240
+ return result ;
241
+ }
242
+
243
+ // Fall back to SQLcommenter (secondary method)
244
+ result = extractTraceContextFromQueryComments ();
245
+ if (result != NULL ) {
246
+ elog (DEBUG1 , "using trace context from SQLcommenter" );
247
+ return result ;
248
+ }
249
+
250
+ elog (DEBUG2 , "no trace context found in session variables or SQLcommenter" );
251
+ return NULL ;
252
+ }
253
+
254
+ /*
255
+ * Public wrapper for extractTraceContext - callable from Go
256
+ */
257
+ char * getTraceContext (void )
258
+ {
259
+ return extractTraceContext ();
129
260
}
130
261
131
262
static void fdwGetForeignRelSize (PlannerInfo * root , RelOptInfo * baserel , Oid foreigntableid )
@@ -147,9 +278,9 @@ static void fdwGetForeignRelSize(PlannerInfo *root, RelOptInfo *baserel, Oid for
147
278
// Save plan state information
148
279
baserel -> fdw_private = planstate ;
149
280
planstate -> foreigntableid = foreigntableid ;
150
-
151
- // Extract trace context from session variables
152
- char * traceContext = extractTraceContextFromSession ();
281
+
282
+ // Extract trace context with fallback strategy ( session variables -> SQLcommenter)
283
+ char * traceContext = extractTraceContext ();
153
284
if (traceContext != NULL ) {
154
285
planstate -> trace_context_string = pstrdup (traceContext );
155
286
pfree (traceContext );
0 commit comments