private void NotifyTrafficWatch(string resourceName, TrafficWatchNotification trafficWatchNotification) { object notificationMessage = new { Type = "LogNotification", Value = trafficWatchNotification }; if (serverHttpTrace.Count > 0) { foreach (var eventsTransport in serverHttpTrace) { eventsTransport.SendAsync(notificationMessage); } } if (resourceHttpTraces.Count > 0) { ConcurrentSet <IEventsTransport> resourceEventTransports; if (!resourceHttpTraces.TryGetValue(resourceName, out resourceEventTransports) || resourceEventTransports.Count == 0) { return; } foreach (var eventTransport in resourceEventTransports) { eventTransport.SendAsync(notificationMessage); } } }
private ArraySegment <byte> ToByteArraySegment(TrafficWatchNotification notification) { var json = new DynamicJsonValue { ["TimeStamp"] = notification.TimeStamp, ["RequestId"] = notification.RequestId, ["HttpMethod"] = notification.HttpMethod, ["ElapsedMilliseconds"] = notification.ElapsedMilliseconds, ["ResponseStatusCode"] = notification.ResponseStatusCode, ["RequestUri"] = notification.RequestUri, ["AbsoluteUri"] = notification.AbsoluteUri, ["TenantName"] = notification.TenantName, ["CustomInfo"] = notification.CustomInfo, ["InnerRequestsCount"] = notification.InnerRequestsCount, //["QueryTimings"] = notification.QueryTimings // TODO :: implement this }; _bufferStream.SetLength(0); JsonOperationContext context; using (_jsonContextPool.AllocateOperationContext(out context)) using (var writer = new BlittableJsonTextWriter(context, _bufferStream)) { context.Write(writer, json); writer.Flush(); ArraySegment <byte> bytes; _bufferStream.TryGetBuffer(out bytes); return(bytes); } }
public static void DispatchMessage(TrafficWatchNotification trafficWatchData) { foreach (var connection in ServerHttpTrace) { if (connection.IsAlive == false) { ServerHttpTrace.TryRemove(connection); continue; } if (connection.TenantSpecific != null) { if (string.Equals(connection.TenantSpecific, trafficWatchData.TenantName, StringComparison.OrdinalIgnoreCase) == false) { continue; } } connection.EnqueMsg(trafficWatchData); } }
private async Task RequestHandler(HttpContext context) { try { context.Response.StatusCode = 200; var sp = Stopwatch.StartNew(); var tenant = await _router.HandlePath(context, context.Request.Method, context.Request.Path.Value); sp.Stop(); if (_logger.IsInfoEnabled) { _logger.Info($"{context.Request.Method} {context.Request.Path.Value}?{context.Request.QueryString.Value} - {context.Response.StatusCode} - {sp.ElapsedMilliseconds:#,#;;0} ms"); } if (TrafficWatchManager.HasRegisteredClients) { var requestId = Interlocked.Increment(ref _requestId); var twn = new TrafficWatchNotification { TimeStamp = DateTime.UtcNow, RequestId = requestId, // counted only for traffic watch HttpMethod = context.Request.Method ?? "N/A", // N/A ? ElapsedMilliseconds = sp.ElapsedMilliseconds, ResponseStatusCode = context.Response.StatusCode, RequestUri = context.Request.GetEncodedUrl(), AbsoluteUri = $@"{context.Request.Scheme}://{context.Request.Host}", TenantName = tenant ?? "N/A", CustomInfo = "", // TODO: Implement InnerRequestsCount = 0, // TODO: Implement QueryTimings = null, // TODO: Implement }; TrafficWatchManager.DispatchMessage(twn); } } catch (Exception e) { if (context.RequestAborted.IsCancellationRequested) { return; } //TODO: special handling for argument exception (400 bad request) //TODO: database not found (503) //TODO: operaton cancelled (timeout) //TODO: Invalid data exception 422 //TODO: Proper json output, not like this var response = context.Response; var documentConflictException = e as DocumentConflictException; if (response.HasStarted == false) { if (documentConflictException != null) { response.StatusCode = 409; } else if (response.StatusCode < 400) { response.StatusCode = 500; } } JsonOperationContext ctx; using (_server.ServerStore.ContextPool.AllocateOperationContext(out ctx)) { var djv = new DynamicJsonValue { ["Url"] = $"{context.Request.Path}?{context.Request.QueryString}", ["Type"] = e.GetType().FullName, ["Message"] = e.Message }; string errorString; try { errorString = e.ToAsyncString(); } catch (Exception) { errorString = e.ToString(); } djv["Error"] = errorString; var indexCompilationException = e as IndexCompilationException; if (indexCompilationException != null) { djv[nameof(IndexCompilationException.IndexDefinitionProperty)] = indexCompilationException.IndexDefinitionProperty; djv[nameof(IndexCompilationException.ProblematicText)] = indexCompilationException.ProblematicText; } if (documentConflictException != null) { djv["ConflictInfo"] = ReplicationUtils.GetJsonForConflicts( documentConflictException.DocId, documentConflictException.Conflicts); } using (var writer = new BlittableJsonTextWriter(ctx, response.Body)) { var json = ctx.ReadObject(djv, "exception"); writer.WriteObject(json); } } } }
/// <summary> /// Connects to raven traffic event source and registers all the requests to the file defined in the config /// </summary> /// <param name="config">configuration conatining the connection, the file to write to, etc.</param> /// <param name="store">the store to work with</param> private async Task RecordRequests(TrafficToolConfiguration config, IDocumentStore store) { var id = Guid.NewGuid().ToString(); using (var client = new RavenClientWebSocket()) { var url = store.Url + "/traffic-watch/websockets"; var uri = new Uri(url.ToWebSocketPath()); await client.ConnectAsync(uri, CancellationToken.None) .ConfigureAwait(false); // record traffic no more then 7 days var day = 24 * 60 * 60; var timeout = (int)config.Timeout.TotalMilliseconds / 1000; timeout = Math.Min(timeout, 7 * day); if (timeout <= 0) { timeout = 7 * day; } try { string resourceName = config.ResourceName ?? "N/A"; var connectMessage = new DynamicJsonValue { ["Id"] = id, ["ResourceName"] = resourceName, ["Timeout"] = timeout }; var stream = new MemoryStream(); JsonOperationContext context; using (_jsonContextPool.AllocateOperationContext(out context)) using (var writer = new BlittableJsonTextWriter(context, stream)) { context.Write(writer, connectMessage); writer.Flush(); ArraySegment <byte> bytes; stream.TryGetBuffer(out bytes); await client.SendAsync(bytes, WebSocketMessageType.Text, true, CancellationToken.None) .ConfigureAwait(false); } var requestsCounter = 0; using (var fileStream = File.Create(config.RecordFilePath)) { Stream finalStream = fileStream; if (config.IsCompressed) { finalStream = new GZipStream(fileStream, CompressionMode.Compress, leaveOpen: true); } using (var streamWriter = new StreamWriter(finalStream)) { var jsonWriter = new JsonTextWriter(streamWriter) { Formatting = Formatting.Indented }; jsonWriter.WriteStartArray(); var sp = Stopwatch.StartNew(); while (true) { using (var reader = await Receive(client, context)) { if (reader == null) { // server asked to close connection break; } string type; if (reader.TryGet("Type", out type)) { if (type.Equals("Heartbeat")) { continue; } } string error; if (reader.TryGet("Error", out error)) { throw new InvalidOperationException("Server returned error: " + error); } var notification = new TrafficWatchNotification(); notification.TimeStamp = GetDateTimeFromJson(reader, "TimeStamp"); notification.RequestId = GetIntFromJson(reader, "RequestId"); notification.HttpMethod = GetStringFromJson(reader, "HttpMethod"); notification.ElapsedMilliseconds = GetIntFromJson(reader, "ElapsedMilliseconds"); notification.ResponseStatusCode = GetIntFromJson(reader, "ResponseStatusCode"); notification.TenantName = GetStringFromJson(reader, "TenantName"); notification.CustomInfo = GetStringFromJson(reader, "CustomInfo"); notification.InnerRequestsCount = GetIntFromJson(reader, "InnerRequestsCount"); // notification.QueryTimings = GetRavenJObjectFromJson(reader, "QueryTimings"); // TODO (TrafficWatch) : Handle this both server and client sides if (config.PrintOutput) { Console.Write("\rRequest #{0} Stored...\t\t ", ++requestsCounter); } var jobj = RavenJObject.FromObject(notification); jobj.WriteTo(jsonWriter); if (sp.ElapsedMilliseconds > 5000) { streamWriter.Flush(); sp.Restart(); } } } jsonWriter.WriteEndArray(); streamWriter.Flush(); if (config.IsCompressed) { finalStream.Dispose(); } } } } catch (Exception ex) { Console.WriteLine("\r\n\nError while reading messages from server : " + ex); } finally { Console.WriteLine("\r\n\nClosing connection to server...`"); try { await client.CloseAsync(WebSocketCloseStatus.NormalClosure, "CLOSE_NORMAL", CancellationToken.None) .ConfigureAwait(false); } catch { // ignored } } } }
public void EnqueMsg(TrafficWatchNotification msg) { _msgs.Enqueue(msg); _manualResetEvent.Set(); }