<commit_before>﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Metrics.Endpoints;
using Metrics.Logging;
using Metrics.MetricData;
using Metrics.Reports;

namespace Metrics
{
    public sealed class MetricsConfig : IDisposable, Utils.IHideObjectMembers
    {
        private static readonly ILog log = LogProvider.GetCurrentClassLogger();

        public static readonly bool GloballyDisabledMetrics = ReadGloballyDisableMetricsSetting();

        private readonly MetricsContext context;
        private readonly MetricsReports reports;

        private Func<HealthStatus> healthStatus;

        private readonly CancellationTokenSource httpEndpointCancellation = new CancellationTokenSource();

        private readonly Dictionary<string, Task<MetricsHttpListener>> httpEndpoints = new Dictionary<string, Task<MetricsHttpListener>>();

        private SamplingType defaultSamplingType = SamplingType.ExponentiallyDecaying;

        private bool isDisabled = MetricsConfig.GloballyDisabledMetrics;

        /// <summary>
        /// Gets the currently configured default sampling type to use for histogram sampling.
        /// </summary>
        public SamplingType DefaultSamplingType
        {
            get
            {
                Debug.Assert(this.defaultSamplingType != SamplingType.Default);
                return this.defaultSamplingType;
            }
        }

        public MetricsConfig(MetricsContext context)
        {
            this.context = context;

            if (!GloballyDisabledMetrics)
            {
                this.healthStatus = HealthChecks.GetStatus;
                this.reports = new MetricsReports(this.context.DataProvider, this.healthStatus);

                this.context.Advanced.ContextDisabled += (s, e) =>
                {
                    this.isDisabled = true;
                    DisableAllReports();
                };
            }
        }

        /// <summary>
        /// Create HTTP endpoint where metrics will be available in various formats:
        /// GET / => visualization application
        /// GET /json => metrics serialized as JSON
        /// GET /text => metrics in human readable text format
        /// </summary>
        /// <param name="httpUriPrefix">prefix where to start HTTP endpoint</param>
        /// <param name="filter">Only report metrics that match the filter.</param> 
        /// <param name="maxRetries">maximum number of attempts to start the http listener. Note the retry time between attempts is dependent on this value</param>
        /// <returns>Chain-able configuration object.</returns>
        public MetricsConfig WithHttpEndpoint(string httpUriPrefix, MetricsFilter filter = null, int maxRetries = 3)
        {
            if (this.isDisabled)
            {
                return this;
            }

            return WithHttpEndpoint(httpUriPrefix, _ => { }, filter, maxRetries);
        }

        /// <summary>
        /// Create HTTP endpoint where metrics will be available in various formats:
        /// GET / => visualization application
        /// GET /json => metrics serialized as JSON
        /// GET /text => metrics in human readable text format
        /// </summary>
        /// <param name="httpUriPrefix">prefix where to start HTTP endpoint</param>
        /// <param name="reportsConfig">Endpoint reports configuration</param>
        /// <param name="filter">Only report metrics that match the filter.</param> 
        /// <param name="maxRetries">maximum number of attempts to start the http listener. Note the retry time between attempts is dependent on this value</param>
        /// <returns>Chain-able configuration object.</returns>
        public MetricsConfig WithHttpEndpoint(string httpUriPrefix, Action<MetricsEndpointReports> reportsConfig, MetricsFilter filter = null, int maxRetries = 3)
        {
            if (this.isDisabled)
            {
                return this;
            }

            if (this.httpEndpoints.ContainsKey(httpUriPrefix))
            {
                log.WarnFormat("Http uri prefix {0} already registered. Ignoring...", httpUriPrefix);
                return this;
            }

            var endpointReports = new MetricsEndpointReports(this.context.DataProvider.WithFilter(filter), this.healthStatus);
            reportsConfig(endpointReports);

            var endpoint = MetricsHttpListener.StartHttpListenerAsync(httpUriPrefix, endpointReports.Endpoints, this.httpEndpointCancellation.Token, maxRetries);
            this.httpEndpoints.Add(httpUriPrefix, endpoint);

            return this;
        }
        /// <summary>
        /// Configure Metrics library to use a custom health status reporter. By default HealthChecks.GetStatus() is used.
        /// </summary>
        /// <param name="healthStatus">Function that provides the current health status.</param><commit_msg>Throw an exception if an http endpoint is already configured<commit_after>﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Metrics.Endpoints;
using Metrics.Logging;
using Metrics.MetricData;
using Metrics.Reports;

namespace Metrics
{
    public sealed class MetricsConfig : IDisposable, Utils.IHideObjectMembers
    {
        private static readonly ILog log = LogProvider.GetCurrentClassLogger();

