예제 #1
0
        public Task TestCustomMetrics()
        {
            return(ScenarioRunner.SingleTarget(_outputHelper,
                                               _httpClientFactory,
                                               DiagnosticPortConnectionMode.Connect,
                                               TestAppScenarios.AsyncWait.Name,
                                               async(appRunner, apiClient) =>
            {
                var counterNames = new[] { "cpu-usage", "working-set" };

                using ResponseStreamHolder holder = await apiClient.CaptureMetricsAsync(await appRunner.ProcessIdTask,
                                                                                        durationSeconds: 10,
                                                                                        metricsConfiguration: new EventMetricsConfiguration
                {
                    IncludeDefaultProviders = false,
                    Providers = new[]
                    {
                        new EventMetricsProvider
                        {
                            ProviderName = EventPipe.MonitoringSourceConfiguration.SystemRuntimeEventSourceName,
                            CounterNames = counterNames,
                        }
                    }
                });

                var metrics = GetAllMetrics(holder);
                await ValidateMetrics(new [] { EventPipe.MonitoringSourceConfiguration.SystemRuntimeEventSourceName },
                                      counterNames,
                                      metrics,
                                      strict: true);

                await appRunner.SendCommandAsync(TestAppScenarios.AsyncWait.Commands.Continue);
            }));
        }
예제 #2
0
        public Task TestDefaultMetrics()
        {
            return(ScenarioRunner.SingleTarget(_outputHelper,
                                               _httpClientFactory,
                                               DiagnosticPortConnectionMode.Connect,
                                               TestAppScenarios.AsyncWait.Name,
                                               async(appRunner, apiClient) =>
            {
                using ResponseStreamHolder holder = await apiClient.CaptureMetricsAsync(await appRunner.ProcessIdTask,
                                                                                        durationSeconds: 10);

                var metrics = GetAllMetrics(holder);
                await ValidateMetrics(new [] { EventPipe.MonitoringSourceConfiguration.SystemRuntimeEventSourceName },
                                      new []
                {
                    "cpu-usage",
                    "working-set",
                    "gc-heap-size",
                    "threadpool-thread-count",
                    "threadpool-queue-length"
                },
                                      metrics, strict: false);

                await appRunner.SendCommandAsync(TestAppScenarios.AsyncWait.Commands.Continue);
            }));
        }
예제 #3
0
        private async Task ValidateResponseStream(AppRunner runner, Task <ResponseStreamHolder> holderTask, Func <ChannelReader <LogEntry>, Task> callback, LogFormat logFormat)
        {
            Assert.NotNull(runner);
            Assert.NotNull(holderTask);
            Assert.NotNull(callback);

            // CONSIDER: Give dotnet-monitor some time to start the logs pipeline before having the target
            // application start logging. It would be best if dotnet-monitor could write a console event
            // (at Debug or Trace level) for when the pipeline has started. This would require dotnet-monitor
            // to know when the pipeline started and is waiting for logging data.
            await Task.Delay(TimeSpan.FromSeconds(3));

            // Start logging in the target application
            await runner.SendCommandAsync(TestAppScenarios.Logger.Commands.StartLogging);

            // Await the holder after sending the message to start logging so that ASP.NET can send chunked responses.
            // If awaited before sending the message, ASP.NET will not send the complete set of headers because no data
            // is written into the response stream. Since HttpClient.SendAsync has to wait for the complete set of headers,
            // the /logs invocation would run and complete with no log events. To avoid this, the /logs invocation is started,
            // then the StartLogging message is sent, and finally the holder is awaited.
            using ResponseStreamHolder holder = await holderTask;
            Assert.NotNull(holder);

            await LogsTestUtilities.ValidateLogsEquality(holder.Stream, callback, logFormat, _outputHelper);
        }
