~ifolder-dev/simias/trunk-packaging

« back to all changes in this revision

Viewing changes to src/core/Simias.log4net/src/Appender/.svn/text-base/RemotingAppender.cs.svn-base

  • Committer: Jorge O. Castro
  • Date: 2007-12-03 06:56:46 UTC
  • Revision ID: jorge@ubuntu.com-20071203065646-mupcnjcwgm5mnhyt
* Remove a bunch of .svn directories we no longer need.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#region Copyright & License
2
 
//
3
 
// Copyright 2001-2005 The Apache Software Foundation
4
 
//
5
 
// Licensed under the Apache License, Version 2.0 (the "License");
6
 
// you may not use this file except in compliance with the License.
7
 
// You may obtain a copy of the License at
8
 
//
9
 
// http://www.apache.org/licenses/LICENSE-2.0
10
 
//
11
 
// Unless required by applicable law or agreed to in writing, software
12
 
// distributed under the License is distributed on an "AS IS" BASIS,
13
 
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
 
// See the License for the specific language governing permissions and
15
 
// limitations under the License.
16
 
//
17
 
#endregion
18
 
 
19
 
// .NET Compact Framework 1.0 has no support for System.Runtime.Remoting
20
 
#if !NETCF
21
 
 
22
 
using System;
23
 
using System.Collections;
24
 
using System.Threading;
25
 
 
26
 
using System.Runtime.Remoting.Messaging;
27
 
 
28
 
using log4net.Layout;
29
 
using log4net.Core;
30
 
using log4net.Util;
31
 
 
32
 
namespace log4net.Appender
33
 