        public static readonly bool GloballyDisabledMetrics = ReadGloballyDisableMetricsSetting();

        private readonly MetricsContext context;
        private readonly MetricsReports reports;

        private Func<HealthStatus> healthStatus;

        private readonly CancellationTokenSource httpEndpointCancellation = new CancellationTokenSource();

        private readonly Dictionary<string, Task<MetricsHttpListener>> httpEndpoints = new Dictionary<string, Task<MetricsHttpListener>>();

        private SamplingType defaultSamplingType = SamplingType.ExponentiallyDecaying;

        private bool isDisabled = MetricsConfig.GloballyDisabledMetrics;

        /// <summary>
        /// Gets the currently configured default sampling type to use for histogram sampling.
        /// </summary>
        public SamplingType DefaultSamplingType
        {
            get
            {
                Debug.Assert(this.defaultSamplingType != SamplingType.Default);
                return this.defaultSamplingType;
            }
        }

        public MetricsConfig(MetricsContext context)
        {
            this.context = context;

            if (!GloballyDisabledMetrics)
            {
                this.healthStatus = HealthChecks.GetStatus;
                this.reports = new MetricsReports(this.context.DataProvider, this.healthStatus);

                this.context.Advanced.ContextDisabled += (s, e) =>
                {
                    this.isDisabled = true;
                    DisableAllReports();
                };
            }
        }

        /// <summary>
        /// Create HTTP endpoint where metrics will be available in various formats:
        /// GET / => visualization application
        /// GET /json => metrics serialized as JSON
        /// GET /text => metrics in human readable text format
        /// </summary>
        /// <param name="httpUriPrefix">prefix where to start HTTP endpoint</param>
        /// <param name="filter">Only report metrics that match the filter.</param> 
        /// <param name="maxRetries">maximum number of attempts to start the http listener. Note the retry time between attempts is dependent on this value</param>
        /// <returns>Chain-able configuration object.</returns>
        public MetricsConfig WithHttpEndpoint(string httpUriPrefix, MetricsFilter filter = null, int maxRetries = 3)
        {
            if (this.isDisabled)
            {
                return this;
            }

            return WithHttpEndpoint(httpUriPrefix, _ => { }, filter, maxRetries);
        }

        /// <summary>
        /// Create HTTP endpoint where metrics will be available in various formats:
        /// GET / => visualization application
        /// GET /json => metrics serialized as JSON
        /// GET /text => metrics in human readable text format
        /// </summary>
        /// <param name="httpUriPrefix">prefix where to start HTTP endpoint</param>
        /// <param name="reportsConfig">Endpoint reports configuration</param>
        /// <param name="filter">Only report metrics that match the filter.</param> 
        /// <param name="maxRetries">maximum number of attempts to start the http listener. Note the retry time between attempts is dependent on this value</param>
        /// <returns>Chain-able configuration object.</returns>
        public MetricsConfig WithHttpEndpoint(string httpUriPrefix, Action<MetricsEndpointReports> reportsConfig, MetricsFilter filter = null, int maxRetries = 3)
        {
            if (this.isDisabled)
            {
                return this;
            }

            if (this.httpEndpoints.ContainsKey(httpUriPrefix))
            {
                throw new InvalidOperationException($"Http URI prefix {httpUriPrefix} already configured.");
            }

            var endpointReports = new MetricsEndpointReports(this.context.DataProvider.WithFilter(filter), this.healthStatus);
            reportsConfig(endpointReports);

            var endpoint = MetricsHttpListener.StartHttpListenerAsync(httpUriPrefix, endpointReports.Endpoints, this.httpEndpointCancellation.Token, maxRetries);
            this.httpEndpoints.Add(httpUriPrefix, endpoint);

            return this;
        }
        /// <summary>
        /// Configure Metrics library to use a custom health status reporter. By default HealthChecks.GetStatus() is used.
        /// </summary>
        /// <param name="healthStatus">Function that provides the current health status.</param>
{'fraction_non_alphanumeric': 0.08630863086308631, 'fraction_numerical': 0.0005000500050005, 'mean_word_length': 2.367003367003367, 'pattern_counts': {'":': 0, '<': 71, '<?xml version=': 0, '>': 87, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4795100', 'n_tokens_mistral': 2347, 'n_tokens_neox': 2266, 'n_words': 692}