예제 #4
0
        public Task LogsDefaultLevelNoneNotSupportedViaBodyTest(DiagnosticPortConnectionMode mode, LogFormat logFormat)
        {
            return(ScenarioRunner.SingleTarget(
                       _outputHelper,
                       _httpClientFactory,
                       mode,
                       TestAppScenarios.Logger.Name,
                       appValidate: async(runner, client) =>
            {
                ValidationProblemDetailsException exception = await Assert.ThrowsAsync <ValidationProblemDetailsException>(
                    async() =>
                {
                    using ResponseStreamHolder _ = await client.CaptureLogsAsync(
                              await runner.ProcessIdTask,
                              CommonTestTimeouts.LogsDuration,
                              new LogsConfiguration()
                    {
                        LogLevel = LogLevel.None
                    },
                              logFormat);
                });
                Assert.Equal(HttpStatusCode.BadRequest, exception.StatusCode);
                Assert.Equal(StatusCodes.Status400BadRequest, exception.Details.Status);

                // Allow test app to gracefully exit by continuing the scenario.
                await runner.SendCommandAsync(TestAppScenarios.Logger.Commands.StartLogging);
            }));
        }
예제 #5
0
        public Task DumpTest(DiagnosticPortConnectionMode mode, DumpType type)
        {
#if !NET6_0_OR_GREATER
            // Capturing non-full dumps via diagnostic command works inconsistently
            // on Alpine for .NET 5 and lower (the dump command will return successfully, but)
            // the dump file will not exist). Only test other dump types on .NET 6+
            if (DistroInformation.IsAlpineLinux && type != DumpType.Full)
            {
                _outputHelper.WriteLine("Skipped on Alpine for .NET 5 and lower.");
                return(Task.CompletedTask);
            }
#endif

            return(ScenarioRunner.SingleTarget(
                       _outputHelper,
                       _httpClientFactory,
                       mode,
                       TestAppScenarios.AsyncWait.Name,
                       appValidate: async(runner, client) =>
            {
                int processId = await runner.ProcessIdTask;

                using ResponseStreamHolder holder = await client.CaptureDumpAsync(processId, type);
                Assert.NotNull(holder);

                // The dump operation may still be in progress but the process should still be discoverable.
                // If this check fails, then the dump operation is causing dotnet-monitor to not be able
                // to observe the process any more.
                ProcessInfo processInfo = await client.GetProcessAsync(processId);
                Assert.NotNull(processInfo);

                await DumpTestUtilities.ValidateDump(runner.Environment.ContainsKey(DumpTestUtilities.EnableElfDumpOnMacOS), holder.Stream);

                await runner.SendCommandAsync(TestAppScenarios.AsyncWait.Commands.Continue);
            },
                       configureApp: runner =>
            {
                // MachO not supported on .NET 5, only ELF: https://github.com/dotnet/runtime/blob/main/docs/design/coreclr/botr/xplat-minidump-generation.md#os-x
                if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX) && DotNetHost.RuntimeVersion.Major == 5)
                {
                    runner.Environment.Add(DumpTestUtilities.EnableElfDumpOnMacOS, "1");
                }
            },
                       configureTool: runner =>
            {
                string dumpTempFolder = Path.Combine(runner.TempPath, "Dumps");

                // The dump temp folder should not exist in order to test that capturing dumps into the folder
                // will work since dotnet-monitor should ensure the folder is created before issuing the dump command.
                Assert.False(Directory.Exists(dumpTempFolder), "The dump temp folder should not exist.");

                runner.ConfigurationFromEnvironment.SetDumpTempFolder(dumpTempFolder);
            }));
        }
예제 #6
0
        private static async IAsyncEnumerable <CounterPayload> GetAllMetrics(ResponseStreamHolder holder)
        {
            using var reader = new StreamReader(holder.Stream);

            string entry = string.Empty;

            while ((entry = await reader.ReadLineAsync()) != null)
            {
                Assert.Equal(StreamingLogger.JsonSequenceRecordSeparator, (byte)entry[0]);
                yield return(JsonSerializer.Deserialize <CounterPayload>(entry.Substring(1)));
            }
        }