Create Logger for Microservices Powered By RedisSearch & RedisJSON
Tags: distributedsystems, aspnetcore, softwareengineering, redis
Published: 2022-09-15 12:32:39

---
title: Create Logger for Microservices Powered By RedisSearch & RedisJSON
published: true
date: 2022-09-15 12:19:49 UTC
tags: distributedsystems,aspnetcore,softwareengineering,redis
canonical_url: https://rajdeep-das.medium.com/create-logger-for-microservices-powered-by-redissearch-redisjson-5628aca71e91
---

#### A Lightweight Dot Net Realtime Message, Event, HTTP (Request & Response) and Exception Logger For Web (Trying to make centralised logger for Microservice and K8s environment)

![banner](https://cdn-images-1.medium.com/max/700/1*wPD6Ta4X7ZJYXlz622vxJg.png)

I’m searching for a logger and a simple UI to view my HTTP request & response logs in microservice environments. I found something called [_elastic-search_](https://www.elastic.co/), where all logs are stored & it gives a nice UI to view.

But for my simple APP & Low User base, Elastic search setup & operation cost are so high for my requirements. so I decided to build my simple logger, nothing fancy or complicated.

The idea is to build a simple **Middleware** that logs all the HTTP requests & responses. Then store the logs in DB for View Later. Create an **Extension Method** to register this middleware in HTTP Pipeline & Publish this middleware as [**Nuget**](https://www.nuget.org/) Package.

**My Requirements are**

1. I want a simple temporary log storage max 7–14 Days Logs.
2. Very Lightweight to set up, and operate and has low memory usage.
3. It just does two things record all HTTP request & response data, and exception logs for my microservices which are written in ASP.NET Core (.NET 6).
4. A Simple UI where I can search & view logs by service name, request methods, timestamp, etc filter.
5. I don’t want to use my primary application, DB, to store temporary logs.

**How I build**

When searching on the internet I found something called [**RedisSearch**](https://redis.io/docs/stack/search/) **.** _RediSearch is a Full-Text Search Engine for NoSQL Database._

> According to Redis Website, **RediSearch** is powerful indexing, querying, and full-text search engine for Redis, available on-premises and as a managed service in the cloud.

Everyone knows what is **Redis** (At least for those who are in the web development field for the last few years). Redis is a very popular cache but **Redis** also can be used as Primary Database, it supports JSON Documents like MongoDB (No-SQL Database). We can enable these features by installing **Redis JSON**  Module.

This is the perfect choice for my requirements because I want nice search capabilities, I want search data in the HTTP request & response body and I don’t want a strong schema because HTTP request and response bodies vary from service to service but at the same time I also want strong search functionality.

#### Let’s Get Started

1. Let’s set up Redis, we are going to use the Redis cloud for easy setup, and quickly get started with **RedisJSON** & **RedisFullText** Search Module.
2. **Redis Enterprise Cloud** provides performance, operational simplicity, data management, and security in the cloud. [https://redis.com/redis-enterprise-cloud/overview/](https://redis.com/redis-enterprise-cloud/overview/). Don’t worry it provides a free tier for quickly building & prototype your solution. You can choose your favorite cloud provider & region. I’m Going to choose AWS and AP-South-1.

![Redis Enterprise ](https://cdn-images-1.medium.com/max/1024/1*ZFt7QXB4nqY0cn7CYtNKBg.png)
_Redis Enterprise Cloud_

After creating Account & Choosing Your RedisStack Deployment, You will get a public endpoint.

![Redis Enterprise Cloud](https://cdn-images-1.medium.com/max/1024/1*yaHw9oaEw9JwtdaFFIasVA.png)
_Redis Public Endpoint_

We will use [**RedisInsight**](https://redis.com/redis-enterprise/redis-insight/) **.** A Redis GUI tool to connect to Redis cloud instance.RedisInsight enables the use of Redis data types including JSON and time series by providing a new user interface, a browser tool, a sophisticated CLI, bespoke data visualization, and built-in tutorials.

![Redisinsight](https://cdn-images-1.medium.com/max/1024/1*-Q5oLwLhKbAi0KVwy8uvHQ.png)
_Redisinsight_

**Redis Enterprise** enables you to create backups across all database shards quickly and consistently. It achieves quick auto-cluster recovery by rebuilding the cluster from the configuration file and using the same endpoints and database configurations.

Instant disaster recovery is achieved through Active-Active deployment, which allows reading and writing to each replica at any time and is backed up by an academically proven conflict-resolution mechanism.

**Quick Overview of Redis JSON & Get Started**

We can interact with Redis JSON documents using Redis CLI or Redis CLI available on RedisInsight GUI Tool.

To interact with Redis JSON we most often use JSON.GET & JSON.SET Commands from CLI

![Redis CLI](https://cdn-images-1.medium.com/max/1024/1*1v09vveG-mA1B8TyRgbJtQ.png)
_Redis Insight CLI_

According to Redis DOCS & Website Redis.JSON GET & SET Commands specification.

Redis JSON Supported Data Structure

- Scalar
- Objects (including nested objects)
- Arrays of JSON objects
- JSON nested objects

**JSON.GET**  
Syntax

```
JSON.GET key [INDENT indent] [NEWLINE newline] [SPACE space] [paths
[paths ...]]
```

Available in:  
Redis Stack / JSON 1.0.0

Time complexity:  
O(N) when the path is evaluated to a single value where N is the size of the value, O(N) when the path is evaluated to multiple values, where N is the size of the key

This command accepts multiple path arguments. If no path is given, it defaults to the value's root.

The following subcommands change the reply’s format (all are empty strings by default):

- INDENT sets the indentation string for nested levels
- NEWLINE sets the string that's printed at the end of each line
- SPACE sets the string that's put between a key and a value

![JSON.GET Result](https://cdn-images-1.medium.com/max/1024/1*tzpX6W7QJB229JoKtUMzhg.png)
_JSON.GET Result_

**JSON.SET**

```
JSON.SET key path value [NX | XX]
```

Available in: [Redis Stack](https://redis.io/docs/stack) / [JSON 1.0.0](https://redis.io/docs/stack/json)

Time complexity: O(M+N) when the path is evaluated to a single value where M is the size of the original value (if it exists) and N is the size of the new value, O(M+N) when the path is evaluated to multiple values where M is the size of the key and N is the size of the new value

![Redis Commands](https://cdn-images-1.medium.com/max/1024/1*fTDl59zZ35nhzmGFflMbfg.png)
_JSON.SET Command_

**How to get all keys in Redis JSON**

To list the keys in the Redis data store, use the **KEYS** command followed by a specific pattern. Redis will search the keys for all the keys matching the specified pattern. In our example, we can use an asterisk (\*) to match all the keys in the data store to get the keys.

![Redis Commands](https://cdn-images-1.medium.com/max/1024/1*MniWUvoNCaOECu6_T3gGxg.png)
_List Keys_

**To connect Redis from .NET Required Some sort of DB Driver & ORM.** [**StackExchange Redis**](https://stackexchange.github.io/StackExchange.Redis/) **is popular amongst .NET Developers to connect Redis instances. But for easy use of Redis search & Redis JSON features, we will use** [**Redis OM**](https://github.com/redis/redis-om-dotnet). NET.

**Why Redis OM?**

Redis OM provides high-level abstractions for using Redis in .NET, making it easy to model and query your Redis domain objects.

- Declarative object mapping for Redis objects
- Declarative secondary-index generation
- Fluent APIs for querying Redis
- Fluent APIs for performing Redis aggregations

Let’s try to use RedisOM in Our Dotnet Application. It’s simple to use RedisJSON with ASP.NET.

1. **Create the Logs model**. Here you will notice that the fields are decorated with the Indexed attribute. These attributes ( **Searchable** and **Indexed** ) tell Redis OM that you want to be able to use those fields in queries when querying your documents in Redis Stack.

{% gist https://gist.github.com/Rajdeep-Das/6e739da5194dcd860cdfb2789c241342.js %}

[Document(StorageType = StorageType.Json, Prefixes = new []{“WLog”})] Indicates that the data type that Redis OM will use to store the document in Redis is JSON and that the prefix for the keys for the WLog class will be WLog.

The Id property is marked as a RedisIdField. This denotes the field as one that will be used to generate the document’s key name when it’s stored in Redis. e,g Id:”01GC92PD10R0DFVST9CV6Q7SBS”

To insert your object into Redis, use Set on the RedisConnection or Insert in the RedisCollection. Redis OM will automatically set the id for you and you will be able to access it in the object. If the Id type is a string and no IdGenerationStrategy is explicitly overridden on the thing, the ULID will bind to the string.

![Redis JSON](https://cdn-images-1.medium.com/max/1024/1*OXaLMHMrv5yfr768bqWCJg.png)
_WLog.cs to RedisJSON_

After you’ve finished building the model, you’ll need to construct the _index_ in Redis. The best method to handle this is to spin the index creation out into a Hosted Service that will execute when the app is launched. Make a directory called ‘HostedServices’ and add _IndexCreationService.cs_ to it. Add the following to that file to construct the index on startup.

{% gist https://gist.github.com/Rajdeep-Das/7486fd2858fd58048c9ae38162d78b76 %}

Redis OM handles connections to Redis and offers the classes you may use to communicate with Redis via the RedisConnectionProvider class. To utilize it, just inject a RedisConnectionProvider object into your application.

Let’s Create a Helper Class That will contain DB Access Logic. One Of the great features I like about Redis OM, we can easily query using LINQ expression. I used Object Mapper to Convert Domain Model to Redis DB Models. In the future, if we want to support other DB, we can easily do that.

```
public IEnumerable<WatchLog> FilterByMethod(string method){ var logs = _redisWatchLog.Where(x => x.Method == method).ToList(); List<WatchLog> logList = CustomMapper.Mapper.Map<List<WLog>, List<WatchLog>>(logs);            
return logList;                        
}
```

{% gist https://gist.github.com/Rajdeep-Das/97e00b194edb4e7db4567cbc1dc5900d %}

**Import Note About Redis OM .NET**

Redis OM may be used in conjunction with normal Redis for object mapping and retrieving objects by ID. Redis OM is dependent on the Redis Stack platform for more sophisticated functionality like indexing, querying, and aggregation. The Redis Stack platform is a collection of modules that expand Redis.

Why is this significant?  
You can still use Redis OM to develop declarative models supported by Redis if you don’t have Redis Stack.

We’ll store your model data as Hashes in Redis, and you’ll be able to retrieve models using their main keys.

So, what won’t operate in the absence of Redis Stack?

1. Models cannot be nested inside each other.
2. You will not be able to discover objects using our expressive queries; you will only be able to query by primary key.

As We are Building A Logger Libray as Middleware, the Injection code is written in Service Collection Extension Method.

{% gist https://gist.github.com/Rajdeep-Das/e1ffe4169f5db44c81cd6f34f43ef1f5.js %}

We Register the RedisConnection provider as a singleton.

```
services.AddSingleton(new RedisConnectionProvider(WatchLogExternalDbConfig.ConnectionString));
```

This will retrieve your connection string from the configuration and initialize the provider. The provider is now accessible for usage in your controllers/services.

Now we will create the leading **Middleware** , That will intercept the HTTP Request & Response and save it to DB.

{% gist https://gist.github.com/Rajdeep-Das/726ccfce6292ee4d78bd1a1f02fda2c4 %}

Next, To Get Logs in UI, We have to create an API, from which we will fetch logs. Let’s Create an API Controller That looks like the one below.

This is a very basic simple API Idea, We will later extend it with robust Redis **FullTextSearch** Methods, RealTime Streaming, etc fancy things. Keep in mind this is a Proof of concept type of Project, a very early stage in development.

{% gist https://gist.github.com/Rajdeep-Das/b57f7053a1a1d6e4372f5e3146c9c074 %}

Now we can use This Logger in the dotnet Web API project.

{% gist https://gist.github.com/Rajdeep-Das/43b6602bf586f4bcdd004dae9831fba7 %}

```
// Configure DB Connection In API Service
builder.Services.AddWatchLoggerServices(opt =>{ opt.SetExternalDbConnString = builder.Configuration["RedisConnectionString"];});
```

Now Register WatchLogger In Middleware

```
// Custom Logger Middleware
app.UseWatchLogger();
```

Next, We will Build A Sample UI In Angular or a Similar Framework, That will somewhat look like this.

![WatchLogger UI](https://cdn-images-1.medium.com/max/1024/1*6umPxAaEDLlrgzdx7SUT6w.png)
_WatchLogger UI_

For UI, I am writing a separate second Part. Where we will extend Redis Stack Features, Fully Use RedisFullText Search, and RedisStream also adds Exception Logger Middleware, WebSocket, SignalR, etc.

Don’t forget to try Redis, and we’ll continue the series as a Redis Stack. In forthcoming blogs, we will look at Redis Search, Redis Stream, pub-sub, and many more topics. To learn more about Redis, go to [https://redis.io/](https://redis.io/).

Early Stage Project Available On Github: [WatchLogger](https://github.com/Rajdeep-Das/WatchLogger)

[GitHub - Rajdeep-Das/WatchLogger: A Lightweight Dot Net Realtime Message, Event, HTTP (Request & Response) and Exception Logger For Web (Trying to make centralized logger for Microservices and K8s)](https://github.com/Rajdeep-Das/WatchLogger)

_This post is in collaboration with Redis._

**Learn more about Redis Cool 😎 Features:**

- [Try Redis Cloud for free](https://redis.info/3NBGJRT)
- [Watch this video on the benefits of Redis Cloud over other Redis providers](https://redis.info/3Ga9YII)
- [Redis Developer Hub — tools, guides, and tutorials about Redis](https://redis.info/3LC4GqB)
- [RedisInsight Desktop GUI](https://redis.info/3wMR7PR)