Best way to log an event


#1

Hi Guys,
Love your work, I think we will host our own server using your server code for security reasons. But how can we give you attribution?
However what is the best way just to log an event with CodeRR just like a verbose info message in other logging frameworks.

Best Regards,
Alistair


#2

Hello,

codeRR isn’t designed to be able to send messages. However, if you have messages that indicates errors, you can just create your own exception and then sent it:

try
{
    throw new InvalidOperationException("This is the message");
}
catch (Exception ex)
{
    Err.Report(ex, new { ErrTags = "info" });
}

In the next version, you can filter the search result using tags. Thus you can get a list of all messages and the number of times that they have been triggered.

Do note, if you are using messages for diagnostics purposes, the cost of doing the above is too high (throwing exceptions). In that case I would look at the ErrorReportDTO and send that message directly Err.SendReport(dto).

For the Community Server, you can buy a support subscription. Email support with next business day response and a higher chance of getting features implemented.

Our OnPremise server is being released in April. Better team management, integration with TFS and Active Directory support.


#3

Great thanks heaps. I will use this.
Do note, if you are using messages for diagnostics purposes, the cost of
doing the above is too high (throwing exceptions). In that case I would
look at the ErrorReportDTO and send that message directly
Err.SendReport(dto).

However I was not able to get the creating the applications to work. Are
there any recent bug fixes for this?

I will see if I can get clients to use your OnPremise solution in the
future!!

Best Regards,
Alistair


#4

Which version are you using? What error do you get?


#5

the latest download, the .net version, is there a core version?


#6

No. Just a MVC5 version of the server.

Mind doing a skype session and show me your server configuration? It allows me to quickly see what’s wrong. My email+skype is jonas@coderrapp.com


#7

Thanks mate but I only see
ErrorReportDTO log = new ErrorReportDTO() // But ErrorReportDTO is private
Err.UploadReport(log);


#8

ErrorReportDTO is now protected so I guess I can derive from that.
Or I can create something like this?

var collectionDto = new ContextCollectionDTO(“MyName”, new Dictionary<string, string> {{“Key”, “Val”}});
var report = new ErrorReportDTO(“aaa”, new ExceptionDTO(new Exception()), new[] {collectionDto});


#9

Have got the some request from more users. I’ll create an alternative for reporting errors that aren’t exceptions. Hang on a day.


#10

Awesome mate! maybe keep the DTO to give the context but take the exception out?
And will we search for these events in the same way as for the exceptions?


#11

they will look like any other error (including a stack trace), but a tag will be added so that they are searchable.

do you have a suggestion for the tag name? Maybe logical-error?

Api suggestion:

Err.ReportLogicError("User should have had a default id", user);

i.e. using a string instead of an exception and second parameter is context data or context collections like for Err.Report.


#12

Awesome again mate.

second parameter is context data OR context collections like for Err.Report.

Is bang on mate


#13

#14

Mate but I would just like to log an event. i.e without it being exception

So with the .net core Core event logging that uses CommonLogging.
I created a provider
So these logs can go to the coderr server.

_logger.LogInformation(LoggingEvents.ReStart, "Restart starting {now}", now);

And for different levels using the .net
_logger.LogInWarning(LoggingEvents.ReStart, "Restart starting {now}", now);

using Coderr.Client;
using Coderr.Client.Contracts;
using Coderr.Client.Reporters;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;

namespace Transport.CTABS.Web.Startup
{
   public class CodeRRLogger : ILogger
   {
      private readonly string _name;
      private readonly CodeRRLoggerConfiguration _config;

      public CodeRRLogger(string name, CodeRRLoggerConfiguration config)
      {
         _name = name;
         _config = config;
      }

      public IDisposable BeginScope<TState>(TState state)
      {
         return null;
      }

      public bool IsEnabled(LogLevel logLevel)
      {
         return logLevel == _config.LogLevel;
      }

