Best way to include global event logger for tenant context

I currently have the following defined in Startup

RegisterTypedRequestFilter<IForEnvironment>((req, res, requestDto) =>
{
    Guid.TryParse(req.Headers["User"], out Guid user);
    Guid.TryParse(req.Headers["Tenant"], out Guid tenant);
    requestDto.Tenant = tenant;
    requestDto.User = user;
    req.Items[Keywords.DbInfo] = new ConnectionInfo() { ConnectionString = GetEnvironmentConnString(dbFactory, requestDto.Environment) };                
    using (var db = dbFactory.Open())
    {
        db.Insert(new Event()
        {
            Name = requestDto.GetType().Name,
            Tenant = tenant,
            Environment = requestDto.Environment,
            User = user
        });
    }
});

I did this so I don’t have to put this code in every service method. However, the db.Insert part is what I’m wondering if there is a better way. I was trying to figure out how to get the IDbConnection (Service.Db) of the IRequest because I figure this is a bit cleaner:

RegisterTypedRequestFilter<IForEnvironment>((req, res, requestDto) =>
{
    Guid.TryParse(req.Headers["User"], out Guid user);
    Guid.TryParse(req.Headers["Tenant"], out Guid tenant);
    requestDto.Tenant = tenant;
    requestDto.User = user;
    req.Items[Keywords.DbInfo] = new ConnectionInfo() { ConnectionString = GetEnvironmentConnString(dbFactory, requestDto.Environment) };                
        Db.Insert(new Event()
        {
            Name = requestDto.GetType().Name,
            Tenant = tenant,
            Environment = requestDto.Environment,
            User = user
        });
});

But Service.Db doesn’t seem to be available from here. Any advice on how to do this a better way would be appreciated.

The request filters are executed before the Service is created to execute the Service. Your Request Filter is just opening the default connection directly from the dbFactory.

Here’s Service implementation that resolves its Db:

Which you can do in your Request Filters with:

using (var db = GetDbConnection(req))
{
  //...
}

Ok that’s cleaner.

Related question: Is there some built in ServiceStack way of enabling a global event logger to log all service requests (by default) along with request parameters, authenticated user, etc to something like Serilog?

You can use the Request Logger to log requests, by default it logs in Memory, but there’s also CSV, Redis or Rollbar request loggers available.

Beautiful!

Great stuff

I added the RequestLogsFeature but it’s giving the following error:

{
    "results": [],
    "responseStatus": {
        "errorCode": "Invalid Role",
        "message": "Invalid Role",
        "errors": []
    }
}

Is there anyway to use this without any authentication just for testing purposes?

What exactly are you accessing that’s giving you that error?

Using Postman to call GET http://{{host}}/requestlogs

The Roles aren’t validated in DebugMode, i.e. what should be used during Development.

You can control which roles can be used to view the /requestlogs API with RequiredRoles, e.g. you can remove the auth validation with:

Plugins.Add(new RequestLogsFeature {
    RequiredRoles = new string[0],
});

Ya, I saw that in the source code, but I’m definitely in DebugMode. I’m using self hosting Kestrel, not IIS Express, so maybe that’s it? The console window for self host even says:

Hosting environment: Development

So, since RequestLogService is enforcing the roles check, I’m assuming that it thinks:

if (!HostContext.DebugMode)
{
          RequiredRoleAttribute.AssertRequiredRoles(Request, RequestLogger.RequiredRoles);
}

Is True.

In any event, your suggestion to add an empty array to RequiredRoles did the trick.

Thanks.

DebugMode is set in your HostConfig, e.g here’s a couple of common ways of populating it:

SetConfig(new HostConfig {
    DebugMode = AppSettings.Get(nameof(HostConfig.DebugMode), false),
//    DebugMode = HostingEnvironment.IsDevelopment(),
});

According to the docs:

ServiceStack allows additional debug information when in DebugMode , which is automatically set by default in Debug builds…:

Which is what I’m doing. I’m running the app in Visual Studio with Debug → Start Debugging. Isn’t that a “debug build”?

It’s a heuristic that looks for the [Debuggable] Assembly attribute which you can check with:

typeof(AppHost).IsDebugBuild();

If Config.DebugMode isn’t true in your AppHost.Configure(), explicitly set it.

Thanks. This built in request logging feature is great!

1 Like

Any chance you have an AWS Kinesis Firehose plugin for this?

No if it’s not documented it doesn’t exist, you can submit any feature requests to User Voice.

Turns out a better approach to this might be to just monitor the CSV file and stream that to Kinesis with an external process.