Exemple #1
0
    /// <summary>
    /// <see cref="LoggerSinkConfiguration"/> extension that provides configuration chaining.
    /// </summary>
    /// <param name="loggerSinkConfiguration">Instance of <see cref="LoggerSinkConfiguration"/> object.</param>
    /// <param name="telegramSinkOptions">The Telegram sink options object.</param>
    /// <param name="restrictedToMinimumLevel"><see cref="LogEventLevel"/> value that specifies minimum logging
    /// level that will be allowed to be logged.</param>
    /// <returns>Instance of <see cref="LoggerConfiguration"/> object.</returns>
    public static LoggerConfiguration Telegram(
        this LoggerSinkConfiguration loggerSinkConfiguration,
        TelegramSinkOptions telegramSinkOptions,
        LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum)
    {
        if (loggerSinkConfiguration is null)
        {
            throw new ArgumentNullException(nameof(loggerSinkConfiguration), "The logger sink configuration is null.");
        }

        if (telegramSinkOptions is null)
        {
            throw new ArgumentNullException(nameof(telegramSinkOptions), "The Telegram sink options are null.");
        }

        if (string.IsNullOrWhiteSpace(telegramSinkOptions.BotToken))
        {
            throw new ArgumentNullException(nameof(telegramSinkOptions.BotToken), "The Telegram bot token is null.");
        }

        var batchingOptions = new PeriodicBatchingSinkOptions()
        {
            BatchSizeLimit = telegramSinkOptions.BatchSizeLimit,
            Period         = telegramSinkOptions.Period
        };

        var batchingSink = new PeriodicBatchingSink(new TelegramSink(telegramSinkOptions), batchingOptions);

        return(loggerSinkConfiguration.Sink(batchingSink, restrictedToMinimumLevel));
    }
Exemple #2
0
    /// <summary>
    /// Initializes a new instance of the <see cref="TelegramSink"/> class.
    /// </summary>
    /// <param name="options">Telegram options object.</param>
    public TelegramSink(TelegramSinkOptions options)
    {
        this.options = options;

        if (!string.IsNullOrWhiteSpace(options.OutputTemplate))
        {
            this.outputTemplateRenderer = new OutputTemplateRenderer(options.OutputTemplate!, options);
        }
    }
Exemple #3
0
    /// <summary>
    /// Initializes a new instance of the <see cref="OutputTemplateRenderer"/> class.
    /// </summary>
    /// <param name="outputTemplate">The output template.</param>
    /// <param name="options">The options.</param>
    internal OutputTemplateRenderer(string outputTemplate, TelegramSinkOptions options)
    {
        MessageTemplate template      = new MessageTemplateParser().Parse(outputTemplate);
        var             renderActions = new List <Action <ExtendedLogEvent, TextWriter> >();

        foreach (MessageTemplateToken token in template.Tokens)
        {
            switch (token)
            {
            case TextToken textToken:
                renderActions.Add((_, w) => TextTokenRenderer.Render(textToken, w, options));
                break;

            case PropertyToken propertyToken:
                switch (propertyToken.PropertyName)
                {
                case OutputProperties.LevelPropertyName:
                    renderActions.Add(new LogLevelRenderer(propertyToken).Render);
                    break;

                case OutputProperties.NewLinePropertyName:
                    renderActions.Add((_, w) => w.WriteLine());
                    break;

                case OutputProperties.ExceptionPropertyName:
                    renderActions.Add(new ExceptionRenderer(options).Render);
                    break;

                case OutputProperties.MessagePropertyName:
                    renderActions.Add(new MessageRenderer(options).Render);
                    break;

                case OutputProperties.TimestampPropertyName:
                    renderActions.Add(new TimestampRenderer(propertyToken).Render);
                    break;

                default:
                    renderActions.Add(new DefaultPropertyRenderer(propertyToken).Render);
                    break;
                }

                break;
            }
        }

        this.renderActions = renderActions.ToArray();
    }
