Skip to content

Event Metric Logging

Peter Chapman edited this page Jan 5, 2025 · 6 revisions

Overview

Note: This page is a for a Work-In-Progress PR (#2849).

The event metric logging system is implemented via Interceptors using an Aspect-Oriented Programming pattern. This pattern means that the class which wishes to log event metrics does not need to know the details on how to log, such as what class, syntax, or format, but only needs to declare the functions that need to be logged as having executed and the scope of the event metric. The scope can be thought of as a category or grouping.

In most cases, the user identifier and project identifier will be retrieved from the userId and projectId function parameters (if present), but if these are not present, the correpsonding arguments will need to be specified.

Restrictions

  • The class/interface that is to be intercepted must bepublic.
    • However, if the class or interface cannot be public:
      • Change the class or interface to internal
      • Mark the assembly as: [assembly: InternalsVisibleTo("DynamicProxyGenAssembly2")]
  • If you are using [LogEventMetric] on a function in a class (not an interface), that function will need to be virtual.

How to Log an Event

This tutorial assumes that your class has an interface.

  1. In your interface, adding the following using declarations:
using Autofac.Extras.DynamicProxy;
using SIL.XForge.EventMetrics;
  1. Add the following attribute to your interface:
[Intercept(typeof(EventMetricLogger))]
public interface I...
  1. Add the following attribute to the function you wish to log the event metric of, choosing the scope you wish to use:
[LogEventMetric(EventScope.Drafting)]
void MyMethod(string userId, string projectId);

If your function does not use the standard parameter names of userId or projectId, declare these in the attribute:

[LogEventMetric(EventScope.Settings, nameof(curUserId), nameof(targetProjectId))]
void MyMethod(string curUserId, string targetProjectId);

Or, if they are in an object, declare them as follows:

[LogEventMetric(EventScope.Sync, "syncConfig.UserId", "syncConfig.ProjectId")]
Task<string> SyncAsync(SyncConfig syncConfiguration);
  1. Add the mapping for your interface and the class that implements it to SFEventMetricsContainerBuilderExtensions.RegisterSFEventMetrics():
containerBuilder.RegisterEventMetrics<ISyncService, SyncService>();
  1. Add the name of the function being logged, and description of it to the TypeScript function getEventType() in EventMetricsLogComponent.ts.

  2. After running the application and executing the method that logs the event metric, check the event_metrics collection in MongoDB for your logged event metric.

Adding Scopes

Scopes are treated string values, and can be added as required. The name of the enum value will be its scope name in the database. These are defined in the enum EventScope in the SIL.XForge project.

Example Code

Using [LogEventMetric] in an interface:

[Intercept(typeof(EventMetricLogger))]
public interface IMyService
{
    [LogEventMetric(EventScope.Settings)]
    void ThisMethodWillBeLogged();

    void ThisMethodWillNot();

    [LogEventMetric(EventScope.Settings)]
    void ThisMethodUsesDefaultParameterNames(string userId, string projectId);

    [LogEventMetric(EventScope.Settings, nameof(curUserId), nameof(targetProjectId))]
    void ThisMethodUsesDifferentParameterNames(string curUserId, string targetProjectId);

    [LogEventMetric(EventScope.Sync, "syncConfig.UserId", "syncConfig.ProjectId")]
    void ThisMethodUsesAnObject(SyncConfig syncConfiguration);

    [LogEventMetric(EventScope.Settings, captureReturnValue: true)]
    string ThisWillCaptureTheReturnVAlue(string userId, string projectId);
}

Registering a class and interface for event metrics:

containerBuilder.RegisterEventMetrics<IMyService, MyService>();

Using [LogEventMetric] in a class:

[Intercept(typeof(EventMetricLogger))]
public class MyService
{
    [LogEventMetric(EventScope.Settings)]
    public virtual void ThisMethodWillBeLogged() => ...
}

Registering a class which does not have an interface for event metrics:

containerBuilder.RegisterEventMetrics<MyService>();

Further Reading

Clone this wiki locally