{
34
 
        /// <summary>
35
 
        /// Delivers logging events to a remote logging sink. 
36
 
        /// </summary>
37
 
        /// <remarks>
38
 
        /// <para>
39
 
        /// This Appender is designed to deliver events to a remote sink. 
40
 
        /// That is any object that implements the <see cref="IRemoteLoggingSink"/>
41
 
        /// interface. It delivers the events using .NET remoting. The
42
 
        /// object to deliver events to is specified by setting the
43
 
        /// appenders <see cref="RemotingAppender.Sink"/> property.</para>
44
 
        /// <para>
45
 
        /// The RemotingAppender buffers events before sending them. This allows it to 
46
 
        /// make more efficient use of the remoting infrastructure.</para>
47
 
        /// <para>
48
 
        /// Once the buffer is full the events are still not sent immediately. 
49
 
        /// They are scheduled to be sent using a pool thread. The effect is that 
50
 
        /// the send occurs asynchronously. This is very important for a 
51
 
        /// number of non obvious reasons. The remoting infrastructure will 
52
 
        /// flow thread local variables (stored in the <see cref="CallContext"/>),
53
 
        /// if they are marked as <see cref="ILogicalThreadAffinative"/>, across the 
54
 
        /// remoting boundary. If the server is not contactable then
55
 
        /// the remoting infrastructure will clear the <see cref="ILogicalThreadAffinative"/>
56
 
        /// objects from the <see cref="CallContext"/>. To prevent a logging failure from
57
 
        /// having side effects on the calling application the remoting call must be made
58
 
        /// from a separate thread to the one used by the application. A <see cref="ThreadPool"/>
59
 
        /// thread is used for this. If no <see cref="ThreadPool"/> thread is available then
60
 
        /// the events will block in the thread pool manager until a thread is available.</para>
61
 
        /// <para>
62
 
        /// Because the events are sent asynchronously using pool threads it is possible to close 
63
 
        /// this appender before all the queued events have been sent.
64
 
        /// When closing the appender attempts to wait until all the queued events have been sent, but 
65
 
        /// this will timeout after 30 seconds regardless.</para>
66
 
        /// <para>
67
 
        /// If this appender is being closed because the <see cref="AppDomain.ProcessExit"/>
68
 
        /// event has fired it may not be possible to send all the queued events. During process
69
 
        /// exit the runtime limits the time that a <see cref="AppDomain.ProcessExit"/>
70
 
        /// event handler is allowed to run for. If the runtime terminates the threads before
71
 
        /// the queued events have been sent then they will be lost. To ensure that all events
72
 
        /// are sent the appender must be closed before the application exits. See 
73
 
        /// <see cref="log4net.Core.LoggerManager.Shutdown"/> for details on how to shutdown
74
 
        /// log4net programmatically.</para>
75
 
        /// </remarks>
76
 
        /// <seealso cref="IRemoteLoggingSink" />
77
 
        /// <author>Nicko Cadell</author>
78
 
        /// <author>Gert Driesen</author>
79
 
        /// <author>Daniel Cazzulino</author>
80
 
        public class RemotingAppender : BufferingAppenderSkeleton
81
 
        {
82
 
                #region Public Instance Constructors
83
 
 
84
 
                /// <summary>
85
 
                /// Initializes a new instance of the <see cref="RemotingAppender" /> class.
86
 
                /// </summary>
87
 
                /// <remarks>
88
 
                /// <para>
89
 
                /// Default constructor.
90
 
                /// </para>
91
 
                /// </remarks>
92
 
                public RemotingAppender()
93
 
                {
94
 
                }
95
 
 
96
 
                #endregion Public Instance Constructors
97
 
 
98
 
                #region Public Instance Properties
99
 
 
100
 
                /// <summary>
101
 
                /// Gets or sets the URL of the well-known object that will accept 
102
 
                /// the logging events.
103
 
                /// </summary>
104
 
                /// <value>
105
 
                /// The well-known URL of the remote sink.
106
 
                /// </value>
107
 
                /// <remarks>
108
 
                /// <para>
109
 
                /// The URL of the remoting sink that will accept logging events.
110
 
                /// The sink must implement the <see cref="IRemoteLoggingSink"/>
111
 
                /// interface.
112
 
                /// </para>
113
 
                /// </remarks>
114
 
                public string Sink
115
 
                {
116
 
                        get { return m_sinkUrl; }
117
 
                        set { m_sinkUrl = value; }
118
 
                }
119
 
 
120
 
                #endregion Public Instance Properties
121
 
 
122
 
                #region Implementation of IOptionHandler
123
 
 
124
 
                /// <summary>
125
 
                /// Initialize the appender based on the options set
126
 
                /// </summary>
127
 
                /// <remarks>
128
 
                /// <para>
129
 
                /// This is part of the <see cref="IOptionHandler"/> delayed object
130
 
                /// activation scheme. The <see cref="ActivateOptions"/> method must 
131
 
                /// be called on this object after the configuration properties have
132
 
                /// been set. Until <see cref="ActivateOptions"/> is called this
133
 
                /// object is in an undefined state and must not be used. 
134
 
                /// </para>
135
 
                /// <para>
136
 
                /// If any of the configuration properties are modified then 
137
 
                /// <see cref="ActivateOptions"/> must be called again.
138
 
                /// </para>
139
 
                /// </remarks>
140
 
                override public void ActivateOptions() 
141
 
                {
142
 
                        base.ActivateOptions();
143
 
 
144
 
                        IDictionary channelProperties = new Hashtable(); 
145
 
                        channelProperties["typeFilterLevel"] = "Full";
146
 
 
147
 
                        m_sinkObj = (IRemoteLoggingSink)Activator.GetObject(typeof(IRemoteLoggingSink), m_sinkUrl, channelProperties);
148
 
                }
149
 
 
150
 
                #endregion
151
 
 
152
 
                #region Override implementation of BufferingAppenderSkeleton
153
 
 
154
 
                /// <summary>
155
 
                /// Send the contents of the buffer to the remote sink.
156
 
                /// </summary>
157
 
                /// <remarks>
158
 
                /// The events are not sent immediately. They are scheduled to be sent
159
 
                /// using a pool thread. The effect is that the send occurs asynchronously.
160
 
                /// This is very important for a number of non obvious reasons. The remoting
161
 
                /// infrastructure will flow thread local variables (stored in the <see cref="CallContext"/>),
162
 
                /// if they are marked as <see cref="ILogicalThreadAffinative"/>, across the 
163
 
                /// remoting boundary. If the server is not contactable then
164
 
                /// the remoting infrastructure will clear the <see cref="ILogicalThreadAffinative"/>
165
 
                /// objects from the <see cref="CallContext"/>. To prevent a logging failure from
166
 
                /// having side effects on the calling application the remoting call must be made
167
 
                /// from a separate thread to the one used by the application. A <see cref="ThreadPool"/>
168
 
                /// thread is used for this. If no <see cref="ThreadPool"/> thread is available then
169
 
                /// the events will block in the thread pool manager until a thread is available.
170
 
                /// </remarks>
171
 
                /// <param name="events">The events to send.</param>
172
 
                override protected void SendBuffer(LoggingEvent[] events)
173
 
                {
174
 
                        // Setup for an async send
175
 
                        BeginAsyncSend();
176
 
 
177
 
                        // Send the events
178
 
                        if (!ThreadPool.QueueUserWorkItem(new WaitCallback(SendBufferCallback), events))
179
 
                        {
180
 
                                // Cancel the async send
181
 
                                EndAsyncSend();
182
 
 
183
 
                                ErrorHandler.Error("RemotingAppender ["+Name+"] failed to ThreadPool.QueueUserWorkItem logging events in SendBuffer.");
184
 
                        }
185
 
                }
186
 
 
187
 
                /// <summary>
188
 
                /// Override base class close.
189
 
                /// </summary>
190
 
                /// <remarks>
191
 
                /// <para>
192
 
                /// This method waits while there are queued work items. The events are
193
 
                /// sent asynchronously using <see cref="ThreadPool"/> work items. These items
194
 
                /// will be sent once a thread pool thread is available to send them, therefore
195
 
                /// it is possible to close the appender before all the queued events have been
196
 
                /// sent.</para>
197
 
                /// <para>
198
 
                /// This method attempts to wait until all the queued events have been sent, but this 
199
 
                /// method will timeout after 30 seconds regardless.</para>
200
 
                /// <para>
201
 
                /// If the appender is being closed because the <see cref="AppDomain.ProcessExit"/>
202
 
                /// event has fired it may not be possible to send all the queued events. During process
203
 
                /// exit the runtime limits the time that a <see cref="AppDomain.ProcessExit"/>
204
 
                /// event handler is allowed to run for.</para>
205
 
                /// </remarks>
206
 
                override protected void OnClose()
207
 
                {
208
 
                        base.OnClose();
209
 
 
210
 
                        // Wait for the work queue to become empty before closing, timeout 30 seconds
211
 
                        if (!m_workQueueEmptyEvent.WaitOne(30 * 1000, false))
212
 
                        {
213
 
                                ErrorHandler.Error("RemotingAppender ["+Name+"] failed to send all queued events before close, in OnClose.");
214
 
                        }
215
 
                }
216
 
 
217
 
                #endregion
218
 
 
219
 
                /// <summary>
220
 
                /// A work item is being queued into the thread pool
221
 
                /// </summary>
222
 
                private void BeginAsyncSend()
223
 
                {
224
 
                        // The work queue is not empty
225
 
                        m_workQueueEmptyEvent.Reset();
226
 
 
227
 
                        // Increment the queued count
228
 
                        Interlocked.Increment(ref m_queuedCallbackCount);
229
 
                }
230
 
 
231
 
                /// <summary>
232
 
                /// A work item from the thread pool has completed
233
 
                /// </summary>
234
 
                private void EndAsyncSend()
235
 
                {
236
 
                        // Decrement the queued count
237
 
                        if (Interlocked.Decrement(ref m_queuedCallbackCount) <= 0)
238
 
                        {
239
 
                                // If the work queue is empty then set the event
240
 
                                m_workQueueEmptyEvent.Set();
241
 
                        }
242
 
                }
243
 
 
244
 
                /// <summary>
245
 
                /// Send the contents of the buffer to the remote sink.
246
 
                /// </summary>
247
 
                /// <remarks>
248
 
                /// This method is designed to be used with the <see cref="ThreadPool"/>.
249
 
                /// This method expects to be passed an array of <see cref="LoggingEvent"/>
250
 
                /// objects in the state param.
251
 
                /// </remarks>
252
 
                /// <param name="state">the logging events to send</param>
253
 
                private void SendBufferCallback(object state)
254
 
                {
255
 
                        try
256
 
                        {
257
 
                                LoggingEvent[] events = (LoggingEvent[])state;
258
 
 
259
 
                                // Send the events
260
 
                                m_sinkObj.LogEvents(events);
261
 
                        }
262
 
                        catch(Exception ex)
263
 
                        {
264
 
                                ErrorHandler.Error("Failed in SendBufferCallback", ex);
265
 
                        }
266
 
                        finally
267
 
                        {
268
 
                                EndAsyncSend();
269
 
                        }
270
 
                }
271
 
 
272
 
                #region Private Instance Fields
273
 
 
274
 
                /// <summary>
275
 
                /// The URL of the remote sink.
276
 
                /// </summary>
277
 
                private string m_sinkUrl;
278
 
 
279
 
                /// <summary>
280
 
                /// The local proxy (.NET remoting) for the remote logging sink.
281
 
                /// </summary>
282
 
                private IRemoteLoggingSink m_sinkObj;
283
 
 
284
 
                /// <summary>
285
 
                /// The number of queued callbacks currently waiting or executing
286
 
                /// </summary>
287
 
                private int m_queuedCallbackCount = 0;
288
 
 
289
 
                /// <summary>
290
 
                /// Event used to signal when there are no queued work items
291
 
                /// </summary>
292
 
                /// <remarks>
293
 
                /// This event is set when there are no queued work items. In this
294
 
                /// state it is safe to close the appender.
295
 
                /// </remarks>
296
 
                private ManualResetEvent m_workQueueEmptyEvent = new ManualResetEvent(true);
297
 
 
298
 
                #endregion Private Instance Fields
299
 
 
300
 
                /// <summary>
301
 
                /// Interface used to deliver <see cref="LoggingEvent"/> objects to a remote sink.
302
 
                /// </summary>
303
 
                /// <remarks>
304
 
                /// This interface must be implemented by a remoting sink
305
 
                /// if the <see cref="RemotingAppender"/> is to be used
306
 
                /// to deliver logging events to the sink.
307
 
                /// </remarks>
308
 
                public interface IRemoteLoggingSink
309
 
                {
310
 
                        /// <summary>
311
 
                        /// Delivers logging events to the remote sink
312
 
                        /// </summary>
313
 
                        /// <param name="events">Array of events to log.</param>
314
 
                        /// <remarks>
315
 
                        /// <para>
316
 
                        /// Delivers logging events to the remote sink
317
 
                        /// </para>
318
 
                        /// </remarks>
319
 
                        void LogEvents(LoggingEvent[] events);
320
 
                }
321
 
        }
322
 
}
323
 
 
324
 
#endif // !NETCF
 
 
b'\\ No newline at end of file'