      public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
      {
         if (!IsEnabled(logLevel))
         {
            return;
         }

         if (_config.EventId == 0 || _config.EventId == eventId.Id)
         {
            //var color = Console.ForegroundColor;
            //Console.ForegroundColor = _config.Color;
            //Console.WriteLine($"{logLevel.ToString()} - {eventId.Id} - {_name} - {formatter(state, exception)}");
            //Console.ForegroundColor = color;
         }
         //var ex = new Exception();
         //ex.Data["ErrCollections"] = "MEX";

         //var sut = new ErrorReporterContext(this, ex);
         //Err.ReportLogicError(state.ToString());
         ReportEvent(state.ToString());
      }

      public void ReportEvent(string errorMessage, object contextData = null, string errorId = null)
      {
         if (errorMessage == null) throw new ArgumentNullException(nameof(errorMessage));

         var collections = new List<ContextCollectionDTO>();
         if (contextData != null) AppendCustomContextData(contextData, collections);
         collections.AddTag("logical-event"); //event

         //var xx = new StackFrame(3).GetMethod();
         //var yy = new StackFrame(2).GetMethod();
         var method = new StackFrame(1).GetMethod();

         //StackTrace st = new StackTrace(new StackFrame(1));
         //Console.WriteLine(" Stack trace for next level frame: {0}",
         //   st.ToString());

         //var x = st.ToString();
         //Console.WriteLine(" Stack frame for next level: ");
         //Console.WriteLine("   {0}", st.GetFrame(0).ToString());

         //var y = st.GetFrame(0);

         //Console.WriteLine(" Line Number: {0}",
         //   st.GetFrame(0).GetFileLineNumber().ToString());

         var callerName = method.DeclaringType?.FullName + ":" + method.Name;
         var trace = new StackTrace().ToString();
         var pos = trace.IndexOf("\r\n", StringComparison.Ordinal);
         if (pos == -1)
         {
            pos = trace.IndexOf("\n", StringComparison.Ordinal);
            if (pos != -1) trace = trace.Remove(0, pos + 1);
         }
         else
         {
            trace = trace.Remove(0, pos + 2);
         }

         var logicException =
             new LogicalErrorException(errorMessage, trace)
             {
                ErrorHashSource = errorId ?? $"{errorMessage}:{callerName}"
             };

         Err.Report(logicException, collections);
      }

      private void AppendCustomContextData(object contextData, IList<ContextCollectionDTO> contextInfo)
      {
         if (contextData is IEnumerable<ContextCollectionDTO> dtos)
         {
            var arr = dtos;
            foreach (var dto in arr)
               contextInfo.Add(dto);
         }
         else
         {
            var col = contextData.ToContextCollection();
            contextInfo.Add(col);
         }
      }


   }
}

With

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Transport.CTABS.Configuration;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Transport.CTABS.Web.Startup
{
   public class CodeRRLoggerConfiguration
   {
      private readonly IConfigurationRoot _appConfiguration;
      private LogLevel _logLevel;

      public CodeRRLoggerConfiguration(IHostingEnvironment env)
      {
         _appConfiguration = env.GetAppConfiguration();
         _logLevel = _appConfiguration.GetValue<LogLevel>("AppSettings:LogLevel");
      }

      public LogLevel LogLevel { get { return _logLevel; } set { _logLevel = value; } }
      public int EventId { get; set; } = 0;
      //public ConsoleColor Color { get; set; } = ConsoleColor.Yellow;
   }

}

and Provider is

using Microsoft.Extensions.Logging;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace Transport.CTABS.Web.Startup
{
   public class CodeRRLoggerProvider : ILoggerProvider
   {
      private readonly CodeRRLoggerConfiguration _config;
      private readonly ConcurrentDictionary<string, CodeRRLogger> _loggers = new ConcurrentDictionary<string, CodeRRLogger>();

      public CodeRRLoggerProvider(CodeRRLoggerConfiguration config)
      {
         _config = config;
      }

      public ILogger CreateLogger(string categoryName)
      {
         return _loggers.GetOrAdd(categoryName, name => new CodeRRLogger(name, _config));
      }

      public void Dispose()
      {
         _loggers.Clear();
      }
   }
}

So in Startup.Configure you just call

 loggerFactory.AddProvider(new CodeRRLoggerProvider(new CodeRRLoggerConfiguration(env)));