You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

759 lines
22 KiB

  1. // Copyright 2016 Google LLC
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. // Package trace is OBSOLETE. See https://cloud.google.com/trace/docs/setup/go.
  15. package trace // import "cloud.google.com/go/trace"
  16. import (
  17. "context"
  18. "crypto/rand"
  19. "encoding/binary"
  20. "encoding/json"
  21. "fmt"
  22. "log"
  23. "net/http"
  24. "runtime"
  25. "strconv"
  26. "strings"
  27. "sync"
  28. "sync/atomic"
  29. "time"
  30. api "google.golang.org/api/cloudtrace/v1"
  31. "google.golang.org/api/gensupport"
  32. "google.golang.org/api/option"
  33. "google.golang.org/api/support/bundler"
  34. htransport "google.golang.org/api/transport/http"
  35. )
  36. const (
  37. httpHeader = `X-Cloud-Trace-Context`
  38. userAgent = `gcloud-golang-trace/20160501`
  39. cloudPlatformScope = `https://www.googleapis.com/auth/cloud-platform`
  40. spanKindClient = `RPC_CLIENT`
  41. spanKindServer = `RPC_SERVER`
  42. spanKindUnspecified = `SPAN_KIND_UNSPECIFIED`
  43. maxStackFrames = 20
  44. labelAgent = `trace.cloud.google.com/agent`
  45. )
  46. // Stackdriver Trace API predefined labels.
  47. //
  48. // Deprecated: see https://cloud.google.com/trace/docs/setup/go.
  49. const (
  50. LabelComponent = `trace.cloud.google.com/component`
  51. LabelErrorMessage = `trace.cloud.google.com/error/message`
  52. LabelErrorName = `trace.cloud.google.com/error/name`
  53. LabelHTTPClientCity = `trace.cloud.google.com/http/client_city`
  54. LabelHTTPClientCountry = `trace.cloud.google.com/http/client_country`
  55. LabelHTTPClientProtocol = `trace.cloud.google.com/http/client_protocol`
  56. LabelHTTPClientRegion = `trace.cloud.google.com/http/client_region`
  57. LabelHTTPHost = `trace.cloud.google.com/http/host`
  58. LabelHTTPMethod = `trace.cloud.google.com/http/method`
  59. LabelHTTPRedirectedURL = `trace.cloud.google.com/http/redirected_url`
  60. LabelHTTPRequestSize = `trace.cloud.google.com/http/request/size`
  61. LabelHTTPResponseSize = `trace.cloud.google.com/http/response/size`
  62. LabelHTTPStatusCode = `trace.cloud.google.com/http/status_code`
  63. LabelHTTPURL = `trace.cloud.google.com/http/url`
  64. LabelHTTPUserAgent = `trace.cloud.google.com/http/user_agent`
  65. LabelPID = `trace.cloud.google.com/pid`
  66. LabelSamplingPolicy = `trace.cloud.google.com/sampling_policy`
  67. LabelSamplingWeight = `trace.cloud.google.com/sampling_weight`
  68. LabelStackTrace = `trace.cloud.google.com/stacktrace`
  69. LabelTID = `trace.cloud.google.com/tid`
  70. )
  71. const (
  72. // ScopeTraceAppend grants permissions to write trace data for a project.
  73. //
  74. // Deprecated: see https://cloud.google.com/trace/docs/setup/go.
  75. ScopeTraceAppend = "https://www.googleapis.com/auth/trace.append"
  76. // ScopeCloudPlatform grants permissions to view and manage your data
  77. // across Google Cloud Platform services.
  78. //
  79. // Deprecated: see https://cloud.google.com/trace/docs/setup/go.
  80. ScopeCloudPlatform = "https://www.googleapis.com/auth/cloud-platform"
  81. )
  82. type contextKey struct{}
  83. type stackLabelValue struct {
  84. Frames []stackFrame `json:"stack_frame"`
  85. }
  86. type stackFrame struct {
  87. Class string `json:"class_name,omitempty"`
  88. Method string `json:"method_name"`
  89. Filename string `json:"file_name"`
  90. Line int64 `json:"line_number"`
  91. }
  92. var (
  93. spanIDCounter uint64
  94. spanIDIncrement uint64
  95. )
  96. func init() {
  97. // Set spanIDCounter and spanIDIncrement to random values. nextSpanID will
  98. // return an arithmetic progression using these values, skipping zero. We set
  99. // the LSB of spanIDIncrement to 1, so that the cycle length is 2^64.
  100. binary.Read(rand.Reader, binary.LittleEndian, &spanIDCounter)
  101. binary.Read(rand.Reader, binary.LittleEndian, &spanIDIncrement)
  102. spanIDIncrement |= 1
  103. // Attach hook for autogenerated Google API calls. This will automatically
  104. // create trace spans for API calls if there is a trace in the context.
  105. gensupport.RegisterHook(requestHook)
  106. }
  107. func requestHook(ctx context.Context, req *http.Request) func(resp *http.Response) {
  108. span := FromContext(ctx)
  109. if span == nil || req == nil {
  110. return nil
  111. }
  112. span = span.NewRemoteChild(req)
  113. return func(resp *http.Response) {
  114. if resp != nil {
  115. span.Finish(WithResponse(resp))
  116. } else {
  117. span.Finish()
  118. }
  119. }
  120. }
  121. // nextSpanID returns a new span ID. It will never return zero.
  122. func nextSpanID() uint64 {
  123. var id uint64
  124. for id == 0 {
  125. id = atomic.AddUint64(&spanIDCounter, spanIDIncrement)
  126. }
  127. return id
  128. }
  129. // nextTraceID returns a new trace ID.
  130. func nextTraceID() string {
  131. id1 := nextSpanID()
  132. id2 := nextSpanID()
  133. return fmt.Sprintf("%016x%016x", id1, id2)
  134. }
  135. // Client is a client for uploading traces to the Google Stackdriver Trace service.
  136. // A nil Client will no-op for all of its methods.
  137. //
  138. // Deprecated: see https://cloud.google.com/trace/docs/setup/go.
  139. type Client struct {
  140. service *api.Service
  141. projectID string
  142. policy SamplingPolicy
  143. bundler *bundler.Bundler
  144. }
  145. // NewClient creates a new Google Stackdriver Trace client.
  146. //
  147. // Deprecated: see https://cloud.google.com/trace/docs/setup/go.
  148. func NewClient(ctx context.Context, projectID string, opts ...option.ClientOption) (*Client, error) {
  149. o := []option.ClientOption{
  150. option.WithScopes(cloudPlatformScope),
  151. option.WithUserAgent(userAgent),
  152. }
  153. o = append(o, opts...)
  154. hc, basePath, err := htransport.NewClient(ctx, o...)
  155. if err != nil {
  156. return nil, fmt.Errorf("creating HTTP client for Google Stackdriver Trace API: %v", err)
  157. }
  158. apiService, err := api.New(hc)
  159. if err != nil {
  160. return nil, fmt.Errorf("creating Google Stackdriver Trace API client: %v", err)
  161. }
  162. if basePath != "" {
  163. // An option set a basepath, so override api.New's default.
  164. apiService.BasePath = basePath
  165. }
  166. c := &Client{
  167. service: apiService,
  168. projectID: projectID,
  169. }
  170. bundler := bundler.NewBundler((*api.Trace)(nil), func(bundle interface{}) {
  171. traces := bundle.([]*api.Trace)
  172. err := c.upload(traces)
  173. if err != nil {
  174. log.Printf("failed to upload %d traces to the Cloud Trace server: %v", len(traces), err)
  175. }
  176. })
  177. bundler.DelayThreshold = 2 * time.Second
  178. bundler.BundleCountThreshold = 100
  179. // We're not measuring bytes here, we're counting traces and spans as one "byte" each.
  180. bundler.BundleByteThreshold = 1000
  181. bundler.BundleByteLimit = 1000
  182. bundler.BufferedByteLimit = 10000
  183. c.bundler = bundler
  184. return c, nil
  185. }
  186. // SetSamplingPolicy sets the SamplingPolicy that determines how often traces
  187. // are initiated by this client.
  188. //
  189. // Deprecated: see https://cloud.google.com/trace/docs/setup/go.
  190. func (c *Client) SetSamplingPolicy(p SamplingPolicy) {
  191. if c != nil {
  192. c.policy = p
  193. }
  194. }
  195. // SpanFromHeader returns a new trace span based on a provided request header
  196. // value or nil iff the client is nil.
  197. //
  198. // The trace information and identifiers will be read from the header value.
  199. // Otherwise, a new trace ID is made and the parent span ID is zero.
  200. // For the exact format of the header value, see
  201. // https://cloud.google.com/trace/docs/troubleshooting#force-trace
  202. //
  203. // The name of the new span is provided as an argument.
  204. //
  205. // If a non-nil sampling policy has been set in the client, it can override
  206. // the options set in the header and choose whether to trace the request.
  207. //
  208. // If the header doesn't have existing tracing information, then a *Span is
  209. // returned anyway, but it will not be uploaded to the server, just as when
  210. // calling SpanFromRequest on an untraced request.
  211. //
  212. // Most users using HTTP should use SpanFromRequest, rather than
  213. // SpanFromHeader, since it provides additional functionality for HTTP
  214. // requests. In particular, it will set various pieces of request information
  215. // as labels on the *Span, which is not available from the header alone.
  216. //
  217. // Deprecated: see https://cloud.google.com/trace/docs/setup/go.
  218. func (c *Client) SpanFromHeader(name string, header string) *Span {
  219. if c == nil {
  220. return nil
  221. }
  222. traceID, parentSpanID, options, _, ok := traceInfoFromHeader(header)
  223. if !ok {
  224. traceID = nextTraceID()
  225. }
  226. t := &trace{
  227. traceID: traceID,
  228. client: c,
  229. globalOptions: options,
  230. localOptions: options,
  231. }
  232. span := startNewChild(name, t, parentSpanID)
  233. span.span.Kind = spanKindServer
  234. span.rootSpan = true
  235. configureSpanFromPolicy(span, c.policy, ok)
  236. return span
  237. }
  238. // SpanFromRequest returns a new trace span for an HTTP request or nil
  239. // iff the client is nil.
  240. //
  241. // If the incoming HTTP request contains a trace context header, the trace ID,
  242. // parent span ID, and tracing options will be read from that header.
  243. // Otherwise, a new trace ID is made and the parent span ID is zero.
  244. //
  245. // If a non-nil sampling policy has been set in the client, it can override the
  246. // options set in the header and choose whether to trace the request.
  247. //
  248. // If the request is not being traced, then a *Span is returned anyway, but it
  249. // will not be uploaded to the server -- it is only useful for propagating
  250. // trace context to child requests and for getting the TraceID. All its
  251. // methods can still be called -- the Finish, FinishWait, and SetLabel methods
  252. // do nothing. NewChild does nothing, and returns the same *Span. TraceID
  253. // works as usual.
  254. //
  255. // Deprecated: see https://cloud.google.com/trace/docs/setup/go.
  256. func (c *Client) SpanFromRequest(r *http.Request) *Span {
  257. if c == nil {
  258. return nil
  259. }
  260. traceID, parentSpanID, options, _, ok := traceInfoFromHeader(r.Header.Get(httpHeader))
  261. if !ok {
  262. traceID = nextTraceID()
  263. }
  264. t := &trace{
  265. traceID: traceID,
  266. client: c,
  267. globalOptions: options,
  268. localOptions: options,
  269. }
  270. span := startNewChildWithRequest(r, t, parentSpanID)
  271. span.span.Kind = spanKindServer
  272. span.rootSpan = true
  273. configureSpanFromPolicy(span, c.policy, ok)
  274. return span
  275. }
  276. // NewSpan returns a new trace span with the given name or nil iff the
  277. // client is nil.
  278. //
  279. // A new trace and span ID is generated to trace the span.
  280. // Returned span need to be finished by calling Finish or FinishWait.
  281. //
  282. // Deprecated: see https://cloud.google.com/trace/docs/setup/go.
  283. func (c *Client) NewSpan(name string) *Span {
  284. if c == nil {
  285. return nil
  286. }
  287. t := &trace{
  288. traceID: nextTraceID(),
  289. client: c,
  290. localOptions: optionTrace,
  291. globalOptions: optionTrace,
  292. }
  293. span := startNewChild(name, t, 0)
  294. span.span.Kind = spanKindUnspecified
  295. span.rootSpan = true
  296. configureSpanFromPolicy(span, c.policy, false)
  297. return span
  298. }
  299. func configureSpanFromPolicy(s *Span, p SamplingPolicy, ok bool) {
  300. if p == nil {
  301. return
  302. }
  303. d := p.Sample(Parameters{HasTraceHeader: ok})
  304. if d.Trace {
  305. // Turn on tracing locally, and in child requests.
  306. s.trace.localOptions |= optionTrace
  307. s.trace.globalOptions |= optionTrace
  308. } else {
  309. // Turn off tracing locally.
  310. s.trace.localOptions = 0
  311. return
  312. }
  313. if d.Sample {
  314. // This trace is in the random sample, so set the labels.
  315. s.SetLabel(LabelSamplingPolicy, d.Policy)
  316. s.SetLabel(LabelSamplingWeight, fmt.Sprint(d.Weight))
  317. }
  318. }
  319. // NewContext returns a derived context containing the span.
  320. //
  321. // Deprecated: see https://cloud.google.com/trace/docs/setup/go.
  322. func NewContext(ctx context.Context, s *Span) context.Context {
  323. if s == nil {
  324. return ctx
  325. }
  326. return context.WithValue(ctx, contextKey{}, s)
  327. }
  328. // FromContext returns the span contained in the context, or nil.
  329. //
  330. // Deprecated: see https://cloud.google.com/trace/docs/setup/go.
  331. func FromContext(ctx context.Context) *Span {
  332. s, _ := ctx.Value(contextKey{}).(*Span)
  333. return s
  334. }
  335. func traceInfoFromHeader(h string) (traceID string, spanID uint64, options optionFlags, optionsOk bool, ok bool) {
  336. // See https://cloud.google.com/trace/docs/faq for the header format.
  337. // Return if the header is empty or missing, or if the header is unreasonably
  338. // large, to avoid making unnecessary copies of a large string.
  339. if h == "" || len(h) > 200 {
  340. return "", 0, 0, false, false
  341. }
  342. // Parse the trace id field.
  343. slash := strings.Index(h, `/`)
  344. if slash == -1 {
  345. return "", 0, 0, false, false
  346. }
  347. traceID, h = h[:slash], h[slash+1:]
  348. // Parse the span id field.
  349. spanstr := h
  350. semicolon := strings.Index(h, `;`)
  351. if semicolon != -1 {
  352. spanstr, h = h[:semicolon], h[semicolon+1:]
  353. }
  354. spanID, err := strconv.ParseUint(spanstr, 10, 64)
  355. if err != nil {
  356. return "", 0, 0, false, false
  357. }
  358. // Parse the options field, options field is optional.
  359. if !strings.HasPrefix(h, "o=") {
  360. return traceID, spanID, 0, false, true
  361. }
  362. o, err := strconv.ParseUint(h[2:], 10, 64)
  363. if err != nil {
  364. return "", 0, 0, false, false
  365. }
  366. options = optionFlags(o)
  367. return traceID, spanID, options, true, true
  368. }
  369. type optionFlags uint32
  370. const (
  371. optionTrace optionFlags = 1 << iota
  372. optionStack
  373. )
  374. type trace struct {
  375. mu sync.Mutex
  376. client *Client
  377. traceID string
  378. globalOptions optionFlags // options that will be passed to any child requests
  379. localOptions optionFlags // options applied in this server
  380. spans []*Span // finished spans for this trace.
  381. }
  382. // finish appends s to t.spans. If s is the root span, uploads the trace to the
  383. // server.
  384. func (t *trace) finish(s *Span, wait bool, opts ...FinishOption) error {
  385. for _, o := range opts {
  386. o.modifySpan(s)
  387. }
  388. s.end = time.Now()
  389. t.mu.Lock()
  390. t.spans = append(t.spans, s)
  391. spans := t.spans
  392. t.mu.Unlock()
  393. if s.rootSpan {
  394. if wait {
  395. return t.client.upload([]*api.Trace{t.constructTrace(spans)})
  396. }
  397. go func() {
  398. tr := t.constructTrace(spans)
  399. err := t.client.bundler.Add(tr, 1+len(spans))
  400. if err == bundler.ErrOversizedItem {
  401. err = t.client.upload([]*api.Trace{tr})
  402. }
  403. if err != nil {
  404. log.Println("error uploading trace:", err)
  405. }
  406. }()
  407. }
  408. return nil
  409. }
  410. func (t *trace) constructTrace(spans []*Span) *api.Trace {
  411. apiSpans := make([]*api.TraceSpan, len(spans))
  412. for i, sp := range spans {
  413. sp.span.StartTime = sp.start.In(time.UTC).Format(time.RFC3339Nano)
  414. sp.span.EndTime = sp.end.In(time.UTC).Format(time.RFC3339Nano)
  415. if t.localOptions&optionStack != 0 {
  416. sp.setStackLabel()
  417. }
  418. if sp.host != "" {
  419. sp.SetLabel(LabelHTTPHost, sp.host)
  420. }
  421. if sp.url != "" {
  422. sp.SetLabel(LabelHTTPURL, sp.url)
  423. }
  424. if sp.method != "" {
  425. sp.SetLabel(LabelHTTPMethod, sp.method)
  426. }
  427. if sp.statusCode != 0 {
  428. sp.SetLabel(LabelHTTPStatusCode, strconv.Itoa(sp.statusCode))
  429. }
  430. sp.SetLabel(labelAgent, userAgent)
  431. apiSpans[i] = &sp.span
  432. }
  433. return &api.Trace{
  434. ProjectId: t.client.projectID,
  435. TraceId: t.traceID,
  436. Spans: apiSpans,
  437. }
  438. }
  439. func (c *Client) upload(traces []*api.Trace) error {
  440. _, err := c.service.Projects.PatchTraces(c.projectID, &api.Traces{Traces: traces}).Do()
  441. return err
  442. }
  443. // Span contains information about one span of a trace.
  444. //
  445. // Deprecated: see https://cloud.google.com/trace/docs/setup/go.
  446. type Span struct {
  447. trace *trace
  448. spanMu sync.Mutex // guards span.Labels
  449. span api.TraceSpan
  450. start time.Time
  451. end time.Time
  452. rootSpan bool
  453. stack [maxStackFrames]uintptr
  454. host string
  455. method string
  456. url string
  457. statusCode int
  458. }
  459. // Traced reports whether the current span is sampled to be traced.
  460. //
  461. // Deprecated: see https://cloud.google.com/trace/docs/setup/go.
  462. func (s *Span) Traced() bool {
  463. if s == nil {
  464. return false
  465. }
  466. return s.trace.localOptions&optionTrace != 0
  467. }
  468. // NewChild creates a new span with the given name as a child of s.
  469. // If s is nil, does nothing and returns nil.
  470. //
  471. // Deprecated: see https://cloud.google.com/trace/docs/setup/go.
  472. func (s *Span) NewChild(name string) *Span {
  473. if s == nil {
  474. return nil
  475. }
  476. if !s.Traced() {
  477. // TODO(jbd): Document this behavior in godoc here and elsewhere.
  478. return s
  479. }
  480. return startNewChild(name, s.trace, s.span.SpanId)
  481. }
  482. // NewRemoteChild creates a new span as a child of s.
  483. //
  484. // Some labels in the span are set from the outgoing *http.Request r.
  485. //
  486. // A header is set in r so that the trace context is propagated to the
  487. // destination. The parent span ID in that header is set as follows:
  488. // - If the request is being traced, then the ID of s is used.
  489. // - If the request is not being traced, but there was a trace context header
  490. // in the incoming request for this trace (the request passed to
  491. // SpanFromRequest), the parent span ID in that header is used.
  492. // - Otherwise, the parent span ID is zero.
  493. // The tracing bit in the options is set if tracing is enabled, or if it was
  494. // set in the incoming request.
  495. //
  496. // If s is nil, does nothing and returns nil.
  497. //
  498. // Deprecated: see https://cloud.google.com/trace/docs/setup/go.
  499. func (s *Span) NewRemoteChild(r *http.Request) *Span {
  500. if s == nil {
  501. return nil
  502. }
  503. if !s.Traced() {
  504. r.Header[httpHeader] = []string{spanHeader(s.trace.traceID, s.span.ParentSpanId, s.trace.globalOptions)}
  505. return s
  506. }
  507. newSpan := startNewChildWithRequest(r, s.trace, s.span.SpanId)
  508. r.Header[httpHeader] = []string{spanHeader(s.trace.traceID, newSpan.span.SpanId, s.trace.globalOptions)}
  509. return newSpan
  510. }
  511. // Header returns the value of the X-Cloud-Trace-Context header that
  512. // should be used to propagate the span. This is the inverse of
  513. // SpanFromHeader.
  514. //
  515. // Most users should use NewRemoteChild unless they have specific
  516. // propagation needs or want to control the naming of their span.
  517. // Header() does not create a new span.
  518. //
  519. // Deprecated: see https://cloud.google.com/trace/docs/setup/go.
  520. func (s *Span) Header() string {
  521. if s == nil {
  522. return ""
  523. }
  524. return spanHeader(s.trace.traceID, s.span.SpanId, s.trace.globalOptions)
  525. }
  526. func startNewChildWithRequest(r *http.Request, trace *trace, parentSpanID uint64) *Span {
  527. name := r.URL.Host + r.URL.Path // drop scheme and query params
  528. newSpan := startNewChild(name, trace, parentSpanID)
  529. if r.Host == "" {
  530. newSpan.host = r.URL.Host
  531. } else {
  532. newSpan.host = r.Host
  533. }
  534. newSpan.method = r.Method
  535. newSpan.url = r.URL.String()
  536. return newSpan
  537. }
  538. func startNewChild(name string, trace *trace, parentSpanID uint64) *Span {
  539. spanID := nextSpanID()
  540. for spanID == parentSpanID {
  541. spanID = nextSpanID()
  542. }
  543. newSpan := &Span{
  544. trace: trace,
  545. span: api.TraceSpan{
  546. Kind: spanKindClient,
  547. Name: name,
  548. ParentSpanId: parentSpanID,
  549. SpanId: spanID,
  550. },
  551. start: time.Now(),
  552. }
  553. if trace.localOptions&optionStack != 0 {
  554. _ = runtime.Callers(1, newSpan.stack[:])
  555. }
  556. return newSpan
  557. }
  558. // TraceID returns the ID of the trace to which s belongs.
  559. //
  560. // Deprecated: see https://cloud.google.com/trace/docs/setup/go.
  561. func (s *Span) TraceID() string {
  562. if s == nil {
  563. return ""
  564. }
  565. return s.trace.traceID
  566. }
  567. // SetLabel sets the label for the given key to the given value.
  568. // If the value is empty, the label for that key is deleted.
  569. // If a label is given a value automatically and by SetLabel, the
  570. // automatically-set value is used.
  571. // If s is nil, does nothing.
  572. //
  573. // SetLabel shouldn't be called after Finish or FinishWait.
  574. //
  575. // Deprecated: see https://cloud.google.com/trace/docs/setup/go.
  576. func (s *Span) SetLabel(key, value string) {
  577. if s == nil {
  578. return
  579. }
  580. if !s.Traced() {
  581. return
  582. }
  583. s.spanMu.Lock()
  584. defer s.spanMu.Unlock()
  585. if value == "" {
  586. if s.span.Labels != nil {
  587. delete(s.span.Labels, key)
  588. }
  589. return
  590. }
  591. if s.span.Labels == nil {
  592. s.span.Labels = make(map[string]string)
  593. }
  594. s.span.Labels[key] = value
  595. }
  596. // FinishOption allows users to specify span finalizers.
  597. // Deprecated: see https://cloud.google.com/trace/docs/setup/go.
  598. type FinishOption interface {
  599. modifySpan(s *Span)
  600. }
  601. type withResponse struct {
  602. *http.Response
  603. }
  604. // WithResponse returns an option that can be passed to Finish that indicates
  605. // that some labels for the span should be set using the given *http.Response.
  606. //
  607. // Deprecated: see https://cloud.google.com/trace/docs/setup/go.
  608. func WithResponse(resp *http.Response) FinishOption {
  609. return withResponse{resp}
  610. }
  611. func (u withResponse) modifySpan(s *Span) {
  612. if u.Response != nil {
  613. s.statusCode = u.StatusCode
  614. }
  615. }
  616. // Finish declares that the span has finished.
  617. //
  618. // If s is nil, Finish does nothing and returns nil.
  619. //
  620. // If the option trace.WithResponse(resp) is passed, then some labels are set
  621. // for s using information in the given *http.Response. This is useful when the
  622. // span is for an outgoing http request; s will typically have been created by
  623. // NewRemoteChild in this case.
  624. //
  625. // If s is a root span (one created by SpanFromRequest) then s, and all its
  626. // descendant spans that have finished, are uploaded to the Google Stackdriver
  627. // Trace server asynchronously.
  628. //
  629. // Deprecated: see https://cloud.google.com/trace/docs/setup/go.
  630. func (s *Span) Finish(opts ...FinishOption) {
  631. if s == nil {
  632. return
  633. }
  634. if !s.Traced() {
  635. return
  636. }
  637. s.trace.finish(s, false, opts...)
  638. }
  639. // FinishWait is like Finish, but if s is a root span, it waits until uploading
  640. // is finished, then returns an error if one occurred.
  641. //
  642. // Deprecated: see https://cloud.google.com/trace/docs/setup/go.
  643. func (s *Span) FinishWait(opts ...FinishOption) error {
  644. if s == nil {
  645. return nil
  646. }
  647. if !s.Traced() {
  648. return nil
  649. }
  650. return s.trace.finish(s, true, opts...)
  651. }
  652. func spanHeader(traceID string, spanID uint64, options optionFlags) string {
  653. // See https://cloud.google.com/trace/docs/faq for the header format.
  654. return fmt.Sprintf("%s/%d;o=%d", traceID, spanID, options)
  655. }
  656. func (s *Span) setStackLabel() {
  657. var stack stackLabelValue
  658. lastSigPanic, inTraceLibrary := false, true
  659. for _, pc := range s.stack {
  660. if pc == 0 {
  661. break
  662. }
  663. if !lastSigPanic {
  664. pc--
  665. }
  666. fn := runtime.FuncForPC(pc)
  667. file, line := fn.FileLine(pc)
  668. // Name has one of the following forms:
  669. // path/to/package.Foo
  670. // path/to/package.(Type).Foo
  671. // For the first form, we store the whole name in the Method field of the
  672. // stack frame. For the second form, we set the Method field to "Foo" and
  673. // the Class field to "path/to/package.(Type)".
  674. name := fn.Name()
  675. if inTraceLibrary && !strings.HasPrefix(name, "cloud.google.com/go/trace.") {
  676. inTraceLibrary = false
  677. }
  678. var class string
  679. if i := strings.Index(name, ")."); i != -1 {
  680. class, name = name[:i+1], name[i+2:]
  681. }
  682. frame := stackFrame{
  683. Class: class,
  684. Method: name,
  685. Filename: file,
  686. Line: int64(line),
  687. }
  688. if inTraceLibrary && len(stack.Frames) == 1 {
  689. stack.Frames[0] = frame
  690. } else {
  691. stack.Frames = append(stack.Frames, frame)
  692. }
  693. lastSigPanic = fn.Name() == "runtime.sigpanic"
  694. }
  695. if label, err := json.Marshal(stack); err == nil {
  696. s.SetLabel(LabelStackTrace, string(label))
  697. }
  698. }