/// <summary> /// Get logs. /// </summary> /// <param name="resourceUri">The resourceUri</param> /// <param name="filterString">The filter string</param> /// <param name="definitions">The log definitions</param> /// <param name="cancellationToken">The cancellation token</param> /// <returns></returns> public async Task<LogListResponse> GetLogsAsync( string resourceUri, string filterString, IEnumerable<LogDefinition> definitions, CancellationToken cancellationToken) { if (definitions == null) { throw new ArgumentNullException("definitions"); } if (resourceUri == null) { throw new ArgumentNullException("resourceUri"); } // Ensure exactly one '/' at the start resourceUri = '/' + resourceUri.TrimStart('/'); LogListResponse result; string invocationId = TracingAdapter.NextInvocationId.ToString(CultureInfo.InvariantCulture); // If no definitions provided, return empty collection if (!definitions.Any()) { this.LogStartGetLogs(invocationId, resourceUri, filterString, definitions); result = new LogListResponse() { RequestId = Guid.NewGuid().ToString("D"), StatusCode = HttpStatusCode.OK, LogCollection = new LogCollection() { Value = new Log[0] } }; this.LogEndGetLogs(invocationId, result); return result; } // Parse LogFilter. Reusing the metric filter. // We might consider extracting the parsing functionality to a class with a less specific name MetricFilter filter = MetricFilterExpressionParser.Parse(filterString, false); if (filter.StartTime == default(DateTime)) { throw new InvalidOperationException("startTime is required"); } if (filter.EndTime == default(DateTime)) { throw new InvalidOperationException("endTime is required"); } this.LogStartGetLogs(invocationId, resourceUri, filterString, definitions); var logsPerBlob = new Dictionary<string, Task<Log>>(StringComparer.OrdinalIgnoreCase); // We download all the relevant blobs first and then use the data later, to avoid download the same blob more than once. foreach (LogDefinition logDefinition in definitions) { foreach (BlobInfo blobInfo in logDefinition.BlobLocation.BlobInfo) { if (blobInfo.EndTime < filter.StartTime || blobInfo.StartTime >= filter.EndTime) { continue; } string blobId = GetBlobEndpoint(blobInfo); if (!logsPerBlob.ContainsKey(blobId)) { logsPerBlob.Add(blobId, FetchLogFromBlob(blobInfo.BlobUri, filter, logDefinition.Category)); } } } foreach (var task in logsPerBlob.Values) { await task; } var logsPerCategory = new Dictionary<string, Log>(); foreach (var task in logsPerBlob.Values) { Log log = task.Result; Log existingLog; if (logsPerCategory.TryGetValue(log.Category.Value, out existingLog)) { ((List<LogValue>)existingLog.Value).AddRange(log.Value); existingLog.StartTime = this.Min(log.StartTime, existingLog.StartTime); existingLog.EndTime = this.Max(log.StartTime, existingLog.StartTime); } else { logsPerCategory.Add(log.Category.Value, log); } } result = new LogListResponse { RequestId = Guid.NewGuid().ToString("D"), StatusCode = HttpStatusCode.OK, LogCollection = new LogCollection { Value = logsPerCategory.Values.ToList() } }; this.LogEndGetLogs(invocationId, result); return result; }
private void LogEndGetLogs(string invocationId, LogListResponse result) { if (TracingAdapter.IsEnabled) { TracingAdapter.Exit(invocationId, result); } }