github.com/SaurabhDubey-Groww/go-cloud@v0.0.0-20221124105541-b26c29285fd8/server/requestlog/stackdriver_test.go (about) 1 // Copyright 2018 The Go Cloud Development Kit Authors 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 // https://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 requestlog 16 17 import ( 18 "bytes" 19 "context" 20 "encoding/json" 21 "fmt" 22 "io" 23 "io/ioutil" 24 "net/http" 25 "net/http/httptest" 26 "strings" 27 "testing" 28 "time" 29 30 "go.opencensus.io/trace" 31 ) 32 33 func TestStackdriverLog(t *testing.T) { 34 const ( 35 startTime = 1507914000 36 startTimeNanos = 512 37 38 latencySec = 5 39 latencyNanos = 123456789 40 41 endTime = startTime + latencySec 42 endTimeNanos = startTimeNanos + latencyNanos 43 ) 44 ctx, span := trace.StartSpan(context.Background(), "test") 45 defer span.End() 46 sc := trace.FromContext(ctx).SpanContext() 47 buf := new(bytes.Buffer) 48 var logErr error 49 l := NewStackdriverLogger(buf, func(e error) { logErr = e }) 50 want := &Entry{ 51 ReceivedTime: time.Unix(startTime, startTimeNanos), 52 RequestMethod: "POST", 53 RequestURL: "/foo/bar", 54 RequestHeaderSize: 456, 55 RequestBodySize: 123000, 56 UserAgent: "Chrome proxied through Firefox and Edge", 57 Referer: "http://www.example.com/", 58 Proto: "HTTP/1.1", 59 RemoteIP: "12.34.56.78", 60 ServerIP: "127.0.0.1", 61 Status: 404, 62 ResponseHeaderSize: 555, 63 ResponseBodySize: 789000, 64 Latency: latencySec*time.Second + latencyNanos*time.Nanosecond, 65 TraceID: sc.TraceID, 66 SpanID: sc.SpanID, 67 } 68 ent := *want // copy in case Log accidentally mutates 69 l.Log(&ent) 70 if logErr != nil { 71 t.Error("Logger called error callback:", logErr) 72 } 73 74 var got json.RawMessage 75 if err := json.Unmarshal(buf.Bytes(), &got); err != nil { 76 t.Fatal("Unmarshal:", err) 77 } 78 79 var r map[string]interface{} 80 if err := json.Unmarshal(got, &r); err != nil { 81 t.Error("Unmarshal record:", err) 82 } else { 83 rr, _ := r["httpRequest"].(map[string]interface{}) 84 if rr == nil { 85 t.Error("httpRequest does not exist in record or is not a JSON object") 86 } 87 if got, want := jsonString(rr, "requestMethod"), ent.RequestMethod; got != want { 88 t.Errorf("httpRequest.requestMethod = %q; want %q", got, want) 89 } 90 if got, want := jsonString(rr, "requestUrl"), ent.RequestURL; got != want { 91 t.Errorf("httpRequest.requestUrl = %q; want %q", got, want) 92 } 93 if got, want := jsonString(rr, "requestSize"), "123456"; got != want { 94 t.Errorf("httpRequest.requestSize = %q; want %q", got, want) 95 } 96 if got, want := jsonNumber(rr, "status"), float64(ent.Status); got != want { 97 t.Errorf("httpRequest.status = %d; want %d", int64(got), int64(want)) 98 } 99 if got, want := jsonString(rr, "responseSize"), "789555"; got != want { 100 t.Errorf("httpRequest.responseSize = %q; want %q", got, want) 101 } 102 if got, want := jsonString(rr, "userAgent"), ent.UserAgent; got != want { 103 t.Errorf("httpRequest.userAgent = %q; want %q", got, want) 104 } 105 if got, want := jsonString(rr, "remoteIp"), ent.RemoteIP; got != want { 106 t.Errorf("httpRequest.remoteIp = %q; want %q", got, want) 107 } 108 if got, want := jsonString(rr, "referer"), ent.Referer; got != want { 109 t.Errorf("httpRequest.referer = %q; want %q", got, want) 110 } 111 if got, want := jsonString(rr, "latency"), "5.123456789"; parseLatency(got) != want { 112 t.Errorf("httpRequest.latency = %q; want %q", got, want+"s") 113 } 114 ts, _ := r["timestamp"].(map[string]interface{}) 115 if ts == nil { 116 t.Error("timestamp does not exist in record or is not a JSON object") 117 } 118 if got, want := jsonNumber(ts, "seconds"), float64(endTime); got != want { 119 t.Errorf("timestamp.seconds = %g; want %g", got, want) 120 } 121 if got, want := jsonNumber(ts, "nanos"), float64(endTimeNanos); got != want { 122 t.Errorf("timestamp.nanos = %g; want %g", got, want) 123 } 124 if got, want := jsonString(r, "logging.googleapis.com/trace"), ent.TraceID.String(); got != want { 125 t.Errorf("traceID = %q; want %q", got, want) 126 } 127 if got, want := jsonString(r, "logging.googleapis.com/spanId"), ent.SpanID.String(); got != want { 128 t.Errorf("spanID = %q; want %q", got, want) 129 } 130 } 131 } 132 133 func parseLatency(s string) string { 134 s = strings.TrimSpace(s) 135 if !strings.HasSuffix(s, "s") { 136 return "" 137 } 138 s = strings.TrimSpace(s[:len(s)-1]) 139 for _, c := range s { 140 if !(c >= '0' && c <= '9') && c != '.' { 141 return "" 142 } 143 } 144 return s 145 } 146 147 func jsonString(obj map[string]interface{}, k string) string { 148 v, _ := obj[k].(string) 149 return v 150 } 151 152 func jsonNumber(obj map[string]interface{}, k string) float64 { 153 v, _ := obj[k].(float64) 154 return v 155 } 156 157 func BenchmarkStackdriverLog(b *testing.B) { 158 ent := &Entry{ 159 ReceivedTime: time.Date(2017, time.October, 13, 17, 0, 0, 512, time.UTC), 160 RequestMethod: "POST", 161 RequestURL: "/foo/bar", 162 RequestHeaderSize: 456, 163 RequestBodySize: 123000, 164 UserAgent: "Chrome proxied through Firefox and Edge", 165 Referer: "http://www.example.com/", 166 Proto: "HTTP/1.1", 167 RemoteIP: "12.34.56.78", 168 ServerIP: "127.0.0.1", 169 Status: 404, 170 ResponseHeaderSize: 555, 171 ResponseBodySize: 789000, 172 Latency: 5 * time.Second, 173 } 174 var buf bytes.Buffer 175 l := NewStackdriverLogger(&buf, func(error) {}) 176 l.Log(ent) 177 b.ReportAllocs() 178 b.SetBytes(int64(buf.Len())) 179 buf.Reset() 180 b.ResetTimer() 181 182 l = NewStackdriverLogger(ioutil.Discard, func(error) {}) 183 for i := 0; i < b.N; i++ { 184 l.Log(ent) 185 } 186 } 187 188 func BenchmarkE2E(b *testing.B) { 189 run := func(b *testing.B, handler http.Handler) { 190 s := httptest.NewServer(handler) 191 defer s.Close() 192 b.ReportAllocs() 193 for i := 0; i < b.N; i++ { 194 resp, err := http.Get(s.URL) 195 if err != nil { 196 b.Fatal(err) 197 } 198 io.Copy(ioutil.Discard, resp.Body) 199 resp.Body.Close() 200 } 201 } 202 b.Run("Baseline", func(b *testing.B) { 203 run(b, http.HandlerFunc(benchHandler)) 204 }) 205 b.Run("WithLog", func(b *testing.B) { 206 l := NewStackdriverLogger(ioutil.Discard, func(error) {}) 207 run(b, NewHandler(l, http.HandlerFunc(benchHandler))) 208 }) 209 } 210 211 func benchHandler(w http.ResponseWriter, r *http.Request) { 212 const msg = "Hello, World!" 213 w.Header().Set("Content-Length", fmt.Sprint(len(msg))) 214 io.WriteString(w, msg) 215 }