Exemple #4
0
    /// <summary>
    /// Renders the message.
    /// </summary>
    /// <param name="extLogEvent">The log event.</param>
    /// <param name="options">The options.</param>
    /// <returns>The rendered message.</returns>
    private static string RenderMessage(ExtendedLogEvent extLogEvent, TelegramSinkOptions options)
    {
        var sb = new StringBuilder();
        var emoji = LogLevelRenderer.GetEmoji(extLogEvent.LogEvent);
        var renderedMessage = HtmlEscaper.Escape(options, extLogEvent.LogEvent.RenderMessage());

        sb.AppendLine($"{emoji} {renderedMessage}");
        sb.AppendLine(string.Empty);

        if (!string.IsNullOrWhiteSpace(options.ApplicationName) ||
            !string.IsNullOrWhiteSpace(options.DateFormat))
        {
            string applicationNamePart = string.IsNullOrWhiteSpace(options.ApplicationName)
                ? string.Empty
                : $"{HtmlEscaper.Escape(options, options.ApplicationName)}: ";

            string datePart = string.IsNullOrWhiteSpace(options.DateFormat)
                ? string.Empty
                : extLogEvent.FirstOccurrence != extLogEvent.LastOccurrence
                    ? $"The message occurred first on {extLogEvent.FirstOccurrence.ToString(options.DateFormat)} and last on {extLogEvent.LastOccurrence.ToString(options.DateFormat)}"
                    : $"The message occurred on {extLogEvent.FirstOccurrence.ToString(options.DateFormat)}";

            sb.AppendLine($"<i>{applicationNamePart}{datePart}</i>");
        }

        if (extLogEvent.LogEvent.Exception is null)
        {
            return sb.ToString();
        }

        var message = HtmlEscaper.Escape(options, extLogEvent.LogEvent.Exception.Message);
        var exceptionType = HtmlEscaper.Escape(options, extLogEvent.LogEvent.Exception.GetType().Name);

        sb.AppendLine($"\n<strong>{message}</strong>\n");
        sb.AppendLine($"Message: <code>{message}</code>");
        sb.AppendLine($"Type: <code>{exceptionType}</code>\n");

        if (extLogEvent.IncludeStackTrace)
        {
            var exception = HtmlEscaper.Escape(options, $"{extLogEvent.LogEvent.Exception}");
            sb.AppendLine($"Stack Trace\n<code>{exception}</code>");
        }

        return sb.ToString();
    }
        /// <summary>
        /// <see cref="LoggerSinkConfiguration"/> extension that provides configuration chaining.
        /// <example>
        ///     new LoggerConfiguration()
        ///         .MinimumLevel.Verbose()
        ///         .WriteTo.Telegram("botToken", "chatId")
        ///         .CreateLogger();
        /// </example>
        /// </summary>
        /// <param name="loggerSinkConfiguration">Instance of <see cref="LoggerSinkConfiguration"/> object.</param>
        /// <param name="botToken">The Telegram bot token.</param>
        /// <param name="chatId">The Telegram chat id.</param>
        /// <param name="batchSizeLimit">The maximum number of events to post in a single batch; defaults to 1 if
        /// not provided i.e. no batching by default.</param>
        /// <param name="period">The time to wait between checking for event batches; defaults to 1 sec if not
        /// provided.</param>
        /// <param name="formatProvider">The format provider used for formatting the message.</param>
        /// <param name="restrictedToMinimumLevel"><see cref="LogEventLevel"/> value that specifies minimum logging
        /// level that will be allowed to be logged.</param>
        /// <param name="visibleProperties">A value indicating log event properties that must be appended to the message.</param>
        /// <returns>Instance of <see cref="LoggerConfiguration"/> object.</returns>
        public static LoggerConfiguration Telegram(
            this LoggerSinkConfiguration loggerSinkConfiguration,
            string botToken,
            string chatId                          = null,
            int?batchSizeLimit                     = null,
            TimeSpan?period                        = null,
            IFormatProvider formatProvider         = null,
            LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum,
            IEnumerable <string> visibleProperties = null)
        {
            var telegramSinkOptions = new TelegramSinkOptions(
                botToken,
                chatId,
                batchSizeLimit,
                period,
                formatProvider,
                restrictedToMinimumLevel,
                visibleProperties: visibleProperties);

            return(loggerSinkConfiguration.Telegram(telegramSinkOptions, restrictedToMinimumLevel));
        }
        /// <summary>
        /// <see cref="LoggerSinkConfiguration"/> extension that provides configuration chaining.
        /// </summary>
        /// <param name="loggerSinkConfiguration">Instance of <see cref="LoggerSinkConfiguration"/> object.</param>
        /// <param name="telegramSinkOptions">The Telegram sink options object.</param>
        /// <param name="restrictedToMinimumLevel"><see cref="LogEventLevel"/> value that specifies minimum logging
        /// level that will be allowed to be logged.</param>
        /// <returns>Instance of <see cref="LoggerConfiguration"/> object.</returns>
        public static LoggerConfiguration Telegram(
            this LoggerSinkConfiguration loggerSinkConfiguration,
            TelegramSinkOptions telegramSinkOptions,
            LogEventLevel restrictedToMinimumLevel = LevelAlias.Minimum)
        {
            if (loggerSinkConfiguration == null)
            {
                throw new ArgumentNullException(nameof(loggerSinkConfiguration));
            }

            if (telegramSinkOptions == null)
            {
                throw new ArgumentNullException(nameof(telegramSinkOptions));
            }

            if (string.IsNullOrWhiteSpace(telegramSinkOptions.BotToken))
            {
                throw new ArgumentNullException(nameof(telegramSinkOptions.BotToken));
            }

            return(loggerSinkConfiguration.Sink(new TelegramSink(telegramSinkOptions), restrictedToMinimumLevel));
        }
