1616
1717import math
1818import json
19+ import re
1920
2021try :
2122 import flask
@@ -55,12 +56,13 @@ def get_request_data_from_flask():
5556 """Get http_request and trace data from flask request headers.
5657
5758 Returns:
58- Tuple[Optional[dict], Optional[str]]:
59- Data related to the current http request and the trace_id for the
60- request. Both fields will be None if a flask request isn't found.
59+ Tuple[Optional[dict], Optional[str], Optional[str]]:
60+ Data related to the current http request, trace_id, and span_id for
61+ the request. All fields will be None if a django request isn't
62+ found.
6163 """
6264 if flask is None or not flask .request :
63- return None , None
65+ return None , None , None
6466
6567 # build http_request
6668 http_request = {
@@ -73,34 +75,34 @@ def get_request_data_from_flask():
7375 "protocol" : flask .request .environ .get (_PROTOCOL_HEADER ),
7476 }
7577
76- # find trace id
77- trace_id = None
78+ # find trace id and span id
7879 header = flask .request .headers .get (_FLASK_TRACE_HEADER )
79- if header :
80- trace_id = header .split ("/" , 1 )[0 ]
80+ trace_id , span_id = _parse_trace_span (header )
8181
82- return http_request , trace_id
82+ return http_request , trace_id , span_id
8383
8484
8585def get_request_data_from_django ():
8686 """Get http_request and trace data from django request headers.
8787
8888 Returns:
89- Tuple[Optional[dict], Optional[str]]:
90- Data related to the current http request and the trace_id for the
91- request. Both fields will be None if a django request isn't found.
89+ Tuple[Optional[dict], Optional[str], Optional[str]]:
90+ Data related to the current http request, trace_id, and span_id for
91+ the request. All fields will be None if a django request isn't
92+ found.
9293 """
9394 request = _get_django_request ()
9495
9596 if request is None :
96- return None , None
97+ return None , None , None
9798
9899 # convert content_length to int if it exists
99100 content_length = None
100101 try :
101102 content_length = int (request .META .get (_DJANGO_CONTENT_LENGTH ))
102103 except (ValueError , TypeError ):
103104 content_length = None
105+
104106 # build http_request
105107 http_request = {
106108 "requestMethod" : request .method ,
@@ -112,32 +114,55 @@ def get_request_data_from_django():
112114 "protocol" : request .META .get (_PROTOCOL_HEADER ),
113115 }
114116
115- # find trace id
116- trace_id = None
117+ # find trace id and span id
117118 header = request .META .get (_DJANGO_TRACE_HEADER )
118- if header :
119- trace_id = header .split ("/" , 1 )[0 ]
119+ trace_id , span_id = _parse_trace_span (header )
120+
121+ return http_request , trace_id , span_id
120122
121- return http_request , trace_id
123+
124+ def _parse_trace_span (header ):
125+ """Given an X_CLOUD_TRACE header, extract the trace and span ids.
126+
127+ Args:
128+ header (str): the string extracted from the X_CLOUD_TRACE header
129+ Returns:
130+ Tuple[Optional[dict], Optional[str]]:
131+ The trace_id and span_id extracted from the header
132+ Each field will be None if not found.
133+ """
134+ trace_id = None
135+ span_id = None
136+ if header :
137+ try :
138+ split_header = header .split ("/" , 1 )
139+ trace_id = split_header [0 ]
140+ header_suffix = split_header [1 ]
141+ # the span is the set of alphanumeric characters after the /
142+ span_id = re .findall (r"^\w+" , header_suffix )[0 ]
143+ except IndexError :
144+ pass
145+ return trace_id , span_id
122146
123147
124148def get_request_data ():
125149 """Helper to get http_request and trace data from supported web
126150 frameworks (currently supported: Flask and Django).
127151
128152 Returns:
129- Tuple[Optional[dict], Optional[str]]:
130- Data related to the current http request and the trace_id for the
131- request. Both fields will be None if a supported web request isn't found.
153+ Tuple[Optional[dict], Optional[str], Optional[str]]:
154+ Data related to the current http request, trace_id, and span_id for
155+ the request. All fields will be None if a django request isn't
156+ found.
132157 """
133158 checkers = (
134159 get_request_data_from_django ,
135160 get_request_data_from_flask ,
136161 )
137162
138163 for checker in checkers :
139- http_request , trace_id = checker ()
164+ http_request , trace_id , span_id = checker ()
140165 if http_request is not None :
141- return http_request , trace_id
166+ return http_request , trace_id , span_id
142167
143- return None , None
168+ return None , None , None
0 commit comments