github.com/epsagon/epsagon-go@v1.39.0/wrappers/mongo/common_utils.go (about) 1 package epsagonmongo 2 3 import ( 4 "context" 5 "encoding/json" 6 "fmt" 7 "github.com/epsagon/epsagon-go/epsagon" 8 "github.com/epsagon/epsagon-go/protocol" 9 "github.com/epsagon/epsagon-go/tracer" 10 "github.com/google/uuid" 11 "go.mongodb.org/mongo-driver/mongo" 12 "strconv" 13 14 "reflect" 15 "runtime" 16 "strings" 17 ) 18 19 // currentFuncName returns the name of the caller function as a string 20 // for func Foo() { x := currentFuncName() }, x == "Foo" 21 func currentFuncName() string { 22 current := make([]uintptr, 1) 23 if level := runtime.Callers(2, current); level == 0 { 24 return "" 25 } 26 caller := runtime.FuncForPC(current[0] - 1) 27 if caller == nil { 28 return "" 29 } 30 sysFuncName := caller.Name() 31 return partitionByDelimiterAtIndex(sysFuncName, ".", -1) 32 33 } 34 35 func startMongoEvent(opName string, coll *MongoCollectionWrapper) *protocol.Event { 36 defer epsagon.GeneralEpsagonRecover("mongo-driver", currentFuncName(), coll.tracer) 37 return &protocol.Event{ 38 Id: "mongodb-" + uuid.New().String(), 39 Origin: "mongodb", 40 ErrorCode: protocol.ErrorCode_OK, 41 StartTime: tracer.GetTimestamp(), 42 Resource: createMongoResource(opName, coll), 43 } 44 } 45 46 func completeMongoEvent(currentTracer tracer.Tracer, event *protocol.Event) { 47 defer epsagon.GeneralEpsagonRecover("mongo-driver", currentFuncName(), currentTracer) 48 event.Duration = tracer.GetTimestamp() - event.StartTime 49 currentTracer.AddEvent(event) 50 51 } 52 53 func createMongoResource(opName string, coll *MongoCollectionWrapper) *protocol.Resource { 54 defer epsagon.GeneralEpsagonRecover("mongo-driver", currentFuncName(), coll.tracer) 55 return &protocol.Resource{ 56 Name: coll.Database().Name() + "." + coll.collection.Name(), 57 Type: "mongodb", 58 Operation: opName, 59 Metadata: make(map[string]string), 60 } 61 } 62 63 // extractStructFields parses the fields from a struct and adds it to metadata under field name metaField 64 // attempts to convert to int if possible, else keeps as a string 65 func extractStructFields( 66 metadata map[string]string, 67 metaField string, 68 s interface{}, 69 ) { 70 val := reflect.ValueOf(s) 71 if val.Kind() == reflect.Ptr { 72 val = val.Elem() 73 } 74 valuesMap := make(map[string]string, val.NumField()) 75 76 for i := 0; i < val.NumField(); i++ { 77 if val.Field(i).CanInterface() { 78 fieldVal := val.Field(i) 79 v := fmt.Sprintf("%q", fieldVal) 80 if _, err := strconv.Atoi(v); err == nil { 81 v = strconv.FormatInt(fieldVal.Int(), 10) 82 } 83 valuesMap[val.Type().Field(i).Name] = v 84 } 85 } 86 doc, _ := json.Marshal(valuesMap) 87 metadata[metaField] = string(doc) 88 } 89 90 // marshalToMetadata marshals any object to JSON and adds it as a string to metadata under metaFielf 91 func marshalToMetadata( 92 metadata map[string]string, 93 metaField string, 94 s interface{}, 95 config *tracer.Config, 96 ) { 97 docBytes, err := json.Marshal(s) 98 if err != nil { 99 epsagon.DebugLog(config.Debug, "Could not Marshal JSON", err) 100 } 101 docString := string(docBytes) 102 if docString == "" { 103 return 104 } 105 metadata[metaField] = docString 106 } 107 108 // readCursor accepts a cursor and returns a slice of maps 109 // each map represents a mongo document 110 func readCursor(cursor *mongo.Cursor) ([]map[string]string, error) { 111 var documents []map[string]string 112 err := cursor.All(context.Background(), &documents) 113 return documents, err 114 } 115 116 func logOperationFailure(messages ...string) { 117 for _, m := range messages { 118 epsagon.DebugLog(true, "[MONGO]", m) 119 } 120 } 121 122 // partition a string by delimiter and return the partitioned at the index 123 func partitionByDelimiterAtIndex(original, delimiter string, index int) string { 124 s := strings.Split(original, delimiter) 125 i := moduloFloor(len(s), index) 126 return s[i] 127 128 } 129 130 // flooring an index by size 131 // useful for wrapping around negative indices to positive 132 func moduloFloor(size, index int) int { 133 return (index + size) % size 134 }