Exemple #7
0
    /// <summary>
    /// <see cref="LoggerSinkConfiguration"/> extension that provides configuration chaining.
    /// <example>
    ///     new LoggerConfiguration()
    ///         .MinimumLevel.Verbose()
    ///         .WriteTo.Telegram("botToken", "chatId")
    ///         .CreateLogger();
    /// </example>
    /// </summary>
    /// <param name="loggerSinkConfiguration">Instance of <see cref="LoggerSinkConfiguration"/> object.</param>
    /// <param name="botToken">The Telegram bot token.</param>
    /// <param name="chatId">The Telegram chat id.</param>
    /// <param name="batchSizeLimit">The maximum number of events to post in a single batch; defaults to 1 if
    /// not provided i.e. no batching by default.</param>
    /// <param name="period">The time to wait between checking for event batches; defaults to 1 sec if not
    /// provided.</param>
    /// <param name="formatProvider">The format provider used for formatting the message.</param>
    /// <param name="restrictedToMinimumLevel"><see cref="LogEventLevel"/> value that specifies minimum logging
    /// level that will be allowed to be logged.</param>
    /// <param name="sendBatchesAsSingleMessages">A value indicating whether the batches are sent as single messages or as one block of messages.</param>
    /// <param name="includeStackTrace">Whether stack traces should be included or not.</param>
    /// <param name="dateFormat">The date time format showing how the date and time should be formatted.</param>
    /// <param name="applicationName">The name of the application sending the events in case multiple apps write to the same channel.</param>
    /// <param name="failureCallback">The failure callback.</param>
    /// <param name="useCustomHtmlFormatting">A value indicating whether custom HTML formatting in the messages could be used. (Use this carefully and only if really needed).</param>
    /// <param name="botApiUrl">The Telegram bot API url, defaults to https://api.telegram.org/bot.</param>
    /// <param name="outputTemplate">A output template that can be used to format the output data.</param>
    /// <param name="customHtmlFormatter">
    ///    You can pass a func in addition to <see cref="TelegramSinkOptions.UseCustomHtmlFormatting"/> to set your custom function for escaping HTML strings.
    ///    This will only be considered if <see cref="TelegramSinkOptions.UseCustomHtmlFormatting"/> is set to true.
    /// </param>
    /// <returns>Instance of <see cref="LoggerConfiguration"/> object.</returns>
    public static LoggerConfiguration Telegram(
        this LoggerSinkConfiguration loggerSinkConfiguration,
        string botToken,
        string chatId,
        int?batchSizeLimit                        = null,
        TimeSpan?period                           = null,
        IFormatProvider?formatProvider            = null,
        LogEventLevel restrictedToMinimumLevel    = LevelAlias.Minimum,
        bool?sendBatchesAsSingleMessages          = true,
        bool?includeStackTrace                    = true,
        string dateFormat                         = "dd.MM.yyyy HH:mm:sszzz",
        string applicationName                    = "",
        Action <Exception>?failureCallback        = null,
        bool useCustomHtmlFormatting              = false,
        string?botApiUrl                          = null,
        string?outputTemplate                     = null,
        Func <string, string>?customHtmlFormatter = null)
    {
        var telegramSinkOptions = new TelegramSinkOptions(
            botToken,
            chatId,
            dateFormat,
            applicationName,
            batchSizeLimit,
            period,
            formatProvider,
            restrictedToMinimumLevel,
            sendBatchesAsSingleMessages,
            includeStackTrace,
            failureCallback,
            useCustomHtmlFormatting,
            botApiUrl,
            outputTemplate,
            customHtmlFormatter: customHtmlFormatter);

        return(loggerSinkConfiguration.Telegram(telegramSinkOptions, restrictedToMinimumLevel));
    }
 /// <summary>
 ///     Creates a new instance of the renderer.
 /// </summary>
 /// <param name="options">The Telegram sink options.</param>
 public MessageRenderer(TelegramSinkOptions options)
 {
     this.options = options;
 }
 /// <summary>
 /// Renders the given text <paramref name="token"/>. Results are written to the <paramref name="output"/>.
 /// </summary>
 /// <param name="token">The text token.</param>
 /// <param name="output">The output.</param>
 /// <param name="options">The sink options.</param>
 public static void Render(TextToken token, TextWriter output, TelegramSinkOptions options)
 {
     output.Write(HtmlEscaper.Escape(options, token.Text));
 }
Exemple #10
0
 /// <summary>
 /// Correctly escapes strings taking options into consideration.
 /// </summary>
 /// <param name="options">The options specified by the consumer.</param>
 /// <param name="message">The string to escape.</param>
 /// <returns>The properly escaped string.</returns>
 internal static string Escape(TelegramSinkOptions options, string message)
 {
     return(options.CustomHtmlFormatter is null
         ? message.HtmlEscape(options.ShouldEscape)
         : options.CustomHtmlFormatter.Invoke(message));
 }
Exemple #11
0
 /// <summary>
 ///     Initializes a new instance of the <see cref="DefaultPropertyRenderer"/> class.
 /// </summary>
 /// <param name="options">The Telegram sink options.</param>
 public ExceptionRenderer(TelegramSinkOptions options)
 {
     this.options = options;
 }