private void TrackMetric(LogLevel logLevel, EventId eventId, string message, MetricLog metric)
        {
            var telemetry = new MetricTelemetry(metric.Name, metric.Value);

            telemetry.Count             = metric.Count;
            telemetry.Min               = metric.Min;
            telemetry.Max               = metric.Max;
            telemetry.StandardDeviation = metric.StandardDeviation;
            if (metric.Properties != null)
            {
                foreach (var item in metric.Properties)
                {
                    telemetry.Properties[item.Key] = item.Value?.ToString();
                }
            }
            telemetry.Properties["logger"]    = categoryName;
            telemetry.Properties["eventName"] = eventId.Name;
            telemetry.Properties["eventId"]   = eventId.Id.ToString();
            telemetry.Properties["remark"]    = metric.Remark;
            telemetryClient.TrackMetric(telemetry);
        }
        public void Log <TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func <TState, Exception, string> formatter)
        {
            if (!IsEnabled(logLevel))
            {
                return;
            }

            if (formatter == null)
            {
                formatter = (TState s, Exception e) =>
                            e == null
                    ? $"{s}"
                    : $"{s}\n{e}";
            }

            var message = formatter(state, exception) ?? "";

            if (exception == null)
            {
                if (state is IEnumerable <KeyValuePair <string, object> > )
                {
                    var properties = state as IEnumerable <KeyValuePair <string, object> >;
                    var logType    = properties
                                     .Where(item => item.Key.Equals("LogType", StringComparison.OrdinalIgnoreCase))
                                     .Select(item => item.Value?.ToString() ?? "")
                                     .FirstOrDefault() ?? "";
                    if (logType.Equals(nameof(MetricLog), StringComparison.OrdinalIgnoreCase))
                    {
                        var metric = MetricLog.Create(properties);
                        if (metric == null)
                        {
                            TrackTrace(logLevel, eventId, message, properties);
                        }
                        else
                        {
                            TrackMetric(logLevel, eventId, message, metric);
                        }
                    }
                    else if (logType.Equals(nameof(EventLog), StringComparison.OrdinalIgnoreCase))
                    {
                        var @event = EventLog.Create(properties);
                        if (@event == null)
                        {
                            TrackTrace(logLevel, eventId, message, properties);
                        }
                        else
                        {
                            TrackEvent(logLevel, eventId, message, @event);
                        }
                    }
                    else
                    {
                        TrackTrace(logLevel, eventId, message, properties);
                    }
                }
                else if (state is EventLog)
                {
                    TrackEvent(logLevel, eventId, message, state as EventLog);
                }
                else if (state is MetricLog)
                {
                    TrackMetric(logLevel, eventId, message, state as MetricLog);
                }
                else
                {
                    TrackTrace(logLevel, eventId, message, Enumerable.Empty <KeyValuePair <string, object> >());
                }
            }
            else
            {
                TrackException(eventId, message, exception, Enumerable.Empty <KeyValuePair <string, object> >());
            }
        }
        /// <summary>
        /// Create a new MetricLog from given properties.
        /// </summary>
        /// <param name="properties">Key-value properties.</param>
        /// <remarks>
        /// Name and Value are mandatory properties.
        /// </remarks>
        /// <returns>Returns a new MetricLog if given properties have the Name and Value properties, or null otherwise.</returns>
        public static MetricLog Create(IEnumerable <KeyValuePair <string, object> > properties)
        {
            if (properties == null)
            {
                return(null);
            }
            if (false == properties.Any(item =>
                                        item.Key.Equals("LogType", StringComparison.OrdinalIgnoreCase) &&
                                        (item.Value?.ToString() ?? "").Equals(nameof(MetricLog), StringComparison.OrdinalIgnoreCase)))
            {
                return(null);
            }
            var metric = new MetricLog("No name", 0);
            var dic    = properties.ToDictionary(item => item.Key, item => item.Value, StringComparer.OrdinalIgnoreCase);

            foreach (var item in dic.Where(item =>
                                           false == new string[]
            {
                nameof(Name),
                nameof(StandardDeviation),
                nameof(Count),
                nameof(Value),
                nameof(Min),
                nameof(Max),
                nameof(Remark),
            }.Contains(item.Key, StringComparer.OrdinalIgnoreCase)))
            {
                metric.Properties[item.Key] = item.Value;
            }
            if (dic.ContainsKey(nameof(Name)))
            {
                metric.Name = dic[nameof(Name)]?.ToString();
            }
            else
            {
                return(null);
            }
            if (dic.ContainsKey(nameof(Value)))
            {
                metric.Value = double.Parse(dic[nameof(Value)]?.ToString() ?? "0");
            }
            else
            {
                return(null);
            }
            if (dic.ContainsKey(nameof(StandardDeviation)))
            {
                var standardDeviation = dic[nameof(StandardDeviation)];
                if (standardDeviation != null)
                {
                    double value = 0.0;
                    if (double.TryParse(standardDeviation.ToString(), out value))
                    {
                        metric.StandardDeviation = value;
                    }
                }
            }
            if (dic.ContainsKey(nameof(Count)))
            {
                var count = dic[nameof(Count)];
                if (count != null)
                {
                    int value = 0;
                    if (int.TryParse(count.ToString(), out value))
                    {
                        metric.Count = value;
                    }
                }
            }
            if (dic.ContainsKey(nameof(Min)))
            {
                var min = dic[nameof(Min)];
                if (min != null)
                {
                    double value = 0;
                    if (double.TryParse(min.ToString(), out value))
                    {
                        metric.Min = value;
                    }
                }
            }
            if (dic.ContainsKey(nameof(Max)))
            {
                var max = dic[nameof(Max)];
                if (max != null)
                {
                    double value = 0;
                    if (double.TryParse(max.ToString(), out value))
                    {
                        metric.Max = value;
                    }
                }
            }
            if (dic.ContainsKey(nameof(Remark)))
            {
                metric.Remark = dic[nameof(Remark)]?.ToString();
            }
            return(metric);
        }