Exemple #1
0
        public static OptionSet InitOptionsSetObject(TrafficToolConfiguration config = null)
        {
            var options = new OptionSet();

            options.OnWarning += s => WriteLineWithColor(ConsoleColor.Yellow, s);
            options.Add("traceSeconds:", OptionCategory.TrafficRecordReplay, "Time to perform the traffic watch(seconds)", x =>
            {
                var durationConstraint    = Int32.Parse(x);
                config.DurationConstraint = TimeSpan.FromSeconds(durationConstraint);
            });

            options.Add("traceRequests:", OptionCategory.TrafficRecordReplay, "Time to perform the traffic watch", x =>
            {
                var amountConstraint    = Int32.Parse(x);
                config.AmountConstraint = amountConstraint;
            });
            options.Add("compressed", OptionCategory.TrafficRecordReplay, "Work with compressed json outpu/input", x => { config.IsCompressed = true; });
            options.Add("noOutput", OptionCategory.TrafficRecordReplay, "Suppress console progress output", value => config.PrintOutput = false);
            options.Add("timeout:", OptionCategory.TrafficRecordReplay, "The timeout to use for requests(seconds)", s => config.Timeout = TimeSpan.FromSeconds(int.Parse(s)));
            options.Add("u|user|username:"******"The username to use when the database requires the client to authenticate.", value => GetCredentials(config.ConnectionString).UserName = value);
            options.Add("p|pass|password:"******"The password to use when the database requires the client to authenticate.", value => GetCredentials(config.ConnectionString).Password = value);
            options.Add("domain:", OptionCategory.TrafficRecordReplay, "The domain to use when the database requires the client to authenticate.", value => GetCredentials(config.ConnectionString).Domain = value);
            options.Add("key|api-key|apikey:", OptionCategory.TrafficRecordReplay, "The API-key to use, when using OAuth.", value => config.ApiKey = value);
            return(options);
        }
Exemple #2
0
        public static TrafficArgsProcessStatus ProcessArgs(string[] args, out TrafficToolConfiguration config)
        {
            if (args.Length == 0)
            {
                config = null;
                return(TrafficArgsProcessStatus.NoArguments);
            }
            if (args.Length < 4)
            {
                config = null;
                return(TrafficArgsProcessStatus.NoArguments);
            }

            try
            {
                // ReSharper disable once ObjectCreationAsStatement
                new Uri(args[1]);
            }
            catch (UriFormatException)
            {
                Console.WriteLine("ERROR : Server's url provided isn't in valid format");
                throw;
            }

            config = new TrafficToolConfiguration();

            switch (args[0])
            {
            case "rec":
                config.Mode = TrafficToolMode.Record;
                break;

            case "play":
                config.Mode = TrafficToolMode.Replay;
                break;

            default:
                config = null;
                return(TrafficArgsProcessStatus.InvalidMode);
            }

            config.Urls = new List <string> {
                args[1]
            };
            config.Database       = args[2];
            config.ResourceName   = args[2];
            config.RecordFilePath = args[3];
            InitOptionsSetObject(config).Parse(args);

            if (config.AmountConstraint.HasValue == false && config.DurationConstraint.HasValue == false)
            {
                config.AmountConstraint   = 1000;
                config.DurationConstraint = TimeSpan.FromSeconds(60);
            }

            return(TrafficArgsProcessStatus.ValidConfig);
        }
Exemple #3
0
        private static void Main(string[] args)
        {
            TrafficToolConfiguration config;
            var parseStatus = TrafficToolConfiguration.ProcessArgs(args, out config);

            switch (parseStatus)
            {
            case TrafficToolConfiguration.TrafficArgsProcessStatus.InvalidMode:
                PrintUsage();
                break;

            case TrafficToolConfiguration.TrafficArgsProcessStatus.NoArguments:
                PrintUsage();
                break;

            case TrafficToolConfiguration.TrafficArgsProcessStatus.NotEnoughArguments:
                Console.ForegroundColor = ConsoleColor.Red;
                Console.WriteLine("Illegal arguments amount, see usage instructions:");
                Console.ForegroundColor = ConsoleColor.White;
                break;

            case TrafficToolConfiguration.TrafficArgsProcessStatus.ValidConfig:
                IDocumentStore store;
                try
                {
                    store = new DocumentStore
                    {
                        Urls     = config.Urls.ToArray(),
                        Database = config.ResourceName
                    }.Initialize();
                }
                catch (Exception e)
                {
                    Console.WriteLine("Could not connect to server. Exception: {0}", e);
                    return;
                }

                using (store)
                {
                    try
                    {
                        store.Maintenance.Send(new GetStatisticsOperation());
                    }
                    catch (Exception)
                    {
                        Console.WriteLine("Database does not exist");
                        return;
                    }
                    new TrafficRec(store, config).ExecuteTrafficCommand();
                }
                break;
            }
        }
