You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@logging.apache.org by "ASF GitHub Bot (Jira)" <ji...@apache.org> on 2020/09/17 07:11:00 UTC

[jira] [Work logged] (LOG4NET-644) Rest Appender

     [ https://issues.apache.org/jira/browse/LOG4NET-644?focusedWorklogId=485563&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-485563 ]

ASF GitHub Bot logged work on LOG4NET-644:
------------------------------------------

                Author: ASF GitHub Bot
            Created on: 17/Sep/20 07:10
            Start Date: 17/Sep/20 07:10
    Worklog Time Spent: 10m 
      Work Description: fluffynuts commented on a change in pull request #56:
URL: https://github.com/apache/logging-log4net/pull/56#discussion_r490007841



##########
File path: src/Appender/RestServiceAppender.cs
##########
@@ -0,0 +1,473 @@
+#region Apache License
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more 
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership. 
+// The ASF licenses this file to you under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with 
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#endregion
+
+
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Net.Http;
+
+using log4net.Core;
+using log4net.Layout;
+using Newtonsoft.Json;
+
+namespace log4net.Appender
+{
+    /// <summary>
+    /// Appender that logs to a Rest Service provided via configuration it's designed base of AdoNetAppender.
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// <see cref="RestServiceAppender"/> appends logging events to a rest endpoint
+    /// The appender can be configured to specify the serviice endpoint string by setting  <see cref="LoggingEndpoint"/> property.
+    /// The rest service content type cen be specified by  <see cref="ContentType"/> property.
+    /// The Rest method can be specified via <see cref="HttpMethod"/> property.
+    /// Also this appender has a propert named as <see cref="IncludeAllFields"/>. This fields checks with the appender and it's serialized that 
+    /// all event details with JSonConvert and append it the rest call.
+    /// </para>
+    /// </remarks>
+    /// <example>
+    /// An example of a request Json
+    /// <code lang="JSON">
+    /// {
+    ///     "log_level":"INFO",
+    ///     "logger":"RestLogger",
+    ///     "message":"Log Mesaji 0",
+    ///     "userid":"Custom Parameter With Thread Context"
+    /// }
+    /// </code>
+    /// </example>
+    /// <example>
+    /// An example configuration to log generate like above json format.
+    /// <code lang="XML" escaped="true">
+    /// <appender name="RestServiceAppender_RestEndpoint" type="log4net.Appender.RestServiceAppender" >
+    ///   <LoggingEndpoint value="http://dummyendpoint.log4net.apache.org/DummyLoggingServiceEndpoint" />
+    ///   <ContentType value="applicationJson" />
+    ///   <HttpMethod value="POST" />
+    ///   <IncludeAllFields value="false" />
+    ///      <parameter>
+    ///        <parameterName value="log_level" />
+    ///        <layout type="log4net.Layout.PatternLayout">
+    ///          <conversionPattern value="%level" />
+    ///        </layout>
+    ///      </parameter>
+    ///      <parameter>
+    ///        <parameterName value="logger" />
+    ///        <layout type="log4net.Layout.PatternLayout">
+    ///          <conversionPattern value="%logger" />
+    ///        </layout>
+    ///      </parameter>
+    ///      <parameter>
+    ///        <parameterName value="message" />
+    ///        <layout type="log4net.Layout.PatternLayout">
+    ///          <conversionPattern value="%message" />
+    ///        </layout>
+    ///      </parameter> 
+    ///      <parameter>
+    ///        <parameterName value="CustomParameter" />
+    ///        <layout type="log4net.Layout.PatternLayout">
+    ///          <conversionPattern value="%property{userid}" />
+    ///        </layout>
+    ///      </parameter>
+    /// </appender>
+    /// </code>
+    /// </example>
+    /// <author>Ertugrul Kara</author>
+    public class RestServiceAppender : IAppender, IBulkAppender, IOptionHandler, IErrorHandler
+    {
+        private HttpClient _httpClient;
+
+        #region Public Instance Constructors
+
+        /// <summary> 
+        /// Initializes a new instance of the <see cref="RestServiceAppender" /> class.
+        /// </summary>
+        /// <remarks>
+        /// Public default constructor to initialize a new instance of this class. It will use only Unit Testing purpose
+        /// </remarks>
+        public RestServiceAppender(HttpClient httpClient)
+        {
+            _httpClient = httpClient;
+
+            m_parameters = new ArrayList();
+        }
+
+        /// <summary> 
+        /// Initializes a new instance of the <see cref="RestServiceAppender" /> class.
+        /// </summary>
+        /// <remarks>
+        /// Public default constructor to initialize a new instance of this class.
+        /// </remarks>
+        public RestServiceAppender()
+            :this(new HttpClient())
+        {
+           
+        }
+
+        #endregion // Public Instance Constructors
+
+        #region Public Instance Properties
+
+        /// <summary>
+        /// Gets or sets the Logging endpoint to sending log requests.
+        /// </summary>
+        /// <value>
+        /// http or https based Url formatted end point should be define 
+        /// </value>
+        public string LoggingEndpoint { get; set; }
+
+
+        /// <summary>
+        /// Gets or sets the logging endpoint accepted content type property. I recommend use for application/json
+        /// </summary>
+        /// <value>
+        /// The rest service carry content with that format.
+        /// </value>
+        public string ContentType { get; set; }
+
+        /// <summary>
+        /// Gets or sets the logging endpoint accepted HttpMethod
+        /// </summary>
+        /// <value>
+        /// Values can only be POST or PUT etc. Because rest services should carry service data via rest body, 
+        /// and body formatting options limited for rest services.
+        /// </value>
+        public string HttpMethod { get; set; }
+
+        /// <summary>
+        /// Name of appender.
+        /// </summary>
+        public string Name { get; set; }
+
+        /// <summary>
+        /// That property says to appender, include all event data to rest service for advanced logging
+        /// </summary>
+        /// <value>
+        /// If value set as true, loggingEvent will serialize end put the rest request, othervise it will only contains parameters. Defaults set for false
+        /// </value>
+        public bool IncludeAllFields { get; set; }
+
+        #endregion // Public Instance Properties
+
+        #region Public Instance Methods
+
+        /// <summary>
+        /// Adds a parameter to the command.
+        /// </summary>
+        /// <param name="parameter">The parameter to add to the command.</param>
+        /// <remarks>
+        /// <para>
+        /// Adds a parameter to the ordered list of command parameters.
+        /// </para>
+        /// </remarks>
+        public void AddParameter(RestAppenderParameter parameter)
+        {
+            m_parameters.Add(parameter);
+        }
+
+        #endregion // Public Instance Methods
+
+        #region Private Instance Methods
+
+
+        private string BindParameters(LoggingEvent loggingEvent)
+        {
+            var restFields = new Dictionary<string, object>();
+
+            foreach (RestAppenderParameter item in m_parameters)
+                item.FormatValue(restFields, loggingEvent);
+
+            if (IncludeAllFields)
+                restFields.Add("DetailFields", JsonConvert.SerializeObject(loggingEvent));
+
+            return JsonConvert.SerializeObject(restFields);
+        }
+
+    
+
+        /// <summary>
+        /// Call Rest Service from here.
+        /// This method send log events to rest endpoint. Message content send as string parameter for here
+        /// </summary>
+        private void SendLogs(string messageContent)
+        {
+            try
+            {
+                HttpRequestMessage requestMessage = new HttpRequestMessage();
+
+                requestMessage.Method = new System.Net.Http.HttpMethod(HttpMethod);
+
+                requestMessage.Content = new StringContent(messageContent);
+
+                var result = _httpClient.SendAsync(requestMessage).Result;
+            }
+            catch (Exception ex)
+            {
+                // Sadly, your connection is bad or rest endpoint does not exist
+                Error($"Cannot Send Error To {LoggingEndpoint}", ex);
+            }
+
+        }
+
+        #endregion //Private Instance Methods
+
+        #region Implementation of IAppender
+
+        /// <summary>
+        /// Close method is not implemented because rest queries not contains any file or stream object require to close
+        /// </summary>
+        public void Close()
+        {
+
+        }
+
+        /// <summary>
+        /// Send LoggngEvents to Rest Queries
+        /// BindParameter generates Request Json body based on logging event paremeter
+        /// </summary>
+        /// <param name="loggingEvent">the LoggingEvent that contains log details</param>
+        public void DoAppend(LoggingEvent loggingEvent)
+        {
+            SendLogs(BindParameters(loggingEvent));
+        }
+
+        #endregion //Implementation of IAppender
+
+        #region Implementation of IBulkAppender
+
+        /// <summary>
+        /// Send LoggngEvents to Rest Queries
+        /// BindParameter generates Request Json body based on logging event paremeter. This method gets an array of logging event and sends via rest service in loop
+        /// </summary>
+        /// <param name="loggingEvents">the LoggingEvent that contains log details as array for bulk appender. </param>
+        public void DoAppend(LoggingEvent[] loggingEvents)
+        {
+            foreach (var item in loggingEvents)
+            {
+                SendLogs(BindParameters(item));
+            }
+        }
+
+        #endregion //Implementation of IBulkAppender
+
+        #region Implementation of IOptionHandler
+
+        /// <summary>
+        /// Initialize the appender based on the options set
+        /// </summary>
+        /// <remarks>
+        /// <para>
+        /// This is part of the <see cref="IOptionHandler"/> delayed object
+        /// activation scheme. The <see cref="ActivateOptions"/> method must 
+        /// be called on this object after the configuration properties have
+        /// been set. Until <see cref="ActivateOptions"/> is called this
+        /// object is in an undefined state and must not be used. 
+        /// </para>
+        /// <para>
+        /// If any of the configuration properties are modified then 
+        /// <see cref="ActivateOptions"/> must be called again.
+        /// </para>
+        /// </remarks>
+        public void ActivateOptions()
+        {
+            _httpClient.BaseAddress = new Uri(LoggingEndpoint);
+
+        }
+
+        #endregion //  Implementation of IOptionHandler
+
+        #region Implementation of IErrorHandler
+
+
+        /// <summary>
+        /// Internal Error Handler Implementation <see cref="IErrorHandler"/>
+        /// </summary>
+        /// <param name="message">Message from internal error handler</param>
+        /// <param name="e">Logging Exception parameter from internal error</param>
+        /// <param name="errorCode">Error Code from internal error</param>
+        public void Error(string message, Exception e, ErrorCode errorCode)
+        {
+            Console.WriteLine($"{message} - {e.StackTrace} - {errorCode}");
+        }
+         
+        /// <summary>
+        /// Internal Error Handler Implementation Overload. This logs internal error via overload method
+        /// </summary>
+        /// <param name="message">Message from internal error handler</param>
+        /// <param name="e">Logging exception parameter from internal error</param>
+        /// <remarks>
+        /// <para>
+        /// Overload method has an additional parameter for <see cref="ErrorCode" /> is set as <see cref="ErrorCode.GenericFailure"/>
+        /// </para>
+        /// </remarks>
+        public void Error(string message, Exception e)
+        {
+            Error(message, e, ErrorCode.GenericFailure);
+        }
+
+        /// <summary>
+        /// Internal Error Handler Implementation Overload. This logs internal error via overload method
+        /// </summary>
+        /// <param name="message">Message from internal error handler</param>
+        /// <param name="e">Logging exception parameter from internal error</param>
+        /// <remarks>
+        /// <para>
+        /// Overload method has an additional parameter for <see cref="Exception"/> it set as Null 
+        /// Overload method has an additional parameter for <see cref="ErrorCode" /> is set as <see cref="ErrorCode.GenericFailure"/>
+        /// </para>
+        /// </remarks>
+        public void Error(string message)
+        {
+            this.Error(message, null, ErrorCode.GenericFailure);
+        }
+
+
+        #endregion //Implementation of IErrorHandler
+
+        #region Protected Instance Fields
+
+        /// <summary>
+        /// The list of <see cref="RestAppenderParameter"/> objects.
+        /// </summary>
+        /// <remarks>
+        /// <para>
+        /// The list of <see cref="RestAppenderParameter"/> objects.
+        /// </para>
+        /// </remarks>
+        protected ArrayList m_parameters;
+
+        #endregion //  Protected Instance Fields
+
+        #region Private Static Fields
+
+        /// <summary>
+        /// The fully qualified type of the RestServiceAppender class.
+        /// </summary>
+        /// <remarks>
+        /// Used by the internal logger to record the Type of the
+        /// log message.
+        /// </remarks>
+        private readonly static Type declaringType = typeof(RestServiceAppender);
+
+        #endregion Private Static Fields
+
+    }
+
+
+    /// <summary>
+    /// Parameter type used by the <see cref="RestAppenderParameter"/>.
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// This class provides the basic Dictionary Object that contains Key,Value pairs for logging events.
+    /// </para>
+    /// <para>This type can be subclassed to provide database specific
+    /// functionality. The one method that is called externally
+    /// <see cref="FormatValue"/>.
+    /// </para>
+    /// </remarks>
+    public class RestAppenderParameter

Review comment:
       please use one file per class -- just makes it easier to find stuff when searching through a project.

##########
File path: src/Appender/RestServiceAppender.cs
##########
@@ -0,0 +1,473 @@
+#region Apache License
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more 
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership. 
+// The ASF licenses this file to you under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with 
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#endregion
+
+
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Net.Http;
+
+using log4net.Core;
+using log4net.Layout;
+using Newtonsoft.Json;
+
+namespace log4net.Appender
+{
+    /// <summary>
+    /// Appender that logs to a Rest Service provided via configuration it's designed base of AdoNetAppender.
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// <see cref="RestServiceAppender"/> appends logging events to a rest endpoint
+    /// The appender can be configured to specify the serviice endpoint string by setting  <see cref="LoggingEndpoint"/> property.
+    /// The rest service content type cen be specified by  <see cref="ContentType"/> property.
+    /// The Rest method can be specified via <see cref="HttpMethod"/> property.
+    /// Also this appender has a propert named as <see cref="IncludeAllFields"/>. This fields checks with the appender and it's serialized that 
+    /// all event details with JSonConvert and append it the rest call.
+    /// </para>
+    /// </remarks>
+    /// <example>
+    /// An example of a request Json
+    /// <code lang="JSON">
+    /// {
+    ///     "log_level":"INFO",
+    ///     "logger":"RestLogger",
+    ///     "message":"Log Mesaji 0",
+    ///     "userid":"Custom Parameter With Thread Context"
+    /// }
+    /// </code>
+    /// </example>
+    /// <example>
+    /// An example configuration to log generate like above json format.
+    /// <code lang="XML" escaped="true">
+    /// <appender name="RestServiceAppender_RestEndpoint" type="log4net.Appender.RestServiceAppender" >
+    ///   <LoggingEndpoint value="http://dummyendpoint.log4net.apache.org/DummyLoggingServiceEndpoint" />
+    ///   <ContentType value="applicationJson" />
+    ///   <HttpMethod value="POST" />
+    ///   <IncludeAllFields value="false" />
+    ///      <parameter>
+    ///        <parameterName value="log_level" />
+    ///        <layout type="log4net.Layout.PatternLayout">
+    ///          <conversionPattern value="%level" />
+    ///        </layout>
+    ///      </parameter>
+    ///      <parameter>
+    ///        <parameterName value="logger" />
+    ///        <layout type="log4net.Layout.PatternLayout">
+    ///          <conversionPattern value="%logger" />
+    ///        </layout>
+    ///      </parameter>
+    ///      <parameter>
+    ///        <parameterName value="message" />
+    ///        <layout type="log4net.Layout.PatternLayout">
+    ///          <conversionPattern value="%message" />
+    ///        </layout>
+    ///      </parameter> 
+    ///      <parameter>
+    ///        <parameterName value="CustomParameter" />
+    ///        <layout type="log4net.Layout.PatternLayout">
+    ///          <conversionPattern value="%property{userid}" />
+    ///        </layout>
+    ///      </parameter>
+    /// </appender>
+    /// </code>
+    /// </example>
+    /// <author>Ertugrul Kara</author>
+    public class RestServiceAppender : IAppender, IBulkAppender, IOptionHandler, IErrorHandler
+    {
+        private HttpClient _httpClient;
+
+        #region Public Instance Constructors
+
+        /// <summary> 
+        /// Initializes a new instance of the <see cref="RestServiceAppender" /> class.
+        /// </summary>
+        /// <remarks>
+        /// Public default constructor to initialize a new instance of this class. It will use only Unit Testing purpose
+        /// </remarks>
+        public RestServiceAppender(HttpClient httpClient)
+        {
+            _httpClient = httpClient;
+
+            m_parameters = new ArrayList();
+        }
+
+        /// <summary> 
+        /// Initializes a new instance of the <see cref="RestServiceAppender" /> class.
+        /// </summary>
+        /// <remarks>
+        /// Public default constructor to initialize a new instance of this class.
+        /// </remarks>
+        public RestServiceAppender()
+            :this(new HttpClient())
+        {
+           
+        }
+
+        #endregion // Public Instance Constructors
+
+        #region Public Instance Properties
+
+        /// <summary>
+        /// Gets or sets the Logging endpoint to sending log requests.
+        /// </summary>
+        /// <value>
+        /// http or https based Url formatted end point should be define 
+        /// </value>
+        public string LoggingEndpoint { get; set; }
+
+
+        /// <summary>
+        /// Gets or sets the logging endpoint accepted content type property. I recommend use for application/json
+        /// </summary>
+        /// <value>
+        /// The rest service carry content with that format.
+        /// </value>
+        public string ContentType { get; set; }
+
+        /// <summary>
+        /// Gets or sets the logging endpoint accepted HttpMethod
+        /// </summary>
+        /// <value>
+        /// Values can only be POST or PUT etc. Because rest services should carry service data via rest body, 
+        /// and body formatting options limited for rest services.
+        /// </value>
+        public string HttpMethod { get; set; }
+
+        /// <summary>
+        /// Name of appender.
+        /// </summary>
+        public string Name { get; set; }
+
+        /// <summary>
+        /// That property says to appender, include all event data to rest service for advanced logging
+        /// </summary>
+        /// <value>
+        /// If value set as true, loggingEvent will serialize end put the rest request, othervise it will only contains parameters. Defaults set for false
+        /// </value>
+        public bool IncludeAllFields { get; set; }
+
+        #endregion // Public Instance Properties
+
+        #region Public Instance Methods
+
+        /// <summary>
+        /// Adds a parameter to the command.
+        /// </summary>
+        /// <param name="parameter">The parameter to add to the command.</param>
+        /// <remarks>
+        /// <para>
+        /// Adds a parameter to the ordered list of command parameters.
+        /// </para>
+        /// </remarks>
+        public void AddParameter(RestAppenderParameter parameter)
+        {
+            m_parameters.Add(parameter);
+        }
+
+        #endregion // Public Instance Methods
+
+        #region Private Instance Methods
+
+
+        private string BindParameters(LoggingEvent loggingEvent)
+        {
+            var restFields = new Dictionary<string, object>();
+
+            foreach (RestAppenderParameter item in m_parameters)
+                item.FormatValue(restFields, loggingEvent);
+
+            if (IncludeAllFields)
+                restFields.Add("DetailFields", JsonConvert.SerializeObject(loggingEvent));
+
+            return JsonConvert.SerializeObject(restFields);
+        }
+
+    
+
+        /// <summary>
+        /// Call Rest Service from here.
+        /// This method send log events to rest endpoint. Message content send as string parameter for here
+        /// </summary>
+        private void SendLogs(string messageContent)
+        {
+            try
+            {
+                HttpRequestMessage requestMessage = new HttpRequestMessage();
+
+                requestMessage.Method = new System.Net.Http.HttpMethod(HttpMethod);
+
+                requestMessage.Content = new StringContent(messageContent);
+
+                var result = _httpClient.SendAsync(requestMessage).Result;

Review comment:
       minor: result is never used

##########
File path: src/Appender/RestServiceAppender.cs
##########
@@ -0,0 +1,473 @@
+#region Apache License
+//
+// Licensed to the Apache Software Foundation (ASF) under one or more 
+// contributor license agreements. See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership. 
+// The ASF licenses this file to you under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with 
+// the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+#endregion
+
+
+
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Net.Http;
+
+using log4net.Core;
+using log4net.Layout;
+using Newtonsoft.Json;
+
+namespace log4net.Appender
+{
+    /// <summary>
+    /// Appender that logs to a Rest Service provided via configuration it's designed base of AdoNetAppender.
+    /// </summary>
+    /// <remarks>
+    /// <para>
+    /// <see cref="RestServiceAppender"/> appends logging events to a rest endpoint
+    /// The appender can be configured to specify the serviice endpoint string by setting  <see cref="LoggingEndpoint"/> property.
+    /// The rest service content type cen be specified by  <see cref="ContentType"/> property.
+    /// The Rest method can be specified via <see cref="HttpMethod"/> property.
+    /// Also this appender has a propert named as <see cref="IncludeAllFields"/>. This fields checks with the appender and it's serialized that 
+    /// all event details with JSonConvert and append it the rest call.
+    /// </para>
+    /// </remarks>
+    /// <example>
+    /// An example of a request Json
+    /// <code lang="JSON">
+    /// {
+    ///     "log_level":"INFO",
+    ///     "logger":"RestLogger",
+    ///     "message":"Log Mesaji 0",
+    ///     "userid":"Custom Parameter With Thread Context"
+    /// }
+    /// </code>
+    /// </example>
+    /// <example>
+    /// An example configuration to log generate like above json format.
+    /// <code lang="XML" escaped="true">
+    /// <appender name="RestServiceAppender_RestEndpoint" type="log4net.Appender.RestServiceAppender" >
+    ///   <LoggingEndpoint value="http://dummyendpoint.log4net.apache.org/DummyLoggingServiceEndpoint" />
+    ///   <ContentType value="applicationJson" />
+    ///   <HttpMethod value="POST" />
+    ///   <IncludeAllFields value="false" />
+    ///      <parameter>
+    ///        <parameterName value="log_level" />
+    ///        <layout type="log4net.Layout.PatternLayout">
+    ///          <conversionPattern value="%level" />
+    ///        </layout>
+    ///      </parameter>
+    ///      <parameter>
+    ///        <parameterName value="logger" />
+    ///        <layout type="log4net.Layout.PatternLayout">
+    ///          <conversionPattern value="%logger" />
+    ///        </layout>
+    ///      </parameter>
+    ///      <parameter>
+    ///        <parameterName value="message" />
+    ///        <layout type="log4net.Layout.PatternLayout">
+    ///          <conversionPattern value="%message" />
+    ///        </layout>
+    ///      </parameter> 
+    ///      <parameter>
+    ///        <parameterName value="CustomParameter" />
+    ///        <layout type="log4net.Layout.PatternLayout">
+    ///          <conversionPattern value="%property{userid}" />
+    ///        </layout>
+    ///      </parameter>
+    /// </appender>
+    /// </code>
+    /// </example>
+    /// <author>Ertugrul Kara</author>
+    public class RestServiceAppender : IAppender, IBulkAppender, IOptionHandler, IErrorHandler
+    {
+        private HttpClient _httpClient;
+
+        #region Public Instance Constructors
+
+        /// <summary> 
+        /// Initializes a new instance of the <see cref="RestServiceAppender" /> class.
+        /// </summary>
+        /// <remarks>
+        /// Public default constructor to initialize a new instance of this class. It will use only Unit Testing purpose
+        /// </remarks>
+        public RestServiceAppender(HttpClient httpClient)
+        {
+            _httpClient = httpClient;
+
+            m_parameters = new ArrayList();
+        }
+
+        /// <summary> 
+        /// Initializes a new instance of the <see cref="RestServiceAppender" /> class.
+        /// </summary>
+        /// <remarks>
+        /// Public default constructor to initialize a new instance of this class.
+        /// </remarks>
+        public RestServiceAppender()
+            :this(new HttpClient())
+        {
+           
+        }
+
+        #endregion // Public Instance Constructors
+
+        #region Public Instance Properties
+
+        /// <summary>
+        /// Gets or sets the Logging endpoint to sending log requests.
+        /// </summary>
+        /// <value>
+        /// http or https based Url formatted end point should be define 
+        /// </value>
+        public string LoggingEndpoint { get; set; }
+
+
+        /// <summary>
+        /// Gets or sets the logging endpoint accepted content type property. I recommend use for application/json
+        /// </summary>
+        /// <value>
+        /// The rest service carry content with that format.
+        /// </value>
+        public string ContentType { get; set; }
+
+        /// <summary>
+        /// Gets or sets the logging endpoint accepted HttpMethod
+        /// </summary>
+        /// <value>
+        /// Values can only be POST or PUT etc. Because rest services should carry service data via rest body, 
+        /// and body formatting options limited for rest services.
+        /// </value>
+        public string HttpMethod { get; set; }
+
+        /// <summary>
+        /// Name of appender.
+        /// </summary>
+        public string Name { get; set; }
+
+        /// <summary>
+        /// That property says to appender, include all event data to rest service for advanced logging
+        /// </summary>
+        /// <value>
+        /// If value set as true, loggingEvent will serialize end put the rest request, othervise it will only contains parameters. Defaults set for false
+        /// </value>
+        public bool IncludeAllFields { get; set; }
+
+        #endregion // Public Instance Properties
+
+        #region Public Instance Methods
+
+        /// <summary>
+        /// Adds a parameter to the command.
+        /// </summary>
+        /// <param name="parameter">The parameter to add to the command.</param>
+        /// <remarks>
+        /// <para>
+        /// Adds a parameter to the ordered list of command parameters.
+        /// </para>
+        /// </remarks>
+        public void AddParameter(RestAppenderParameter parameter)
+        {
+            m_parameters.Add(parameter);
+        }
+
+        #endregion // Public Instance Methods
+
+        #region Private Instance Methods
+
+
+        private string BindParameters(LoggingEvent loggingEvent)
+        {
+            var restFields = new Dictionary<string, object>();
+
+            foreach (RestAppenderParameter item in m_parameters)
+                item.FormatValue(restFields, loggingEvent);
+
+            if (IncludeAllFields)
+                restFields.Add("DetailFields", JsonConvert.SerializeObject(loggingEvent));
+
+            return JsonConvert.SerializeObject(restFields);
+        }
+
+    
+
+        /// <summary>
+        /// Call Rest Service from here.
+        /// This method send log events to rest endpoint. Message content send as string parameter for here
+        /// </summary>
+        private void SendLogs(string messageContent)
+        {
+            try
+            {
+                HttpRequestMessage requestMessage = new HttpRequestMessage();
+
+                requestMessage.Method = new System.Net.Http.HttpMethod(HttpMethod);
+
+                requestMessage.Content = new StringContent(messageContent);
+
+                var result = _httpClient.SendAsync(requestMessage).Result;
+            }
+            catch (Exception ex)
+            {
+                // Sadly, your connection is bad or rest endpoint does not exist

Review comment:
       Unfortunately, this means that an intermittent connection error loses the log. I expect that people would probably like to use REST logging to services which are on another machine, perhaps even on a totally different network, so, unlike ADO appending, I expect the chance of failure to be higher. It would be nice if there were some kind of contingency plan here.




----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org


Issue Time Tracking
-------------------

            Worklog Id:     (was: 485563)
    Remaining Estimate: 1h 40m  (was: 1h 50m)
            Time Spent: 20m  (was: 10m)

> Rest Appender
> -------------
>
>                 Key: LOG4NET-644
>                 URL: https://issues.apache.org/jira/browse/LOG4NET-644
>             Project: Log4net
>          Issue Type: Wish
>          Components: Appenders
>    Affects Versions: 2.1.0
>            Reporter: Ertuğrul Kara
>            Priority: Major
>   Original Estimate: 2h
>          Time Spent: 20m
>  Remaining Estimate: 1h 40m
>
> We need a Rest Appender for log4net. I will implement that appender like Ado.Net Appender base. Because we have a logging service that uses many diffrent stores such as elastic, mongo, file etc and we will append the log to there.
>  
> I think a Rest Appender can fit that solution. 



--
This message was sent by Atlassian Jira
(v8.3.4#803005)