github.com/epsagon/epsagon-go@v1.39.0/wrappers/mongo/mongo.go (about)

     1  package epsagonmongo
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"github.com/epsagon/epsagon-go/epsagon"
     8  	"github.com/epsagon/epsagon-go/tracer"
     9  	"go.mongodb.org/mongo-driver/mongo"
    10  	mongoOptions "go.mongodb.org/mongo-driver/mongo/options"
    11  )
    12  
    13  // MongoCollectionWrapper is Epsagon's wrapper for mongo.Collection
    14  type MongoCollectionWrapper struct {
    15  	collection *mongo.Collection
    16  	tracer     tracer.Tracer
    17  }
    18  
    19  func WrapMongoCollection(
    20  	collection *mongo.Collection, ctx ...context.Context,
    21  ) *MongoCollectionWrapper {
    22  	return &MongoCollectionWrapper{
    23  		collection: collection,
    24  		tracer:     epsagon.ExtractTracer(ctx),
    25  	}
    26  }
    27  
    28  func (coll *MongoCollectionWrapper) Name() string {
    29  	return coll.collection.Name()
    30  }
    31  
    32  func (coll *MongoCollectionWrapper) Database() *mongo.Database {
    33  	return coll.collection.Database()
    34  }
    35  
    36  func (coll *MongoCollectionWrapper) Clone(opts ...*mongoOptions.CollectionOptions) (interface{}, error) {
    37  	event := startMongoEvent("Clone", coll)
    38  	response, err := coll.collection.Clone(
    39  		opts...,
    40  	)
    41  	if err != nil {
    42  		logOperationFailure(fmt.Sprint("Could not complete Clone"), err.Error())
    43  		coll.tracer.AddExceptionTypeAndMessage(
    44  			"mongo-driver",
    45  			err.Error(),
    46  		)
    47  	}
    48  	if event != nil {
    49  		completeMongoEvent(coll.tracer, event)
    50  	}
    51  	return response, err
    52  }
    53  
    54  func (coll *MongoCollectionWrapper) InsertOne(
    55  	ctx context.Context, document interface{}, opts ...*mongoOptions.InsertOneOptions,
    56  ) (*mongo.InsertOneResult, error) {
    57  	event := startMongoEvent("InsertOne", coll)
    58  	fmt.Println("EVENT::::")
    59  	fmt.Println(event)
    60  	response, err := coll.collection.InsertOne(
    61  		ctx,
    62  		document,
    63  		opts...,
    64  	)
    65  
    66  	if err != nil {
    67  		logOperationFailure(fmt.Sprint("Could not complete InsertOne"), err.Error())
    68  		coll.tracer.AddExceptionTypeAndMessage(
    69  			"mongo-driver",
    70  			err.Error(),
    71  		)
    72  	}
    73  
    74  	if event != nil {
    75  		if config := coll.tracer.GetConfig(); !config.MetadataOnly {
    76  			marshalToMetadata(event.Resource.Metadata, "document", document, config)
    77  			marshalToMetadata(event.Resource.Metadata, "response", response, config)
    78  		}
    79  		completeMongoEvent(coll.tracer, event)
    80  	}
    81  	return response, err
    82  }
    83  
    84  func (coll *MongoCollectionWrapper) InsertMany(
    85  	ctx context.Context, documents []interface{}, opts ...*mongoOptions.InsertManyOptions,
    86  ) (*mongo.InsertManyResult, error) {
    87  	event := startMongoEvent("InsertMany", coll)
    88  	response, err := coll.collection.InsertMany(
    89  		ctx,
    90  		documents,
    91  		opts...,
    92  	)
    93  	if err != nil {
    94  		logOperationFailure(fmt.Sprintf("Could not complete %s", "InsertMany"), err.Error())
    95  		coll.tracer.AddExceptionTypeAndMessage(
    96  			"mongo-driver",
    97  			err.Error(),
    98  		)
    99  	}
   100  
   101  	if event != nil {
   102  		if config := coll.tracer.GetConfig(); !config.MetadataOnly {
   103  			marshalToMetadata(event.Resource.Metadata, "documents", documents, config)
   104  			marshalToMetadata(event.Resource.Metadata, "response", *response, config)
   105  		}
   106  		completeMongoEvent(coll.tracer, event)
   107  	}
   108  	return response, err
   109  }
   110  
   111  func (coll *MongoCollectionWrapper) BulkWrite(
   112  	ctx context.Context, models []mongo.WriteModel, opts ...*mongoOptions.BulkWriteOptions,
   113  ) (*mongo.BulkWriteResult, error) {
   114  	event := startMongoEvent("BulkWrite", coll)
   115  	response, err := coll.collection.BulkWrite(
   116  		ctx,
   117  		models,
   118  		opts...,
   119  	)
   120  	if err != nil {
   121  		logOperationFailure(fmt.Sprint("Could not complete BulkWrite"), err.Error())
   122  		coll.tracer.AddExceptionTypeAndMessage(
   123  			"mongo-driver",
   124  			err.Error(),
   125  		)
   126  	}
   127  
   128  	if event != nil {
   129  		if config := coll.tracer.GetConfig(); !config.MetadataOnly {
   130  			marshalToMetadata(event.Resource.Metadata, "documents", models, config)
   131  		}
   132  		completeMongoEvent(coll.tracer, event)
   133  	}
   134  	return response, err
   135  }
   136  
   137  func (coll *MongoCollectionWrapper) DeleteOne(
   138  	ctx context.Context, filter interface{}, opts ...*mongoOptions.DeleteOptions,
   139  ) (*mongo.DeleteResult, error) {
   140  	event := startMongoEvent("DeleteOne", coll)
   141  	response, err := coll.collection.DeleteOne(
   142  		ctx,
   143  		filter,
   144  		opts...,
   145  	)
   146  	if err != nil {
   147  		logOperationFailure(fmt.Sprint("Could not complete DeleteOne"), err.Error())
   148  		coll.tracer.AddExceptionTypeAndMessage(
   149  			"mongo-driver",
   150  			err.Error(),
   151  		)
   152  	}
   153  
   154  	if event != nil {
   155  		if config := coll.tracer.GetConfig(); !config.MetadataOnly {
   156  			marshalToMetadata(event.Resource.Metadata, "params", filter, config)
   157  			marshalToMetadata(event.Resource.Metadata, "response", *response, config)
   158  		}
   159  		completeMongoEvent(coll.tracer, event)
   160  	}
   161  	return response, err
   162  }
   163  
   164  func (coll *MongoCollectionWrapper) DeleteMany(
   165  	ctx context.Context, filter interface{}, opts ...*mongoOptions.DeleteOptions,
   166  ) (*mongo.DeleteResult, error) {
   167  	event := startMongoEvent("DeleteMany", coll)
   168  	response, err := coll.collection.DeleteMany(
   169  		ctx,
   170  		filter,
   171  		opts...,
   172  	)
   173  	if err != nil {
   174  		logOperationFailure(fmt.Sprintf("Could not complete DeleteMany"), err.Error())
   175  		coll.tracer.AddExceptionTypeAndMessage(
   176  			"mongo-driver",
   177  			err.Error(),
   178  		)
   179  	}
   180  
   181  	if event != nil {
   182  		if config := coll.tracer.GetConfig(); !config.MetadataOnly {
   183  			marshalToMetadata(event.Resource.Metadata, "params", filter, config)
   184  			marshalToMetadata(event.Resource.Metadata, "response", response, config)
   185  		}
   186  		completeMongoEvent(coll.tracer, event)
   187  	}
   188  	return response, err
   189  }
   190  
   191  func (coll *MongoCollectionWrapper) UpdateOne(
   192  	ctx context.Context, filter interface{}, update interface{}, opts ...*mongoOptions.UpdateOptions,
   193  ) (*mongo.UpdateResult, error) {
   194  	event := startMongoEvent("UpdateOne", coll)
   195  	response, err := coll.collection.UpdateOne(
   196  		ctx,
   197  		filter,
   198  		update,
   199  		opts...,
   200  	)
   201  	if err != nil {
   202  		logOperationFailure(fmt.Sprintf("Could not complete %s", "UpdateOne"), err.Error())
   203  		coll.tracer.AddExceptionTypeAndMessage(
   204  			"mongo-driver",
   205  			err.Error(),
   206  		)
   207  	}
   208  
   209  	if event != nil {
   210  		if config := coll.tracer.GetConfig(); !config.MetadataOnly {
   211  			marshalToMetadata(event.Resource.Metadata, "filter", filter, config)
   212  			marshalToMetadata(event.Resource.Metadata, "update_conditions", update, config)
   213  			extractStructFields(event.Resource.Metadata, "response", *response)
   214  		}
   215  		completeMongoEvent(coll.tracer, event)
   216  	}
   217  	return response, err
   218  }
   219  
   220  func (coll *MongoCollectionWrapper) UpdateMany(
   221  	ctx context.Context, filter interface{}, update interface{}, opts ...*mongoOptions.UpdateOptions,
   222  ) (*mongo.UpdateResult, error) {
   223  	event := startMongoEvent("UpdateMany", coll)
   224  	response, err := coll.collection.UpdateMany(
   225  		ctx,
   226  		filter,
   227  		update,
   228  		opts...,
   229  	)
   230  	if err != nil {
   231  		logOperationFailure(fmt.Sprintf("Could not complete %s", "UpdateMany"), err.Error())
   232  		coll.tracer.AddExceptionTypeAndMessage(
   233  			"mongo-driver",
   234  			err.Error(),
   235  		)
   236  	}
   237  
   238  	if event != nil {
   239  		if config := coll.tracer.GetConfig(); !config.MetadataOnly {
   240  			marshalToMetadata(event.Resource.Metadata, "filter", filter, config)
   241  			marshalToMetadata(event.Resource.Metadata, "update_conditions", update, config)
   242  			extractStructFields(event.Resource.Metadata, "response", *response)
   243  		}
   244  		completeMongoEvent(coll.tracer, event)
   245  	}
   246  	return response, err
   247  }
   248  
   249  func (coll *MongoCollectionWrapper) UpdateByID(
   250  	ctx context.Context, id interface{}, update interface{}, opts ...*mongoOptions.UpdateOptions,
   251  ) (*mongo.UpdateResult, error) {
   252  	event := startMongoEvent("UpdateByID", coll)
   253  	response, err := coll.collection.UpdateByID(
   254  		ctx,
   255  		id,
   256  		update,
   257  		opts...,
   258  	)
   259  	if err != nil {
   260  		logOperationFailure(fmt.Sprintf("Could not complete %s", "UpdateByID"), err.Error())
   261  		coll.tracer.AddExceptionTypeAndMessage(
   262  			"mongo-driver",
   263  			err.Error(),
   264  		)
   265  	}
   266  
   267  	if event != nil {
   268  		if config := coll.tracer.GetConfig(); !config.MetadataOnly {
   269  			marshalToMetadata(event.Resource.Metadata, "id", id, config)
   270  			marshalToMetadata(event.Resource.Metadata, "update_conditions", update, config)
   271  			extractStructFields(event.Resource.Metadata, "response", response)
   272  		}
   273  		completeMongoEvent(coll.tracer, event)
   274  	}
   275  	return response, err
   276  }
   277  
   278  func (coll *MongoCollectionWrapper) ReplaceOne(
   279  	ctx context.Context, filter interface{}, replacement interface{}, opts ...*mongoOptions.ReplaceOptions,
   280  ) (*mongo.UpdateResult, error) {
   281  	event := startMongoEvent("ReplaceOne", coll)
   282  	response, err := coll.collection.ReplaceOne(
   283  		ctx,
   284  		filter,
   285  		replacement,
   286  		opts...,
   287  	)
   288  	if err != nil {
   289  		logOperationFailure(fmt.Sprintf("Could not complete %s", "ReplaceOne"), err.Error())
   290  		coll.tracer.AddExceptionTypeAndMessage(
   291  			"mongo-driver",
   292  			err.Error(),
   293  		)
   294  	}
   295  
   296  	if event != nil {
   297  		if config := coll.tracer.GetConfig(); !config.MetadataOnly {
   298  			marshalToMetadata(event.Resource.Metadata, "filter", filter, config)
   299  			marshalToMetadata(event.Resource.Metadata, "replacement", replacement, config)
   300  			extractStructFields(event.Resource.Metadata, "response", *response)
   301  		}
   302  		completeMongoEvent(coll.tracer, event)
   303  	}
   304  	return response, err
   305  }
   306  
   307  func (coll *MongoCollectionWrapper) Aggregate(
   308  	ctx context.Context, pipeline interface{}, opts ...*mongoOptions.AggregateOptions,
   309  ) (*mongo.Cursor, error) {
   310  	event := startMongoEvent("Aggregate", coll)
   311  	response, err := coll.collection.Aggregate(
   312  		ctx,
   313  		pipeline,
   314  		opts...,
   315  	)
   316  	if err != nil {
   317  		logOperationFailure(fmt.Sprintf("Could not complete %s", "Aggregate"), err.Error())
   318  		coll.tracer.AddExceptionTypeAndMessage(
   319  			"mongo-driver",
   320  			err.Error(),
   321  		)
   322  	}
   323  
   324  	docs, err := readCursor(response)
   325  	if err != nil {
   326  		logOperationFailure("Could not complete readCursor", err.Error())
   327  	}
   328  
   329  	if event != nil {
   330  		if config := coll.tracer.GetConfig(); !config.MetadataOnly {
   331  			marshalToMetadata(event.Resource.Metadata, "params", pipeline, config)
   332  			marshalToMetadata(event.Resource.Metadata, "response", docs, config)
   333  		}
   334  		completeMongoEvent(coll.tracer, event)
   335  	}
   336  	return response, err
   337  }
   338  
   339  func (coll *MongoCollectionWrapper) CountDocuments(
   340  	ctx context.Context, filter interface{}, opts ...*mongoOptions.CountOptions,
   341  ) (int64, error) {
   342  	event := startMongoEvent("CountDocuments", coll)
   343  	response, err := coll.collection.CountDocuments(
   344  		ctx,
   345  		filter,
   346  		opts...,
   347  	)
   348  	if err != nil {
   349  		logOperationFailure(fmt.Sprintf("Could not complete %s", "CountDocuments"), err.Error())
   350  		coll.tracer.AddExceptionTypeAndMessage(
   351  			"mongo-driver",
   352  			err.Error(),
   353  		)
   354  	}
   355  
   356  	if event != nil {
   357  		if config := coll.tracer.GetConfig(); !config.MetadataOnly {
   358  			marshalToMetadata(event.Resource.Metadata, "filter", filter, config)
   359  		}
   360  		event.Resource.Metadata["count"] = fmt.Sprintf("%d", response)
   361  		completeMongoEvent(coll.tracer, event)
   362  	}
   363  	return response, err
   364  }
   365  
   366  func (coll *MongoCollectionWrapper) EstimatedDocumentCount(
   367  	ctx context.Context, opts ...*mongoOptions.EstimatedDocumentCountOptions,
   368  ) (int64, error) {
   369  	event := startMongoEvent("EstimatedDocumentCount", coll)
   370  	response, err := coll.collection.EstimatedDocumentCount(
   371  		ctx,
   372  		opts...,
   373  	)
   374  	if err != nil {
   375  		logOperationFailure(fmt.Sprintf("Could not complete %s", "EstimatedDocumentCount"), err.Error())
   376  		coll.tracer.AddExceptionTypeAndMessage(
   377  			"mongo-driver",
   378  			err.Error(),
   379  		)
   380  	}
   381  
   382  	if event != nil {
   383  		if config := coll.tracer.GetConfig(); !config.MetadataOnly {
   384  			event.Resource.Metadata["estimated_count"] = fmt.Sprintf("%d", response)
   385  		}
   386  		completeMongoEvent(coll.tracer, event)
   387  	}
   388  	return response, err
   389  }
   390  
   391  func (coll *MongoCollectionWrapper) Distinct(
   392  	ctx context.Context, fieldName string, filter interface{}, opts ...*mongoOptions.DistinctOptions,
   393  ) ([]interface{}, error) {
   394  	event := startMongoEvent("Distinct", coll)
   395  	response, err := coll.collection.Distinct(
   396  		ctx,
   397  		fieldName,
   398  		filter,
   399  		opts...,
   400  	)
   401  	if err != nil {
   402  		logOperationFailure(fmt.Sprintf("Could not complete %s", "Distinct"), err.Error())
   403  		coll.tracer.AddExceptionTypeAndMessage(
   404  			"mongo-driver",
   405  			err.Error(),
   406  		)
   407  	}
   408  
   409  	if event != nil {
   410  		event.Resource.Metadata["field_name"] = fieldName
   411  		if config := coll.tracer.GetConfig(); !config.MetadataOnly {
   412  			marshalToMetadata(event.Resource.Metadata, "filter", filter, config)
   413  		}
   414  		completeMongoEvent(coll.tracer, event)
   415  	}
   416  	return response, err
   417  }
   418  
   419  func (coll *MongoCollectionWrapper) Find(
   420  	ctx context.Context, filter interface{}, opts ...*mongoOptions.FindOptions,
   421  ) (*mongo.Cursor, error) {
   422  	event := startMongoEvent("Find", coll)
   423  	response, err := coll.collection.Find(
   424  		ctx,
   425  		filter,
   426  		opts...,
   427  	)
   428  	if err != nil {
   429  		logOperationFailure(fmt.Sprintf("Could not complete %s", "Find"), err.Error())
   430  		coll.tracer.AddExceptionTypeAndMessage(
   431  			"mongo-driver",
   432  			err.Error(),
   433  		)
   434  	}
   435  
   436  	docs, err := readCursor(response)
   437  	if err != nil {
   438  		logOperationFailure("Could not complete readCursor", err.Error())
   439  	}
   440  
   441  	if event != nil {
   442  		if config := coll.tracer.GetConfig(); !config.MetadataOnly {
   443  			marshalToMetadata(event.Resource.Metadata, "filter", filter, config)
   444  			marshalToMetadata(event.Resource.Metadata, "documents", docs, config)
   445  		}
   446  		completeMongoEvent(coll.tracer, event)
   447  	}
   448  	return response, err
   449  }
   450  
   451  func (coll *MongoCollectionWrapper) FindOne(
   452  	ctx context.Context, filter interface{}, opts ...*mongoOptions.FindOneOptions,
   453  ) *mongo.SingleResult {
   454  	event := startMongoEvent("FindOne", coll)
   455  	response := coll.collection.FindOne(
   456  		ctx,
   457  		filter,
   458  		opts...,
   459  	)
   460  
   461  	var document map[string]string
   462  	response.Decode(&document)
   463  
   464  	if err := response.Err(); err != nil {
   465  		logOperationFailure("Could not complete Decode SingleResult", err.Error())
   466  		coll.tracer.AddExceptionTypeAndMessage(
   467  			"mongo-driver",
   468  			err.Error(),
   469  		)
   470  	}
   471  
   472  	if event != nil {
   473  		if config := coll.tracer.GetConfig(); !config.MetadataOnly {
   474  			marshalToMetadata(event.Resource.Metadata, "params", filter, config)
   475  			marshalToMetadata(event.Resource.Metadata, "document", document, config)
   476  		}
   477  		completeMongoEvent(coll.tracer, event)
   478  	}
   479  	return response
   480  }
   481  
   482  func (coll *MongoCollectionWrapper) FindOneAndDelete(
   483  	ctx context.Context, filter interface{}, opts ...*mongoOptions.FindOneAndDeleteOptions,
   484  ) *mongo.SingleResult {
   485  	event := startMongoEvent("FindOneAndDelete", coll)
   486  	response := coll.collection.FindOneAndDelete(
   487  		ctx,
   488  		filter,
   489  		opts...,
   490  	)
   491  
   492  	var document map[string]string
   493  	response.Decode(&document)
   494  	if err := response.Err(); err != nil {
   495  		logOperationFailure("Could not complete Decode SingleResult", err.Error())
   496  		coll.tracer.AddExceptionTypeAndMessage(
   497  			"mongo-driver",
   498  			err.Error(),
   499  		)
   500  	}
   501  
   502  	if event != nil {
   503  		if config := coll.tracer.GetConfig(); !config.MetadataOnly {
   504  			marshalToMetadata(event.Resource.Metadata, "params", filter, config)
   505  			marshalToMetadata(event.Resource.Metadata, "document", document, config)
   506  		}
   507  		completeMongoEvent(coll.tracer, event)
   508  	}
   509  	return response
   510  }
   511  
   512  func (coll *MongoCollectionWrapper) FindOneAndReplace(
   513  	ctx context.Context, filter interface{}, replacement interface{}, opts ...*mongoOptions.FindOneAndReplaceOptions,
   514  ) *mongo.SingleResult {
   515  	event := startMongoEvent("FindOneAndReplace", coll)
   516  	response := coll.collection.FindOneAndReplace(
   517  		ctx,
   518  		filter,
   519  		replacement,
   520  		opts...,
   521  	)
   522  	var document map[string]string
   523  	response.Decode(&document)
   524  
   525  	if err := response.Err(); err != nil {
   526  		logOperationFailure("Could not complete Decode SingleResult", err.Error())
   527  		coll.tracer.AddExceptionTypeAndMessage(
   528  			"mongo-driver",
   529  			err.Error(),
   530  		)
   531  	}
   532  
   533  	if event != nil {
   534  		if config := coll.tracer.GetConfig(); !config.MetadataOnly {
   535  			marshalToMetadata(event.Resource.Metadata, "filter", filter, config)
   536  			marshalToMetadata(event.Resource.Metadata, "replacement", replacement, config)
   537  			marshalToMetadata(event.Resource.Metadata, "document", document, config)
   538  		}
   539  		completeMongoEvent(coll.tracer, event)
   540  	}
   541  	return response
   542  
   543  }
   544  
   545  func (coll *MongoCollectionWrapper) FindOneAndUpdate(
   546  	ctx context.Context, filter interface{}, update interface{}, opts ...*mongoOptions.FindOneAndReplaceOptions,
   547  ) *mongo.SingleResult {
   548  	event := startMongoEvent("FindOneAndUpdate", coll)
   549  	response := coll.collection.FindOneAndReplace(
   550  		ctx,
   551  		filter,
   552  		update,
   553  		opts...,
   554  	)
   555  	var document map[string]string
   556  	response.Decode(&document)
   557  	if err := response.Err(); err != nil {
   558  		logOperationFailure("Could not complete Decode SingleResult", err.Error())
   559  		coll.tracer.AddExceptionTypeAndMessage(
   560  			"mongo-driver",
   561  			err.Error(),
   562  		)
   563  	}
   564  	if event != nil {
   565  		if config := coll.tracer.GetConfig(); !config.MetadataOnly {
   566  			marshalToMetadata(event.Resource.Metadata, "filter", filter, config)
   567  			marshalToMetadata(event.Resource.Metadata, "update", update, config)
   568  			marshalToMetadata(event.Resource.Metadata, "document", document, config)
   569  		}
   570  		completeMongoEvent(coll.tracer, event)
   571  	}
   572  	return response
   573  }
   574  
   575  func (coll *MongoCollectionWrapper) Drop(ctx context.Context) error {
   576  	event := startMongoEvent(currentFuncName(), coll)
   577  	err := coll.collection.Drop(
   578  		ctx,
   579  	)
   580  	if err != nil {
   581  		logOperationFailure(fmt.Sprintf("Could not complete %s", "Drop"), err.Error())
   582  		coll.tracer.AddExceptionTypeAndMessage(
   583  			"mongo-driver",
   584  			err.Error(),
   585  		)
   586  	}
   587  	if event != nil {
   588  		completeMongoEvent(coll.tracer, event)
   589  	}
   590  	return err
   591  }
   592  
   593  func (coll *MongoCollectionWrapper) Indexes() mongo.IndexView {
   594  	event := startMongoEvent("Indexes", coll)
   595  	indexView := coll.collection.Indexes()
   596  	if event != nil {
   597  		completeMongoEvent(coll.tracer, event)
   598  	}
   599  	return indexView
   600  }
   601  
   602  func (coll *MongoCollectionWrapper) Watch(
   603  	ctx context.Context, pipeline interface{}, opts ...*mongoOptions.ChangeStreamOptions,
   604  ) (*mongo.ChangeStream, error) {
   605  	event := startMongoEvent("Watch", coll)
   606  	response, err := coll.collection.Watch(
   607  		ctx,
   608  		pipeline,
   609  		opts...,
   610  	)
   611  	if err != nil {
   612  		logOperationFailure(fmt.Sprintf("Could not complete %s", "Watch"), err.Error())
   613  		coll.tracer.AddExceptionTypeAndMessage(
   614  			"mongo-driver",
   615  			err.Error(),
   616  		)
   617  	}
   618  	if event != nil {
   619  		completeMongoEvent(coll.tracer, event)
   620  	}
   621  	return response, err
   622  }