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  }