mirror of https://github.com/milvus-io/milvus.git
302 lines
6.4 KiB
Go
302 lines
6.4 KiB
Go
// Licensed to the LF AI & Data foundation under one
|
|
// or more contributor license agreements. See the NOTICE file
|
|
// distributed with this work for additional information
|
|
// regarding copyright ownership. The ASF licenses this file
|
|
// to you under the Apache License, Version 2.0 (the
|
|
// "License"); you may not use this file except in compliance
|
|
// with the License. You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package info
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"path"
|
|
"strings"
|
|
"time"
|
|
|
|
"go.opentelemetry.io/otel/trace"
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/codes"
|
|
"google.golang.org/grpc/metadata"
|
|
"google.golang.org/grpc/peer"
|
|
"google.golang.org/grpc/status"
|
|
"google.golang.org/protobuf/proto"
|
|
|
|
"github.com/milvus-io/milvus-proto/go-api/v2/commonpb"
|
|
"github.com/milvus-io/milvus-proto/go-api/v2/milvuspb"
|
|
"github.com/milvus-io/milvus/internal/proxy/connection"
|
|
"github.com/milvus-io/milvus/pkg/v2/util/merr"
|
|
"github.com/milvus-io/milvus/pkg/v2/util/requestutil"
|
|
)
|
|
|
|
type GrpcAccessInfo struct {
|
|
ctx context.Context
|
|
status *commonpb.Status
|
|
req interface{}
|
|
resp interface{}
|
|
err error
|
|
|
|
grpcInfo *grpc.UnaryServerInfo
|
|
start time.Time
|
|
end time.Time
|
|
}
|
|
|
|
func NewGrpcAccessInfo(ctx context.Context, grpcInfo *grpc.UnaryServerInfo, req interface{}) *GrpcAccessInfo {
|
|
accessInfo := &GrpcAccessInfo{
|
|
ctx: ctx,
|
|
grpcInfo: grpcInfo,
|
|
req: req,
|
|
start: time.Now(),
|
|
}
|
|
|
|
return accessInfo
|
|
}
|
|
|
|
// update context for more info
|
|
func (i *GrpcAccessInfo) UpdateCtx(ctx context.Context) {
|
|
i.ctx = ctx
|
|
}
|
|
|
|
func (i *GrpcAccessInfo) SetResult(resp interface{}, err error) {
|
|
i.resp = resp
|
|
i.err = err
|
|
i.end = time.Now()
|
|
|
|
// extract status from response
|
|
baseResp, ok := i.resp.(BaseResponse)
|
|
if ok {
|
|
i.status = baseResp.GetStatus()
|
|
return
|
|
}
|
|
|
|
status, ok := i.resp.(*commonpb.Status)
|
|
if ok {
|
|
i.status = status
|
|
return
|
|
}
|
|
}
|
|
|
|
func (i *GrpcAccessInfo) TimeCost() string {
|
|
if i.end.IsZero() {
|
|
return Unknown
|
|
}
|
|
return fmt.Sprint(i.end.Sub(i.start))
|
|
}
|
|
|
|
func (i *GrpcAccessInfo) TimeNow() string {
|
|
return time.Now().Format(timeFormat)
|
|
}
|
|
|
|
func (i *GrpcAccessInfo) TimeStart() string {
|
|
if i.start.IsZero() {
|
|
return Unknown
|
|
}
|
|
return i.start.Format(timeFormat)
|
|
}
|
|
|
|
func (i *GrpcAccessInfo) TimeEnd() string {
|
|
if i.end.IsZero() {
|
|
return Unknown
|
|
}
|
|
return i.end.Format(timeFormat)
|
|
}
|
|
|
|
func (i *GrpcAccessInfo) MethodName() string {
|
|
_, methodName := path.Split(i.grpcInfo.FullMethod)
|
|
return methodName
|
|
}
|
|
|
|
func (i *GrpcAccessInfo) Address() string {
|
|
ip, ok := peer.FromContext(i.ctx)
|
|
if !ok {
|
|
return "Unknown"
|
|
}
|
|
return fmt.Sprintf("%s-%s", ip.Addr.Network(), ip.Addr.String())
|
|
}
|
|
|
|
func (i *GrpcAccessInfo) TraceID() string {
|
|
meta, ok := metadata.FromOutgoingContext(i.ctx)
|
|
if ok {
|
|
return meta.Get(ClientRequestIDKey)[0]
|
|
}
|
|
|
|
traceID := trace.SpanFromContext(i.ctx).SpanContext().TraceID()
|
|
if !traceID.IsValid() {
|
|
return Unknown
|
|
}
|
|
|
|
return traceID.String()
|
|
}
|
|
|
|
func (i *GrpcAccessInfo) MethodStatus() string {
|
|
code := status.Code(i.err)
|
|
if code != codes.OK && code != codes.Unknown {
|
|
return fmt.Sprintf("Grpc%s", code.String())
|
|
}
|
|
|
|
if i.status.GetCode() != 0 || i.err != nil {
|
|
return "Failed"
|
|
}
|
|
|
|
return "Successful"
|
|
}
|
|
|
|
func (i *GrpcAccessInfo) UserName() string {
|
|
username, err := getCurUserFromContext(i.ctx)
|
|
if err != nil {
|
|
return Unknown
|
|
}
|
|
return username
|
|
}
|
|
|
|
type SizeResponse interface {
|
|
XXX_Size() int
|
|
}
|
|
|
|
func (i *GrpcAccessInfo) ResponseSize() string {
|
|
var size int
|
|
switch r := i.resp.(type) {
|
|
case SizeResponse:
|
|
size = r.XXX_Size()
|
|
case proto.Message:
|
|
size = proto.Size(r)
|
|
default:
|
|
return Unknown
|
|
}
|
|
|
|
return fmt.Sprint(size)
|
|
}
|
|
|
|
type BaseResponse interface {
|
|
GetStatus() *commonpb.Status
|
|
}
|
|
|
|
func (i *GrpcAccessInfo) ErrorCode() string {
|
|
if i.status != nil {
|
|
return fmt.Sprint(i.status.GetCode())
|
|
}
|
|
|
|
return fmt.Sprint(merr.Code(i.err))
|
|
}
|
|
|
|
func (i *GrpcAccessInfo) respStatus() *commonpb.Status {
|
|
baseResp, ok := i.resp.(BaseResponse)
|
|
if ok {
|
|
return baseResp.GetStatus()
|
|
}
|
|
|
|
status, ok := i.resp.(*commonpb.Status)
|
|
if ok {
|
|
return status
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (i *GrpcAccessInfo) ErrorMsg() string {
|
|
if i.err != nil {
|
|
return strings.ReplaceAll(i.err.Error(), "\n", "\\n")
|
|
}
|
|
|
|
if status := i.respStatus(); status != nil {
|
|
return strings.ReplaceAll(status.GetReason(), "\n", "\\n")
|
|
}
|
|
|
|
return Unknown
|
|
}
|
|
|
|
func (i *GrpcAccessInfo) ErrorType() string {
|
|
if i.err != nil {
|
|
return merr.GetErrorType(i.err).String()
|
|
}
|
|
|
|
if status := i.respStatus(); status.GetCode() > 0 {
|
|
if _, ok := status.ExtraInfo[merr.InputErrorFlagKey]; ok {
|
|
return merr.InputError.String()
|
|
}
|
|
return merr.SystemError.String()
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
func (i *GrpcAccessInfo) DbName() string {
|
|
name, ok := requestutil.GetDbNameFromRequest(i.req)
|
|
if !ok {
|
|
return Unknown
|
|
}
|
|
return name.(string)
|
|
}
|
|
|
|
func (i *GrpcAccessInfo) CollectionName() string {
|
|
name, ok := requestutil.GetCollectionNameFromRequest(i.req)
|
|
if !ok {
|
|
return Unknown
|
|
}
|
|
return name.(string)
|
|
}
|
|
|
|
func (i *GrpcAccessInfo) PartitionName() string {
|
|
name, ok := requestutil.GetPartitionNameFromRequest(i.req)
|
|
if ok {
|
|
return name.(string)
|
|
}
|
|
|
|
names, ok := requestutil.GetPartitionNamesFromRequest(i.req)
|
|
if ok {
|
|
return fmt.Sprint(names.([]string))
|
|
}
|
|
|
|
return Unknown
|
|
}
|
|
|
|
func (i *GrpcAccessInfo) Expression() string {
|
|
expr, ok := requestutil.GetExprFromRequest(i.req)
|
|
if ok {
|
|
return expr.(string)
|
|
}
|
|
|
|
dsl, ok := requestutil.GetDSLFromRequest(i.req)
|
|
if ok {
|
|
return dsl.(string)
|
|
}
|
|
return Unknown
|
|
}
|
|
|
|
func (i *GrpcAccessInfo) SdkVersion() string {
|
|
clientInfo := connection.GetManager().Get(i.ctx)
|
|
if clientInfo != nil {
|
|
return clientInfo.GetSdkType() + "-" + clientInfo.GetSdkVersion()
|
|
}
|
|
|
|
if req, ok := i.req.(*milvuspb.ConnectRequest); ok {
|
|
return req.GetClientInfo().GetSdkType() + "-" + req.GetClientInfo().GetSdkVersion()
|
|
}
|
|
|
|
return getSdkVersionByUserAgent(i.ctx)
|
|
}
|
|
|
|
func (i *GrpcAccessInfo) OutputFields() string {
|
|
fields, ok := requestutil.GetOutputFieldsFromRequest(i.req)
|
|
if ok {
|
|
return fmt.Sprint(fields.([]string))
|
|
}
|
|
return Unknown
|
|
}
|
|
|
|
func (i *GrpcAccessInfo) ConsistencyLevel() string {
|
|
level, ok := requestutil.GetConsistencyLevelFromRequst(i.req)
|
|
if ok {
|
|
return level.String()
|
|
}
|
|
return Unknown
|
|
}
|