private ArraySegment <byte> ToByteArraySegment(TrafficWatchChange change) { var json = new DynamicJsonValue { [nameof(change.TimeStamp)] = change.TimeStamp, [nameof(change.RequestId)] = change.RequestId, [nameof(change.HttpMethod)] = change.HttpMethod, [nameof(change.ElapsedMilliseconds)] = change.ElapsedMilliseconds, [nameof(change.ResponseStatusCode)] = change.ResponseStatusCode, [nameof(change.RequestUri)] = change.RequestUri, [nameof(change.AbsoluteUri)] = change.AbsoluteUri, [nameof(change.DatabaseName)] = change.DatabaseName, [nameof(change.CustomInfo)] = change.CustomInfo, [nameof(change.InnerRequestsCount)] = change.InnerRequestsCount //[nameof(change.QueryTimings)] = notification.QueryTimings }; _bufferStream.SetLength(0); using (_jsonContextPool.AllocateOperationContext(out JsonOperationContext context)) using (var writer = new BlittableJsonTextWriter(context, _bufferStream)) { context.Write(writer, json); writer.Flush(); _bufferStream.TryGetBuffer(out ArraySegment <byte> bytes); return(bytes); } }
private ArraySegment <byte> ToByteArraySegment(TrafficWatchChange change) { var json = new DynamicJsonValue { [nameof(change.TimeStamp)] = change.TimeStamp, [nameof(change.RequestId)] = change.RequestId, [nameof(change.HttpMethod)] = change.HttpMethod, [nameof(change.ElapsedMilliseconds)] = change.ElapsedMilliseconds, [nameof(change.ResponseStatusCode)] = change.ResponseStatusCode, [nameof(change.RequestUri)] = change.RequestUri, [nameof(change.AbsoluteUri)] = change.AbsoluteUri, [nameof(change.DatabaseName)] = change.DatabaseName, [nameof(change.CustomInfo)] = change.CustomInfo, [nameof(change.Type)] = change.Type, [nameof(change.ClientIP)] = change.ClientIP }; _bufferStream.SetLength(0); using (var writer = new BlittableJsonTextWriter(_context, _bufferStream)) { _context.Write(writer, json); writer.Flush(); _bufferStream.TryGetBuffer(out var bytes); return(bytes); } }
/// <summary> /// LogTrafficWatch gets HttpContext, elapsed time and database name /// </summary> /// <param name="context"></param> /// <param name="elapsedMilliseconds"></param> /// <param name="database"></param> private void LogTrafficWatch(HttpContext context, long elapsedMilliseconds, string database) { var requestId = Interlocked.Increment(ref _requestId); var contextItem = context.Items["TrafficWatch"]; (string CustomInfo, TrafficWatchChangeType Type)twTuple = ((string, TrafficWatchChangeType)?)contextItem ?? ("N/A", TrafficWatchChangeType.None); var twn = new TrafficWatchChange { TimeStamp = DateTime.UtcNow, RequestId = requestId, // counted only for traffic watch HttpMethod = context.Request.Method ?? "N/A", // N/A ? ElapsedMilliseconds = elapsedMilliseconds, ResponseStatusCode = context.Response.StatusCode, RequestUri = context.Request.GetEncodedUrl(), AbsoluteUri = $"{context.Request.Scheme}://{context.Request.Host}", DatabaseName = database ?? "N/A", CustomInfo = twTuple.CustomInfo, Type = twTuple.Type, InnerRequestsCount = 0, QueryTimings = null }; TrafficWatchManager.DispatchMessage(twn); }
private ArraySegment <byte> ToByteArraySegment(TrafficWatchChange change) { var json = new DynamicJsonValue { ["TimeStamp"] = change.TimeStamp, ["RequestId"] = change.RequestId, ["HttpMethod"] = change.HttpMethod, ["ElapsedMilliseconds"] = change.ElapsedMilliseconds, ["ResponseStatusCode"] = change.ResponseStatusCode, ["RequestUri"] = change.RequestUri, ["AbsoluteUri"] = change.AbsoluteUri, ["TenantName"] = change.TenantName, ["CustomInfo"] = change.CustomInfo, ["InnerRequestsCount"] = change.InnerRequestsCount //["QueryTimings"] = notification.QueryTimings // TODO :: implement this }; _bufferStream.SetLength(0); using (_jsonContextPool.AllocateOperationContext(out JsonOperationContext context)) using (var writer = new BlittableJsonTextWriter(context, _bufferStream)) { context.Write(writer, json); writer.Flush(); _bufferStream.TryGetBuffer(out ArraySegment <byte> bytes); return(bytes); } }
public static void DispatchMessage(TrafficWatchChange trafficWatchData) { foreach (var connection in ServerHttpTrace) { if (connection.IsAlive == false) { Disconnect(connection); continue; } if (connection.TenantSpecific != null) { if (string.Equals(connection.TenantSpecific, trafficWatchData.DatabaseName, StringComparison.OrdinalIgnoreCase) == false) { continue; } } connection.EnqueMsg(trafficWatchData); } }
private void LogTrafficWatch(HttpContext context, long elapsedMilliseconds, string database) { var requestId = Interlocked.Increment(ref _requestId); var twn = new TrafficWatchChange { TimeStamp = DateTime.UtcNow, RequestId = requestId, // counted only for traffic watch HttpMethod = context.Request.Method ?? "N/A", // N/A ? ElapsedMilliseconds = elapsedMilliseconds, ResponseStatusCode = context.Response.StatusCode, RequestUri = context.Request.GetEncodedUrl(), AbsoluteUri = $@"{context.Request.Scheme}://{context.Request.Host}", DatabaseName = database ?? "N/A", CustomInfo = "", // TODO: Implement InnerRequestsCount = 0, // TODO: Implement QueryTimings = null // TODO: Implement }; TrafficWatchManager.DispatchMessage(twn); }
/// <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 ClientWebSocket()) { var url = store.Urls.First() + "/admin/traffic-watch"; 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, ["DatabaseName"] = 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 TrafficWatchChange(); 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 = JObject.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(TrafficWatchChange msg) { _msgs.Enqueue(msg); _manualResetEvent.Set(); }
private async Task RequestHandler(HttpContext context) { try { context.Response.StatusCode = (int)HttpStatusCode.OK; context.Response.Headers["Content-Type"] = "application/json; charset=utf-8"; var sp = Stopwatch.StartNew(); var database = await _router.HandlePath(context, context.Request.Method, context.Request.Path.Value); sp.Stop(); if (_logger.IsInfoEnabled && SkipHttpLogging == false) { _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 TrafficWatchChange { 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}", DatabaseName = database ?? "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: operation canceled (timeout) //TODO: Invalid data exception 422 //TODO: Proper json output, not like this var response = context.Response; MaybeSetExceptionStatusCode(response, e); using (_server.ServerStore.ContextPool.AllocateOperationContext(out JsonOperationContext ctx)) { var djv = new DynamicJsonValue { [nameof(ExceptionDispatcher.ExceptionSchema.Url)] = $"{context.Request.Path}{context.Request.QueryString}", [nameof(ExceptionDispatcher.ExceptionSchema.Type)] = e.GetType().FullName, [nameof(ExceptionDispatcher.ExceptionSchema.Message)] = e.Message }; #if EXCEPTION_ERROR_HUNT var f = Guid.NewGuid() + ".error"; File.WriteAllText(f, $"{context.Request.Path}{context.Request.QueryString}" + Environment.NewLine + errorString); #endif djv[nameof(ExceptionDispatcher.ExceptionSchema.Error)] = e.ToString(); MaybeAddAdditionalExceptionData(djv, e); using (var writer = new BlittableJsonTextWriter(ctx, response.Body)) { var json = ctx.ReadObject(djv, "exception"); writer.WriteObject(json); } #if EXCEPTION_ERROR_HUNT File.Delete(f); #endif } } }