Archive

Archive for June, 2014

Storing Sitecore log events in MongoDB

17/06/2014 4 comments

After Sitecore announced the new Sitecore Experience Database (former DMS), which also included a move from a SQL to a NoSQL database, I thought it was about time to give MongoDB a closer look. After reading a lot of related blog post, seeing educational videos and more, I build few demo apps using the MongoDB. But what Ireally wanted to do, was to use Mongo along with Sitecore, and yes i know there exist MongoDB data providers but i really wanted to start  with something more simple, or at least for me as an MongoDB rookie.

So what better then trying to store Sitecore’s Log events in a Mongo database.

First we need to derive from the log4net implementation found in Sitecore.Logging.dll, to build functionality to catch log entries.


public class MongoLogger : AppenderSkeleton
{
  public string ConnectionString { get; set; }
  public string CollectionName { get; set; }
  private MongoRepository _mongoRepository;

  public MongoRepository MongoRepository
  {
   get
     {
      if (_mongoRepository == null)
      {
        _mongoRepository = new MongoRepository(ConnectionString, CollectionName);
      }
      return _mongoRepository;
     }
  }

  protected override void Append(LoggingEvent loggingEvent)
  {
    MongoRepository.Put(loggingEvent);
  }
}

 

As it turns out the LogEvents is easily serialized and deserialized by the Mongo C# driver. I’ve used the offcial MongoCSharprDRiver for this project.
As seen in code above the logger talks with a Data Repository.  So next is the MongoDB repository that handles all calls to the Database.


public class MongoRepository
{
private readonly string _connectionString;
private readonly string _collectionName;

public MongoRepository(string connectionString, string collectionName)
{
_connectionString = connectionString;
_collectionName = collectionName;
UnMapAllMongoIdField();
}

public void UnMapAllMongoIdField()
{
//Only need once per instance

BsonClassMap.RegisterClassMap<T>(cm =>

{
cm.AutoMap();
cm.SetIgnoreExtraElements(true);
});
}

public virtual void Put(LoggingEvent logEntry)
{
Collection.Insert(logEntry);
}

public virtual LoggingEvent GetSingle(Func<LoggingEvent, bool> filter)
{
return Get(filter).FirstOrDefault();
}

public virtual IEnumerable<LoggingEvent> Get(Func<LoggingEvent, bool> filter)
{
return Collection.AsQueryable<LoggingEvent>().Where(filter);
}

private MongoUrl _mongoUrl;
private MongoUrl MongoUrl
{
get { return _mongoUrl ?? (_mongoUrl = MongoUrl.Create(_connectionString)); }
}

private MongoClient _client;
private MongoClient Client
{
get { return _client ?? (_client = new MongoClient(MongoUrl)); }
}

private MongoServer _server;
private MongoServer Server
{
get { return _server ?? (_server = Client.GetServer()); }
}

private MongoDatabase _database;
private MongoDatabase Database
{
get { return _database ?? (_database = Server.GetDatabase(MongoUrl.DatabaseName)); }
}

private MongoCollection<BsonDocument> _collection;
private MongoCollection<BsonDocument> Collection
{
get { return _collection ?? (_collection = Database.GetCollection(_collectionName)); }
}
}

You could off course make the repository more generic but for simplicity it will only handle LogEvents.

Next we need to change the default Logger to use our new Mongo Logger. For this post I will only change the default Logger but you could if you wanted change all the Logger Appenders (SearchLogger, WebDavLogger, CrawlingLoggeror the PublishLogger). In the web.config under the log4net section add a the new log appender we created above like shown below. You can off course change DB-name and collection name as you like.


<appender name="MongoDBAppender" type="SitecoreMongoDBAppender.MongoAppender, SitecoreMongoDBAppender">
<connectionstring value="mongodb://localhost:27017/Logs" />
<collectionname value="log" />
</appender>

and also update the root section to point to long appender


 <root>
 <priority value="INFO" />
 <appender-ref ref="MongoDBAppender" />
 </root>

if you start up Sitecore now you should get entries into the MongoDB

17-06-2014 09-04-32

You could replace all the log appender with the  new MongoLogger . You can if  you want use the different collections or just store each logevent in one big collection. Maybee next one should build a Sitecore Speak application to show the relevant log information, inside Sitecore but that is left for the reader :). The repository allready have Get method, where you can parse in your own linq queries.

 

Advertisements
Categories: .Net, C#, MongoDB, Sitecore Tags: , ,