...

Source file src/golang.conradwood.net/go-easyops/client/unary_interceptor.go

Documentation: golang.conradwood.net/go-easyops/client

     1  package client
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"golang.conradwood.net/go-easyops/auth"
     8  	"golang.conradwood.net/go-easyops/cmdline"
     9  	"golang.conradwood.net/go-easyops/common"
    10  	"golang.conradwood.net/go-easyops/ctx"
    11  	pctx "golang.conradwood.net/go-easyops/ctx"
    12  	"golang.conradwood.net/go-easyops/ctx/shared"
    13  	pp "golang.conradwood.net/go-easyops/profiling"
    14  	"golang.conradwood.net/go-easyops/prometheus"
    15  	"golang.conradwood.net/go-easyops/rpc"
    16  	"golang.conradwood.net/go-easyops/tokens"
    17  	"golang.conradwood.net/go-easyops/utils"
    18  
    19  	//	"reflect"
    20  	"google.golang.org/grpc"
    21  	//	"google.golang.org/grpc/metadata"
    22  	"time"
    23  )
    24  
    25  // called for each outbound rpc
    26  func ClientMetricsUnaryInterceptor(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
    27  	if ctx == nil {
    28  		return fmt.Errorf("missing context, will not make outbound call without context")
    29  	}
    30  	pp.ClientRpcEntered()
    31  	defer pp.ClientRpcDone()
    32  	start := time.Now()
    33  	s, m, err := splitMethodAndService(method)
    34  	// keep prometheus happy: (not to panic)
    35  	if s == "" {
    36  		s = "unknown"
    37  	}
    38  	if m == "" {
    39  		m = "unknown"
    40  	}
    41  	// bad programmer! - log it prominently (often)
    42  	if err != nil {
    43  		fmt.Printf("[go-easyops] invalid fqdn method: \"%s\": %s\n", method, err)
    44  	}
    45  	if cmdline.IsDebugRPCClient() && !isKnownNotAuthRPCs(s, m) {
    46  		ls := pctx.GetLocalState(ctx)
    47  		// technically.. this is _wrong_. the CallingService() is the service which called us.
    48  		if ls.CallingService() == nil && ls.User() == nil {
    49  			utils.PrintStack("[go-easyops] outbound context issue")
    50  			fmt.Printf("[go-easyops] WARNING calling another service (%s.%s) with a context without authentication (%s)\n", s, m, pctx.Context2String(ctx))
    51  		} else if ls.CallingService() == nil && tokens.GetServiceTokenParameter() != "" {
    52  			utils.PrintStack("[go-easyops] outbound context issue")
    53  			fmt.Printf("[go-easyops] WARNING calling another service (%s.%s) with a context without calling service information (%s)\n", s, m, pctx.Context2String(ctx))
    54  		}
    55  		/*
    56  			_, ex := metadata.FromOutgoingContext(ctx)
    57  			if !ex {
    58  				if *debug_rpc_client {
    59  					fmt.Printf("Context: %#v\n", ctx)
    60  					utils.PrintStack("No metadata:")
    61  				}
    62  				fmt.Printf("[go-easyops] WARNING - calling external method %s.%s without metadata (authentication)\n", s, m)
    63  			}
    64  		*/
    65  	}
    66  
    67  	print_debug_client(ctx, fmt.Sprintf("%s.%s()", s, m))
    68  
    69  	grpc_client_sent.With(prometheus.Labels{"method": m, "servicename": s}).Inc()
    70  
    71  	// generated by gRPC, calls the gRPC method
    72  	err = invoker(ctx, method, req, reply, cc, opts...)
    73  
    74  	observeRPC(start, s, m) // record time.Since(start) into metric
    75  
    76  	dur := time.Since(start)
    77  	if err != nil {
    78  		grpc_client_failed.With(prometheus.Labels{"method": m, "servicename": s}).Inc()
    79  		if *dialer_debug || cmdline.IsDebugRPCClient() {
    80  			fmt.Printf("Invoked remote method=%s duration=%0.2fs error=%v (Method: \"%s\" in Service: \"%s\")\n", method, dur.Seconds(), err, m, s)
    81  			utils.PrintStack("method %s/%s invoked at:\n", s, m)
    82  		}
    83  	} else if cmdline.IsDebugRPCClient() {
    84  		fmt.Printf("Invoked method %s.%s (%0.2fs)...\n", s, m, dur.Seconds())
    85  	}
    86  
    87  	return err
    88  }
    89  func print_debug_client(ictx context.Context, targetname string) {
    90  	if !*dialer_debug && !cmdline.IsDebugRPCClient() {
    91  		return
    92  	}
    93  	if cmdline.ContextWithBuilder() {
    94  		ls := ctx.GetLocalState(ictx)
    95  		/*
    96  			if ls == nil || ls.CallingService() == nil && strings.Contains(targetname, "Mail") {
    97  				panic("no calling service")
    98  			}
    99  		*/
   100  		us := auth.UserIDString(common.VerifySignedUser(ls.User()))
   101  		sv := auth.UserIDString(common.VerifySignedUser(ls.CallingService()))
   102  		cmdline.DebugfContext("Invoking method %s as %s (service %s)...\n", targetname, us, sv)
   103  		cmdline.DebugfContext("Outbound context:\n")
   104  		cmdline.DebugfContext("Loccalstate: %s\n", shared.LocalState2string(ls))
   105  
   106  		return
   107  	}
   108  	cs := rpc.CallStateFromContext(ictx)
   109  	if cs == nil {
   110  		//		utils.PrintStack("no callstate")
   111  		fmt.Printf("[go-easyops] WARNING - calling external method %s without callstate (%s)\n", targetname, utils.CallingFunction())
   112  	} else {
   113  		//		cs.PrintContext()
   114  		us := "none"
   115  		u := cs.User()
   116  		if u != nil {
   117  			us = fmt.Sprintf("UserID=%s, Email=%s", u.ID, u.Email)
   118  		}
   119  		fmt.Printf("Invoking method as %s...%s\n", targetname, us)
   120  	}
   121  	//fmt.Printf("Contype: %s (%T)\n", reflect.TypeOf(cc), cc)
   122  	//		fmt.Printf("Ctx: %#v\n", ctx)
   123  
   124  }
   125  

View as plain text