Exemple #4
0
        public static OptionSet InitOptionsSetObject(TrafficToolConfiguration config = null)
        {
            var options = new OptionSet();

            options.OnWarning += s => WriteLineWithColor(ConsoleColor.Yellow, s);
            options.Add("traceSeconds:", OptionCategory.TrafficRecordReplay, "Time to perform the traffic watch(seconds)", x =>
            {
                var durationConstraint    = int.Parse(x);
                config.DurationConstraint = TimeSpan.FromSeconds(durationConstraint);
            });

            options.Add("traceRequests:", OptionCategory.TrafficRecordReplay, "Time to perform the traffic watch", x =>
            {
                var amountConstraint    = int.Parse(x);
                config.AmountConstraint = amountConstraint;
            });
            options.Add("compressed", OptionCategory.TrafficRecordReplay, "Work with compressed json outpu/input", x => { config.IsCompressed = true; });
            options.Add("noOutput", OptionCategory.TrafficRecordReplay, "Suppress console progress output", value => config.PrintOutput = false);
            options.Add("timeout:", OptionCategory.TrafficRecordReplay, "The timeout to use for requests(seconds)", s => config.Timeout = TimeSpan.FromSeconds(int.Parse(s)));
            return(options);
        }
Exemple #5
0
        /// <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 void RecordRequests(TrafficToolConfiguration config, IDocumentStore store)
        {
            var requestsQueue        = new ConcurrentQueue <RavenJObject>();
            var messagesCount        = 0;
            var mre                  = new ManualResetEvent(false);
            var trafficWatchObserver = new TrafficWatchObserver(store, config.ResourceName, mre, config.Timeout, x =>
            {
                if (config.AmountConstraint.HasValue && Interlocked.Increment(ref messagesCount) > config.AmountConstraint.Value)
                {
                    mre.Set();
                }
                else
                {
                    requestsQueue.Enqueue(x);
                }
            });

            trafficWatchObserver.EstablishConnection();

            var writingTask = Task.Run(() =>
            {
                WriteRequestsFromQueueToFile(requestsQueue, config.RecordFilePath, config.IsCompressed, config.PrintOutput, mre);
            });



            if (config.DurationConstraint.HasValue)
            {
                mre.WaitOne(config.DurationConstraint.Value);
            }
            else
            {
                mre.WaitOne();
            }

            mre.Set();

            writingTask.Wait();
            trafficWatchObserver.OnCompleted();
        }
Exemple #6
0
        private static void PrintUsage()
        {
            Console.ForegroundColor = ConsoleColor.DarkMagenta;
            Console.WriteLine(@"
Traffic Recording and Replaying utility for RavenDB
----------------------------------------------
Copyright (C) 2008 - {0} - Hibernating Rhinos
----------------------------------------------", SystemTime.UtcNow.Year);
            Console.ForegroundColor = ConsoleColor.White;
            Console.WriteLine(@"
Usage:
    Raven.Traffic [Mode(rec/play)] [Url] [resource name] [recordingFile] [[option1], [option2] ...] 

Examples:
  - Record 'Northwind' database found on specified server:
    Raven.Traffic rec http://localhost:8080/ Northwind  recording.json
  - Replay 'Northwind' database from specified server to the dump.raven file:
    Raven.Traffic play http://localhost:8080/ Northwind recording.json ");

            Console.ForegroundColor = ConsoleColor.Green;
            TrafficToolConfiguration.InitOptionsSetObject().WriteOptionDescriptions(Console.Out);
            Console.ForegroundColor = ConsoleColor.White;
        }
Exemple #7
0
 private void ReplayRequests(TrafficToolConfiguration config, IDocumentStore store)
 {
     throw new NotImplementedException();
 }
Exemple #8
0
 public TrafficRec(IDocumentStore store, TrafficToolConfiguration config)
 {
     _store  = store;
     _config = config;
 }
Exemple #9
0
        /// <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
                    }
                }
            }
        }
