github.com/aacfactory/fns@v1.2.86-0.20240310083819-80d667fc0a17/services/metrics/metric.go (about) 1 /* 2 * Copyright 2023 Wang Min Xiang 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 */ 17 18 package metrics 19 20 import ( 21 "github.com/aacfactory/errors" 22 "github.com/aacfactory/fns/commons/bytex" 23 "github.com/aacfactory/fns/context" 24 "github.com/aacfactory/fns/services" 25 "time" 26 ) 27 28 var ( 29 contextKey = []byte("@fns:context:metrics") 30 ) 31 32 // Metric 33 // use @metric to enable in fn 34 type Metric struct { 35 Endpoint string `json:"endpoint" avro:"endpoint"` 36 Fn string `json:"fn" avro:"fn"` 37 Latency int64 `json:"latency" avro:"latency"` 38 Succeed bool `json:"succeed" avro:"succeed"` 39 ErrorCode int `json:"errorCode" avro:"errorCode"` 40 ErrorName string `json:"errorName" avro:"errorName"` 41 DeviceId string `json:"deviceId" avro:"deviceId"` 42 DeviceIp string `json:"deviceIp" avro:"deviceIp"` 43 beg time.Time 44 } 45 46 func Begin(ctx context.Context) { 47 r, ok := services.TryLoadRequest(ctx) 48 if !ok { 49 return 50 } 51 ep, fn := r.Fn() 52 metric := Metric{ 53 Endpoint: bytex.ToString(ep), 54 Fn: bytex.ToString(fn), 55 Latency: 0, 56 Succeed: false, 57 ErrorCode: 0, 58 ErrorName: "", 59 DeviceId: bytex.ToString(r.Header().DeviceId()), 60 DeviceIp: bytex.ToString(r.Header().DeviceIp()), 61 beg: time.Now(), 62 } 63 r.SetLocalValue(contextKey, metric) 64 return 65 } 66 67 func End(ctx context.Context) { 68 EndWithCause(ctx, nil) 69 } 70 71 func EndWithCause(ctx context.Context, cause error) { 72 v := ctx.LocalValue(contextKey) 73 if v == nil { 74 return 75 } 76 metric, has := v.(Metric) 77 if !has { 78 return 79 } 80 r, ok := services.TryLoadRequest(ctx) 81 if !ok { 82 return 83 } 84 ep, fn := r.Fn() 85 if metric.Endpoint != bytex.ToString(ep) && metric.Fn != bytex.ToString(fn) { 86 return 87 } 88 metric.Latency = time.Now().Sub(metric.beg).Milliseconds() 89 if cause == nil { 90 metric.Succeed = true 91 } else { 92 err := errors.Wrap(cause) 93 metric.ErrorCode = err.Code() 94 metric.ErrorName = err.Name() 95 } 96 report(ctx, metric) 97 }