...

Source file src/cloud.google.com/go/cloudsqlconn/internal/trace/trace.go

Documentation: cloud.google.com/go/cloudsqlconn/internal/trace

     1  // Copyright 2021 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  
    15  package trace
    16  
    17  import (
    18  	"context"
    19  
    20  	"go.opencensus.io/trace"
    21  	"google.golang.org/api/googleapi"
    22  	"google.golang.org/genproto/googleapis/rpc/code"
    23  	"google.golang.org/grpc/status"
    24  )
    25  
    26  // EndSpanFunc is a function that ends a span, reporting an error if necessary.
    27  type EndSpanFunc func(error)
    28  
    29  // Attribute annotates a span with additional data.
    30  type Attribute struct {
    31  	key   string
    32  	value interface{}
    33  }
    34  
    35  func (a Attribute) traceAttr() trace.Attribute {
    36  	// always use a string attribute for now
    37  	// if need for additional types arise, this can be expanded.
    38  	return trace.StringAttribute(a.key, a.value.(string))
    39  }
    40  
    41  // AddInstanceName creates an attribute with the Cloud SQL instance name.
    42  func AddInstanceName(name string) Attribute {
    43  	return Attribute{key: "/cloudsql/instance", value: name}
    44  }
    45  
    46  // AddDialerID creates an attribute to identify a particular dialer.
    47  func AddDialerID(dialerID string) Attribute {
    48  	return Attribute{key: "/cloudsql/dialer_id", value: dialerID}
    49  }
    50  
    51  // StartSpan begins a span with the provided name and returns a context and a
    52  // function to end the created span.
    53  func StartSpan(ctx context.Context, name string, attrs ...Attribute) (context.Context, EndSpanFunc) {
    54  	var span *trace.Span
    55  	ctx, span = trace.StartSpan(ctx, name)
    56  	as := make([]trace.Attribute, 0, len(attrs))
    57  	for _, a := range attrs {
    58  		as = append(as, a.traceAttr())
    59  	}
    60  	span.AddAttributes(as...)
    61  	return ctx, func(err error) {
    62  		if err != nil {
    63  			span.SetStatus(toStatus(err))
    64  		}
    65  		span.End()
    66  	}
    67  }
    68  
    69  // toStatus interrogates an error and converts it to an appropriate
    70  // OpenCensus status.
    71  // Note: this function is borrowed from
    72  // https://github.com/googleapis/google-cloud-go/blob/master/internal/trace/trace.go
    73  func toStatus(err error) trace.Status {
    74  	if err2, ok := err.(*googleapi.Error); ok {
    75  		return trace.Status{Code: httpStatusCodeToOCCode(err2.Code), Message: err2.Message}
    76  	}
    77  	if s, ok := status.FromError(err); ok {
    78  		return trace.Status{Code: int32(s.Code()), Message: s.Message()}
    79  	}
    80  	return trace.Status{Code: int32(code.Code_UNKNOWN), Message: err.Error()}
    81  }
    82  
    83  // Reference: https://github.com/googleapis/googleapis/blob/26b634d2724ac5dd30ae0b0cbfb01f07f2e4050e/google/rpc/code.proto
    84  func httpStatusCodeToOCCode(httpStatusCode int) int32 {
    85  	switch httpStatusCode {
    86  	case 200:
    87  		return int32(code.Code_OK)
    88  	case 499:
    89  		return int32(code.Code_CANCELLED)
    90  	case 500:
    91  		return int32(code.Code_UNKNOWN) // Could also be Code_INTERNAL, Code_DATA_LOSS
    92  	case 400:
    93  		return int32(code.Code_INVALID_ARGUMENT) // Could also be Code_OUT_OF_RANGE
    94  	case 504:
    95  		return int32(code.Code_DEADLINE_EXCEEDED)
    96  	case 404:
    97  		return int32(code.Code_NOT_FOUND)
    98  	case 409:
    99  		return int32(code.Code_ALREADY_EXISTS) // Could also be Code_ABORTED
   100  	case 403:
   101  		return int32(code.Code_PERMISSION_DENIED)
   102  	case 401:
   103  		return int32(code.Code_UNAUTHENTICATED)
   104  	case 429:
   105  		return int32(code.Code_RESOURCE_EXHAUSTED)
   106  	case 501:
   107  		return int32(code.Code_UNIMPLEMENTED)
   108  	case 503:
   109  		return int32(code.Code_UNAVAILABLE)
   110  	default:
   111  		return int32(code.Code_UNKNOWN)
   112  	}
   113  }
   114  

View as plain text