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
20 "google.golang.org/grpc"
21
22 "time"
23 )
24
25
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
35 if s == "" {
36 s = "unknown"
37 }
38 if m == "" {
39 m = "unknown"
40 }
41
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
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
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
72 err = invoker(ctx, method, req, reply, cc, opts...)
73
74 observeRPC(start, s, m)
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
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
111 fmt.Printf("[go-easyops] WARNING - calling external method %s without callstate (%s)\n", targetname, utils.CallingFunction())
112 } else {
113
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
122
123
124 }
125
View as plain text