0
votes

I am trying to write a custom appender for Log4net by referring the article http://korrozia.blogspot.in/2016/11/how-to-store-log4net-messages-to-azure.html. Documents are getting created in Azure Doc DB, but the log message is not appearing in document. Below is my custom appender code

public class DocumentDbAppender: AppenderSkeleton
{
    private DocumentClient client;

    public string DatabaseId
    {
        get;
        set;
    }

    public string CollectionId
    {
        get;
        set;
    }

    public string EndpointUrl
    {
        get;
        set;
    }

    public string AuthKey
    {
        get;
        set;
    }

    protected override void Append(LoggingEvent loggingEvent)
    {
        try
        {
            using (client = new DocumentClient(new Uri(EndpointUrl), AuthKey))
            {
                var database = RetrieveOrCreateDatabaseAsync(DatabaseId).Result;

                var collection = RetrieveOrCreateCollectionAsync(database.SelfLink, 
                    CollectionId).Result;

                var document = CreateDocumentAsync(client, collection.SelfLink, loggingEvent).Result;
            }
        }
        catch (DocumentClientException de)
        {
            Exception baseException = de.GetBaseException();
            Debug.Print("Status code {0} error occurred: {1}, Message: {2}", de.StatusCode, 
                de.Message, baseException.Message);
        }
        catch (Exception e)
        {
            Exception baseException = e.GetBaseException();
            Debug.Print("Error: {0}, Message: {1}", e.Message, baseException.Message);
        }
    }

    private async Task<Database> RetrieveOrCreateDatabaseAsync(string id)
    {
        // Try to retrieve the database (Microsoft.Azure.Documents.Database) whose Id is equal to databaseId            
        var database = client.CreateDatabaseQuery().Where(db => db.Id == DatabaseId).
            AsEnumerable().FirstOrDefault();

        // If the previous call didn't return a Database, it is necessary to create it
        if (database == null)
        {
            database = await client.CreateDatabaseAsync(new Database { Id = DatabaseId }).ConfigureAwait(false);
            Debug.Print("Created Database: id - {0} and selfLink - {1}", database.Id, database.SelfLink);
        }

        return database;
    }

    private async Task<DocumentCollection> RetrieveOrCreateCollectionAsync(string databaseSelfLink, 
        string id)
    {
        // Try to retrieve the collection (Microsoft.Azure.Documents.DocumentCollection) whose 
        // Id is equal to collectionId
        var collection = client.CreateDocumentCollectionQuery(databaseSelfLink).
            Where(c => c.Id == id).ToArray().FirstOrDefault();

        // If the previous call didn't return a Collection, it is necessary to create it
        if (collection == null)
        {
            collection = await client.CreateDocumentCollectionAsync(databaseSelfLink, 
                new DocumentCollection { Id = id }).ConfigureAwait(false);
        }

        return collection;
    }

    private async Task<Document> CreateDocumentAsync(DocumentClient client, 
        string collectionSelfLink, LoggingEvent loggingEvent)
    {

        var doc = await client.CreateDocumentAsync(collectionSelfLink,
            loggingEvent).ConfigureAwait(false);

        return doc;
    }

}

My Web.config looks like below

<log4net>
<!--This is for local testing. Comment out this appender when moved to azure cloud-->
<!--<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
  <file value=".\\Logs\\WebApi.log"/>
  <appendToFile value="true"/>
  <rollingStyle value="Size"/>
  <maxSizeRollBackups value="10"/>
  <maximumFileSize value="10MB"/>
  <staticLogFileName value="true"/>
  <layout type="log4net.Layout.PatternLayout">
    <conversionPattern value="%-5p %d %5rms %-22.22c{1} %-18.25M - %m%n"/>
  </layout>
</appender>-->

  <appender name="DocumentDbAppender"
    type="MyApp.Infra.Logger.DocumentDbAppender, MyApp.Infra.Logger">
    <DatabaseId>Diagnostics</DatabaseId>
    <CollectionId>Logs</CollectionId>
    <EndpointUrl>https://mydb.documents.azure.com:443/</EndpointUrl>
    <AuthKey>UB0w==</AuthKey>
    <layout type="log4net.Layout.PatternLayout">
      <conversionPattern value="%-5p %d %5rms %-22.22c{1} %-18.25M - %m%n"/>
      <!--<conversionPattern value="%m"/>-->
    </layout>
</appender>

I am creating logger instance as below

  log4net.Util.LogLog.InternalDebugging = true;

  log4net.Config.XmlConfigurator.Configure();
  log4netLogger = log4net.LogManager.GetLogger(
                System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

If I simply writes a info message, it looks like below in Document DB

{
  "$type": "log4net.Core.LoggingEvent, log4net",
  "LoggerName": MyApp.Infra.Logger.Log4NetLogger",
  "Level": {
    "$type": "log4net.Core.Level, log4net",
    "Name": "INFO",
    "Value": 40000,
    "DisplayName": "INFO"
  },
  "Message": null,
  "ThreadName": null,
  "TimeStamp": "2017-03-20T15:57:17.7133358+05:30",
  "LocationInfo": null,
  "UserName": null,
  "ExceptionString": null,
  "Properties": null,
  "Domain": null,
  "Identity": null,
  "id": "23071629-d896-4812-9a87-89871d969780"
}

Please note that Message is null. I am not sure why it is happening. If I use a Rolling File Appender, I am able to get the message without any issue.

1
FYI - not directly related to your question, but all your code about creating or getting databases and collections is quite obsolete (that's from very old tutorials). You should look at more current examples, since none of that code is needed anymore.David Makogon

1 Answers

0
votes

From the link that you provided, we could find it overrides Append method and create a document for LoggingEvent object by using the CreateDocumentAsync method in Append method. Please try to check if Exception object ex is null when you write info message.

LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType).Info("info mes", ex);

Besides, please set breakpoint inside Append(LoggingEvent loggingEvent) method to watch the properties of loggingEvent before you call CreateDocumentAsync method to create the document.