http://blogs.technet.com/b/meamcs/archive/2013/05/23/diagnostics-of-cloud-services-custom-trace-listener.aspx과 비슷한 TraceListener를 구현했습니다.Azure 진단에서 사용자 지정 로그를 기록하고 scheduledTransferPeriod를 기리고
내가 알아챈 한 가지는 로그가 My Azure Table Storage에 바로 표시된다는 것입니다. Custom Trace Listeners로 기대되는지, 아니면 개발 환경에 있기 때문에 궁금합니다.
내 diagnosics.wadcfg는
<?xml version="1.0" encoding="utf-8"?>
<DiagnosticMonitorConfiguration configurationChangePollInterval="PT1M""overallQuotaInMB="4096" xmlns="http://schemas.microsoft.com/ServiceHosting/2010/10/DiagnosticsConfiguration">
<DiagnosticInfrastructureLogs scheduledTransferLogLevelFilter="Information" />
<Directories scheduledTransferPeriod="PT1M">
<IISLogs container="wad-iis-logfiles" />
<CrashDumps container="wad-crash-dumps" />
</Directories>
<Logs bufferQuotaInMB="0" scheduledTransferPeriod="PT30M" scheduledTransferLogLevelFilter="Information" />
</DiagnosticMonitorConfiguration>
내을 약간 변경되었습니다. 이제 웹에서 내 webrole의 구성을 정의하고 있습니다. webconfig에서 autoflush를 true로 설정하면 모든 것이 작동하지만 flush 메서드가 테이블 저장소에 푸시하기 때문에 scheduledTransferPeriod가 적용되지 않습니다. scheduleTransferPeriod를 사용하여 버퍼가 가득 찬 것처럼 일정 수의 로그 항목이 플러시되거나 트리거되도록하십시오. 그런 다음 서버 종료시에도 플러시 할 수 있습니다. ScheduleTransferPeriod를 수신 할 수있는 CustomTraceListener에 메서드 나 이벤트가 있습니까?
<system.diagnostics>
<!--http://msdn.microsoft.com/en-us/library/sk36c28t(v=vs.110).aspx
By default autoflush is false.
By default useGlobalLock is true. While we try to be threadsafe, we keep this default for now. Later if we would like to increase performance we can remove this. see http://msdn.microsoft.com/en-us/library/system.diagnostics.trace.usegloballock(v=vs.110).aspx -->
<trace>
<listeners>
<add name="TableTraceListener"
type="Pos.Services.Implementation.TableTraceListener, Pos.Services.Implementation"
/>
<remove name="Default" />
</listeners>
</trace>
</system.diagnostics>
나는 다음에 사용자 지정 추적 수신기를 수정 :
namespace Pos.Services.Implementation
{
class TableTraceListener : TraceListener
{
#region Fields
//connection string for azure storage
readonly string _connectionString;
//Custom sql storage table for logs.
//TODO put in config
readonly string _diagnosticsTable;
[ThreadStatic]
static StringBuilder _messageBuffer;
readonly object _initializationSection = new object();
bool _isInitialized;
CloudTableClient _tableStorage;
readonly object _traceLogAccess = new object();
readonly List<LogEntry> _traceLog = new List<LogEntry>();
#endregion
#region Constructors
public TableTraceListener() : base("TableTraceListener")
{
_connectionString = RoleEnvironment.GetConfigurationSettingValue("DiagConnection");
_diagnosticsTable = RoleEnvironment.GetConfigurationSettingValue("DiagTableName");
}
#endregion
#region Methods
/// <summary>
/// Flushes the entries to the storage table
/// </summary>
public override void Flush()
{
if (!_isInitialized)
{
lock (_initializationSection)
{
if (!_isInitialized)
{
Initialize();
}
}
}
var context = _tableStorage.GetTableServiceContext();
context.MergeOption = MergeOption.AppendOnly;
lock (_traceLogAccess)
{
_traceLog.ForEach(entry => context.AddObject(_diagnosticsTable, entry));
_traceLog.Clear();
}
if (context.Entities.Count > 0)
{
context.BeginSaveChangesWithRetries(SaveChangesOptions.None, (ar) => context.EndSaveChangesWithRetries(ar), null);
}
}
/// <summary>
/// Creates the storage table object. This class does not need to be locked because the caller is locked.
/// </summary>
private void Initialize()
{
var account = CloudStorageAccount.Parse(_connectionString);
_tableStorage = account.CreateCloudTableClient();
_tableStorage.GetTableReference(_diagnosticsTable).CreateIfNotExists();
_isInitialized = true;
}
public override bool IsThreadSafe
{
get
{
return true;
}
}
#region Trace and Write Methods
/// <summary>
/// Writes the message to a string buffer
/// </summary>
/// <param name="message">the Message</param>
public override void Write(string message)
{
if (_messageBuffer == null)
_messageBuffer = new StringBuilder();
_messageBuffer.Append(message);
}
/// <summary>
/// Writes the message with a line breaker to a string buffer
/// </summary>
/// <param name="message"></param>
public override void WriteLine(string message)
{
if (_messageBuffer == null)
_messageBuffer = new StringBuilder();
_messageBuffer.AppendLine(message);
}
/// <summary>
/// Appends the trace information and message
/// </summary>
/// <param name="eventCache">the Event Cache</param>
/// <param name="source">the Source</param>
/// <param name="eventType">the Event Type</param>
/// <param name="id">the Id</param>
/// <param name="message">the Message</param>
public override void TraceEvent(TraceEventCache eventCache, string source, TraceEventType eventType, int id, string message)
{
base.TraceEvent(eventCache, source, eventType, id, message);
AppendEntry(id, eventType, eventCache);
}
/// <summary>
/// Adds the trace information to a collection of LogEntry objects
/// </summary>
/// <param name="id">the Id</param>
/// <param name="eventType">the Event Type</param>
/// <param name="eventCache">the EventCache</param>
private void AppendEntry(int id, TraceEventType eventType, TraceEventCache eventCache)
{
if (_messageBuffer == null)
_messageBuffer = new StringBuilder();
var message = _messageBuffer.ToString();
_messageBuffer.Length = 0;
if (message.EndsWith(Environment.NewLine))
message = message.Substring(0, message.Length - Environment.NewLine.Length);
if (message.Length == 0)
return;
var entry = new LogEntry()
{
PartitionKey = string.Format("{0:D10}", eventCache.Timestamp >> 30),
RowKey = string.Format("{0:D19}", eventCache.Timestamp),
EventTickCount = eventCache.Timestamp,
Level = (int)eventType,
EventId = id,
Pid = eventCache.ProcessId,
Tid = eventCache.ThreadId,
Message = message
};
lock (_traceLogAccess)
_traceLog.Add(entry);
}
#endregion
#endregion
}
}
Autoflush를 true로 설정하여 매번 푸시하고있었습니다. http://msdn.microsoft.com/en-us/library/system.diagnostics.trace.autoflush(v=vs.110).aspx. – kjsteuer
그러나 auto flush를 false로 설정하면 Flush 메서드가 호출되지 않습니다. 누구 플러시를 트리거 해야하는지 아는 사람 있습니까? – kjsteuer
질문 자체에 코드를 포함시켜 공유 할 수 있습니까? 블로그 게시물에서 flush 메서드는 수동으로 호출됩니다. –