Exemple #10
0
        private void ReplayRequests(TrafficToolConfiguration config, IDocumentStore store)
        {
            Stream finalStream;
            var    requestsCounter           = 0;
            var    skippedRequestsCounter    = 0;
            var    totalCountOfLogicRequests = 0;
            var    totalSp = Stopwatch.StartNew();

            using (var stream = File.Open(config.RecordFilePath, FileMode.Open))
            {
                if (config.IsCompressed)
                {
                    finalStream = new GZipStream(stream, CompressionMode.Decompress, leaveOpen: true);
                }
                else
                {
                    finalStream = stream;
                }
                var trafficLogs =
                    JsonSerializer.Create().Deserialize <LogHttpRequestStatsParams[]>(new JsonTextReader(new StreamReader(finalStream)));

                ConcurrentQueue <string> queue = null;
                var  cts        = new CancellationTokenSource();
                var  ct         = cts.Token;
                Task outputTask = null;
                if (config.PrintOutput)
                {
                    queue      = new ConcurrentQueue <string>();
                    outputTask = Task.Run(() =>
                    {
                        while (!ct.IsCancellationRequested || queue.Count != 0)
                        {
                            string message;
                            if (queue.TryDequeue(out message))
                            {
                                Console.WriteLine(message);
                            }
                            else
                            {
                                Thread.Sleep(10);
                            }
                        }
                    });
                }



                const string postLineSeparatorRegex = "\\t\\d: databases\\/[\\w\\.]+";
                const string endOfPostLineString    = "\t\t\tQuery:";
                const string uriCleanRegex          = "http://[\\w\\.-]+(:\\d*)?(\\/databases\\/[\\w\\.]+)?";

                Parallel.ForEach(trafficLogs, new ParallelOptions
                {
                    MaxDegreeOfParallelism = 60
                }, trafficLog =>
                {
                    var sp = Stopwatch.StartNew();
                    GetRequest[] requestsArray = null;

                    string uriString = Regex.Replace(trafficLog.RequestUri, uriCleanRegex, string.Empty);


                    string trafficQueryPart;
                    var trafficUrlPart = ExtractUrlAndQuery(uriString, out trafficQueryPart);

                    var curCount = Interlocked.Increment(ref requestsCounter);
                    if (ValidateUrlString(trafficUrlPart))
                    {
                        Interlocked.Increment(ref skippedRequestsCounter);
                        if (queue != null)
                        {
                            queue.Enqueue(string.Format("{0} out of {1}, skipped whole message",
                                                        curCount, trafficLogs.Length));
                        }
                        return;
                    }
                    Interlocked.Increment(ref totalCountOfLogicRequests);
                    if (trafficLog.HttpMethod.Equals("get", StringComparison.CurrentCultureIgnoreCase))
                    {
                        requestsArray = new[]
                        {
                            new GetRequest
                            {
                                Url   = trafficUrlPart,
                                Query = trafficQueryPart
                            }
                        };
                    }
                    else if (trafficLog.CustomInfo != null)
                    {
                        var subArray = Regex.Split(trafficLog.CustomInfo.Replace("\r", string.Empty), postLineSeparatorRegex).Where(x => !String.IsNullOrEmpty(x)).Select(x =>
                        {
                            var endOfPostLastIndex = x.IndexOf(endOfPostLineString);
                            if (endOfPostLastIndex < 0)
                            {
                                return(x);
                            }
                            return(x.Remove(endOfPostLastIndex));
                        }).ToArray();
                        requestsArray =
                            subArray.Select(customInfoLine =>
                        {
                            trafficUrlPart = ExtractUrlAndQuery(customInfoLine, out trafficQueryPart);

                            if (ValidateUrlString(trafficUrlPart))
                            {
                                if (queue != null)
                                {
                                    queue.Enqueue(string.Format("{0} out of {1}, skipped inner message",
                                                                curCount, trafficLogs.Length));
                                }
                                return(null);
                            }

                            return(new GetRequest
                            {
                                Url = trafficUrlPart,
                                Query = trafficQueryPart,
                            });
                        }).Where(x => x != null).ToArray();
                    }
                    Interlocked.Add(ref totalCountOfLogicRequests, requestsArray?.Length ?? 0);
                    if (requestsArray == null || requestsArray.Length == 0)
                    {
                        Interlocked.Increment(ref skippedRequestsCounter);
                        if (queue != null)
                        {
                            queue.Enqueue(string.Format("{0} out of {1}, skipped",
                                                        curCount, trafficLogs.Length, sp.ElapsedMilliseconds, totalSp.ElapsedMilliseconds));
                        }
                        return;
                    }
                    try
                    {
                        store.DatabaseCommands.MultiGet(requestsArray);


                        if (queue != null)
                        {
                            queue.Enqueue(string.Format("{0} out of {1}, took {2} ms. Total Time: {3} ms",
                                                        curCount, trafficLogs.Length, sp.ElapsedMilliseconds, totalSp.ElapsedMilliseconds));
                        }
                    }
                    catch (Exception e)
                    {
                        Interlocked.Increment(ref skippedRequestsCounter);
                        if (queue != null)
                        {
                            queue.Enqueue(string.Format("{0} out of {1}, failed, took {2} ms. Total Time: {3} ms",
                                                        curCount, trafficLogs.Length, sp.ElapsedMilliseconds, totalSp.ElapsedMilliseconds));
                        }
                    }
                });

                if (outputTask != null)
                {
                    cts.Cancel();
                    outputTask.Wait();
                }
            }

            Console.WriteLine(@"Summary: 
Requests sent: {0}
Requests skipped: {1}
Nested and non nested request: {2}
Total Time: {3}", requestsCounter, skippedRequestsCounter, totalCountOfLogicRequests, totalSp.ElapsedMilliseconds);
        }
Exemple #11
0
 public TrafficRec(IDocumentStore store, TrafficToolConfiguration config)
 {
     this.store  = store;
     this.config = config;
 }
Exemple #12
0
        private static void RunCommand(CommandLineApplication cmd, TrafficToolConfiguration.TrafficToolMode mode)
        {
            cmd.HelpOption(HelpOptionString);

            var urlArg            = cmd.Argument("URL", "RavenDB Server URL");
            var databaseArg       = cmd.Argument("Database", "Database name");
            var recordFilePathArg = cmd.Argument("RecordFilePath", "Record file path");

            var durationConstraintArg = cmd.Option("--trace-seconds", "Time to perform the traffic watch(seconds)", CommandOptionType.SingleValue);
            var amountConstraintArg   = cmd.Option("--trace-requests", "Time to perform the traffic watch", CommandOptionType.SingleValue);
            var compressedArg         = cmd.Option("--compressed", "Work with compressed json outpu/input", CommandOptionType.NoValue);
            var noOutputArg           = cmd.Option("--no-output", "Suppress console progress output", CommandOptionType.NoValue);
            var timeoutArg            = cmd.Option("--timeout", "The timeout to use for requests(seconds)", CommandOptionType.SingleValue);

            cmd.OnExecute(() =>
            {
                var url = urlArg.Value;
                try
                {
                    // ReSharper disable once ObjectCreationAsStatement
                    new Uri(url);
                }
                catch (UriFormatException e)
                {
                    return(ExitWithError($"Server's url provided isn't in valid format. {e}", cmd));
                }

                IDocumentStore store;
                try
                {
                    store = new DocumentStore
                    {
                        Urls     = new[] { url },
                        Database = databaseArg.Value
                    }.Initialize();
                }
                catch (Exception e)
                {
                    return(ExitWithError($"Could not connect to server. Exception: {e}", cmd));
                }

                using (store)
                {
                    try
                    {
                        store.Maintenance.Send(new GetStatisticsOperation());
                    }
                    catch (Exception)
                    {
                        return(ExitWithError("Database does not exist.", cmd));
                    }

                    var configuration = new TrafficToolConfiguration
                    {
                        Database           = databaseArg.Value,
                        RecordFilePath     = recordFilePathArg.Value,
                        Mode               = mode,
                        DurationConstraint = TimeSpan.FromSeconds(durationConstraintArg.HasValue()
                            ? int.Parse(durationConstraintArg.Value())
                            : 60),
                        AmountConstraint = amountConstraintArg.HasValue()
                            ? int.Parse(amountConstraintArg.Value())
                            : 1000,
                    };
                    if (timeoutArg.HasValue())
                    {
                        configuration.Timeout = TimeSpan.FromSeconds(int.Parse(timeoutArg.Value()));
                    }
                    if (compressedArg.HasValue())
                    {
                        configuration.IsCompressed = true;
                    }
                    if (noOutputArg.HasValue())
                    {
                        configuration.PrintOutput = false;
                    }

                    new TrafficRec(store, configuration).ExecuteTrafficCommand();
                }

                return(0);
            });
        }