From 0676757afcca281c8dc16b4f20693776253d06c7 Mon Sep 17 00:00:00 2001 From: Justin Anderson Date: Wed, 26 May 2021 15:29:57 -0700 Subject: [PATCH 001/185] Update main to Preview 6 (#358) --- eng/Versions.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eng/Versions.props b/eng/Versions.props index af61eed77b4..66b98fa26d7 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -3,7 +3,7 @@ https://github.com/dotnet/dotnet-monitor 5.0.0 preview - 5 + 6 true 6.0.0-preview.6.21275.8 - 5.0.0-preview.21275.1 - 5.0.0-preview.21275.1 + 5.0.0-preview.21276.1 + 5.0.0-preview.21276.1 6.0.0-preview.6.21276.1 From 3fdb519bcd4f524f0c2622b40b3c863f8d6d02eb Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 27 May 2021 13:00:16 +0000 Subject: [PATCH 003/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210526.9 (#366) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 437bcb6b721..082129ce152 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - e7b5aa6f713e9f040ba0730b915ae407d35971c1 + 028470e31304cde30aebacd44be2abc34ee99f62 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 23c33da2536..d3ba6454028 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21275.5 - 6.0.0-preview.6.21275.8 + 6.0.0-preview.6.21276.9 5.0.0-preview.21276.1 5.0.0-preview.21276.1 From cab5c0da3164f60b6bde109aa27e410854b49ae7 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 28 May 2021 00:11:27 +0000 Subject: [PATCH 004/185] Update dependencies from https://github.com/dotnet/runtime build 20210526.13 (#365) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 082129ce152..be4e6934ae2 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 028470e31304cde30aebacd44be2abc34ee99f62 - + https://github.com/dotnet/runtime - f584c7401a24781b4c8e8e2a8097b85462ee4941 + 6e5f722a9dab49f9626ea95326ef6e74129621ca diff --git a/eng/Versions.props b/eng/Versions.props index d3ba6454028..8772c503044 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21276.1 5.0.0-preview.21276.1 - 6.0.0-preview.6.21276.1 + 6.0.0-preview.6.21276.13 1.0.215101 From ff79891f2e3f6ba9f203447a8b1d232bc12b2ef3 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 28 May 2021 00:13:35 +0000 Subject: [PATCH 005/185] Update dependencies from https://github.com/dotnet/arcade build 20210526.5 (#364) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- global.json | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index be4e6934ae2..20a13afee1d 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -14,13 +14,13 @@ - + https://github.com/dotnet/arcade - 579b548c545da1a9747bc5df599f38fe86d66251 + c2a8af3f309fc27402fa9c18bac6df757a9c41ed - + https://github.com/dotnet/arcade - 579b548c545da1a9747bc5df599f38fe86d66251 + c2a8af3f309fc27402fa9c18bac6df757a9c41ed https://github.com/dotnet/symstore diff --git a/eng/Versions.props b/eng/Versions.props index 8772c503044..632462550a8 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -27,7 +27,7 @@ --> - 6.0.0-beta.21275.5 + 6.0.0-beta.21276.5 6.0.0-preview.6.21276.9 diff --git a/global.json b/global.json index cd48e323d4c..1d6f96feba1 100644 --- a/global.json +++ b/global.json @@ -16,6 +16,6 @@ }, "msbuild-sdks": { "Microsoft.Build.NoTargets": "2.0.1", - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21275.5" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21276.5" } } From d345110747a15499049e0846c87795cef62f6b6b Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 28 May 2021 12:49:04 +0000 Subject: [PATCH 006/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210527.6 (#371) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 20a13afee1d..93039b95943 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - 028470e31304cde30aebacd44be2abc34ee99f62 + 3341e46cb7198c0b5dab7cb0bf5893fee8da2c46 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 632462550a8..c63e322b6f3 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21276.5 - 6.0.0-preview.6.21276.9 + 6.0.0-preview.6.21277.6 5.0.0-preview.21276.1 5.0.0-preview.21276.1 From 3b01b677b74e849c971d86a3135587354e5406bf Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 29 May 2021 12:24:57 +0000 Subject: [PATCH 007/185] [main] Update dependencies from dotnet/diagnostics (#368) [main] Update dependencies from dotnet/diagnostics --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 93039b95943..a7cda4cfaa8 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics - 44610b8f3551ddffad14bb4d0867cf36b91d8966 + bec3757f874c90531bdbfbf4064619e155e4d1f6 - + https://github.com/dotnet/diagnostics - 44610b8f3551ddffad14bb4d0867cf36b91d8966 + bec3757f874c90531bdbfbf4064619e155e4d1f6 diff --git a/eng/Versions.props b/eng/Versions.props index c63e322b6f3..0b6e360d860 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-preview.6.21277.6 - 5.0.0-preview.21276.1 - 5.0.0-preview.21276.1 + 5.0.0-preview.21278.1 + 5.0.0-preview.21278.1 6.0.0-preview.6.21276.13 From 7bdb8e77ebdc3c6e493a6f3eb74d38475c44cf99 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 29 May 2021 12:31:59 +0000 Subject: [PATCH 008/185] [main] Update dependencies from dotnet/runtime (#370) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index a7cda4cfaa8..88c507a8849 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 3341e46cb7198c0b5dab7cb0bf5893fee8da2c46 - + https://github.com/dotnet/runtime - 6e5f722a9dab49f9626ea95326ef6e74129621ca + 95a4476b91827e6f707744fab6e9d87df870407a diff --git a/eng/Versions.props b/eng/Versions.props index 0b6e360d860..1584d540e05 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21278.1 5.0.0-preview.21278.1 - 6.0.0-preview.6.21276.13 + 6.0.0-preview.6.21278.10 1.0.215101 From 5491888085c67b6e7f5b9654bc17e2a11120face Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sun, 30 May 2021 12:27:52 +0000 Subject: [PATCH 009/185] [main] Update dependencies from dotnet/arcade (#369) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- global.json | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 88c507a8849..9b277273b5e 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -14,13 +14,13 @@ - + https://github.com/dotnet/arcade - c2a8af3f309fc27402fa9c18bac6df757a9c41ed + b5ca0997b26992dcc4e55ec3d87d71000be295ce - + https://github.com/dotnet/arcade - c2a8af3f309fc27402fa9c18bac6df757a9c41ed + b5ca0997b26992dcc4e55ec3d87d71000be295ce https://github.com/dotnet/symstore diff --git a/eng/Versions.props b/eng/Versions.props index 1584d540e05..d4c94368699 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -27,7 +27,7 @@ --> - 6.0.0-beta.21276.5 + 6.0.0-beta.21278.1 6.0.0-preview.6.21277.6 diff --git a/global.json b/global.json index 1d6f96feba1..194858bc31e 100644 --- a/global.json +++ b/global.json @@ -16,6 +16,6 @@ }, "msbuild-sdks": { "Microsoft.Build.NoTargets": "2.0.1", - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21276.5" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21278.1" } } From fdea348dcc9fd0843c16feb5cd139d9cfe231811 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sun, 30 May 2021 12:38:45 +0000 Subject: [PATCH 010/185] Update dependencies from https://github.com/dotnet/runtime build 20210529.3 (#372) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 9b277273b5e..cb5ea053003 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 3341e46cb7198c0b5dab7cb0bf5893fee8da2c46 - + https://github.com/dotnet/runtime - 95a4476b91827e6f707744fab6e9d87df870407a + b5c91e4c29359f160edcf7caf16530e48d9a4fb0 diff --git a/eng/Versions.props b/eng/Versions.props index d4c94368699..ae873ac565e 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21278.1 5.0.0-preview.21278.1 - 6.0.0-preview.6.21278.10 + 6.0.0-preview.6.21279.3 1.0.215101 From 79c88e277104e40f272a14765e7b38d3c1eea2a3 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sun, 30 May 2021 16:15:47 +0000 Subject: [PATCH 011/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210529.2 (#373) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index cb5ea053003..0df5aac0fe3 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - 3341e46cb7198c0b5dab7cb0bf5893fee8da2c46 + 8d169332d5583a42705eefef63b85a007cda2872 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index ae873ac565e..459bb7e5b3d 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21278.1 - 6.0.0-preview.6.21277.6 + 6.0.0-preview.6.21279.2 5.0.0-preview.21278.1 5.0.0-preview.21278.1 From 993a35aabededc781ae05f3764ea954c8c6f839e Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 31 May 2021 12:40:18 +0000 Subject: [PATCH 012/185] Update dependencies from https://github.com/dotnet/runtime build 20210531.1 (#374) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 0df5aac0fe3..14ff183e43b 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 8d169332d5583a42705eefef63b85a007cda2872 - + https://github.com/dotnet/runtime - b5c91e4c29359f160edcf7caf16530e48d9a4fb0 + fea7ff2cce79da2df9cf1c50ce215287750f055e diff --git a/eng/Versions.props b/eng/Versions.props index 459bb7e5b3d..30a75f112dc 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21278.1 5.0.0-preview.21278.1 - 6.0.0-preview.6.21279.3 + 6.0.0-preview.6.21281.1 1.0.215101 From 09b6aeb105f130d4bacb1cf98e8c1f18bee2c954 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 31 May 2021 12:55:35 +0000 Subject: [PATCH 013/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210530.2 (#375) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 14ff183e43b..81d6eb037be 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - 8d169332d5583a42705eefef63b85a007cda2872 + fbf30e062f2bbf999ec4032eb4dadc117d46f048 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 30a75f112dc..a983478f410 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21278.1 - 6.0.0-preview.6.21279.2 + 6.0.0-preview.6.21280.2 5.0.0-preview.21278.1 5.0.0-preview.21278.1 From b9009488360e6da69a86a31b81531cac254c3455 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 1 Jun 2021 12:31:34 +0000 Subject: [PATCH 014/185] Update dependencies from https://github.com/dotnet/diagnostics build 20210531.1 (#376) [main] Update dependencies from dotnet/diagnostics --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 81d6eb037be..b56b4e81921 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics - bec3757f874c90531bdbfbf4064619e155e4d1f6 + 11f712d3f5782aafa92934f05c04385150431753 - + https://github.com/dotnet/diagnostics - bec3757f874c90531bdbfbf4064619e155e4d1f6 + 11f712d3f5782aafa92934f05c04385150431753 diff --git a/eng/Versions.props b/eng/Versions.props index a983478f410..cc58506b72d 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-preview.6.21280.2 - 5.0.0-preview.21278.1 - 5.0.0-preview.21278.1 + 5.0.0-preview.21281.1 + 5.0.0-preview.21281.1 6.0.0-preview.6.21281.1 From 41adc5f1dac7af4a5f73d5c2dbcb7d9cbde190df Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 1 Jun 2021 12:31:50 +0000 Subject: [PATCH 015/185] Update dependencies from https://github.com/dotnet/arcade build 20210531.1 (#377) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- global.json | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index b56b4e81921..45c41c14f49 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -14,13 +14,13 @@ - + https://github.com/dotnet/arcade - b5ca0997b26992dcc4e55ec3d87d71000be295ce + c7d6bd607715f334cda90e01967bb0c02dee09be - + https://github.com/dotnet/arcade - b5ca0997b26992dcc4e55ec3d87d71000be295ce + c7d6bd607715f334cda90e01967bb0c02dee09be https://github.com/dotnet/symstore diff --git a/eng/Versions.props b/eng/Versions.props index cc58506b72d..1b88fcb346e 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -27,7 +27,7 @@ --> - 6.0.0-beta.21278.1 + 6.0.0-beta.21281.1 6.0.0-preview.6.21280.2 diff --git a/global.json b/global.json index 194858bc31e..1fa7a5cbcbc 100644 --- a/global.json +++ b/global.json @@ -16,6 +16,6 @@ }, "msbuild-sdks": { "Microsoft.Build.NoTargets": "2.0.1", - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21278.1" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21281.1" } } From 44fe47c00e4d9400e5ef933dab5a4a67bf3b1ab8 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 1 Jun 2021 12:51:17 +0000 Subject: [PATCH 016/185] Update dependencies from https://github.com/dotnet/runtime build 20210601.1 (#378) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 45c41c14f49..9641b1e7260 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore fbf30e062f2bbf999ec4032eb4dadc117d46f048 - + https://github.com/dotnet/runtime - fea7ff2cce79da2df9cf1c50ce215287750f055e + 85fde0536b64c4901056b894f5184103f39cac63 diff --git a/eng/Versions.props b/eng/Versions.props index 1b88fcb346e..ad9875f7fb1 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21281.1 5.0.0-preview.21281.1 - 6.0.0-preview.6.21281.1 + 6.0.0-preview.6.21301.1 1.0.215101 From cdef37238d9cce1f32a33c44548debc6c1a1e104 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 1 Jun 2021 18:14:36 +0000 Subject: [PATCH 017/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210531.6 (#379) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 9641b1e7260..a518a1e6b7b 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - fbf30e062f2bbf999ec4032eb4dadc117d46f048 + 564ef4aaca9c66495022d446414d23dc2e363361 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index ad9875f7fb1..97f18ad568e 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21281.1 - 6.0.0-preview.6.21280.2 + 6.0.0-preview.6.21281.6 5.0.0-preview.21281.1 5.0.0-preview.21281.1 From 44785a160c2f675d094f0130857f830731ba6a97 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 2 Jun 2021 12:23:32 +0000 Subject: [PATCH 018/185] Update dependencies from https://github.com/dotnet/diagnostics build 20210601.1 (#381) [main] Update dependencies from dotnet/diagnostics --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index a518a1e6b7b..5a8ac3e4aea 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics - 11f712d3f5782aafa92934f05c04385150431753 + deda6360a34d4479b85aa19f21b5cae35e5c3873 - + https://github.com/dotnet/diagnostics - 11f712d3f5782aafa92934f05c04385150431753 + deda6360a34d4479b85aa19f21b5cae35e5c3873 diff --git a/eng/Versions.props b/eng/Versions.props index 97f18ad568e..5d729e87671 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-preview.6.21281.6 - 5.0.0-preview.21281.1 - 5.0.0-preview.21281.1 + 5.0.0-preview.21301.1 + 5.0.0-preview.21301.1 6.0.0-preview.6.21301.1 From 33ae29b6eeaaa85f7b5d62ed62e2c65955f3a71d Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 2 Jun 2021 12:34:49 +0000 Subject: [PATCH 019/185] Update dependencies from https://github.com/dotnet/runtime build 20210602.1 (#382) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 5a8ac3e4aea..6a373ce2c00 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 564ef4aaca9c66495022d446414d23dc2e363361 - + https://github.com/dotnet/runtime - 85fde0536b64c4901056b894f5184103f39cac63 + dbb05eba3b229df3d4c15ce08de9f84c7febb7b3 diff --git a/eng/Versions.props b/eng/Versions.props index 5d729e87671..714ce2762f4 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21301.1 5.0.0-preview.21301.1 - 6.0.0-preview.6.21301.1 + 6.0.0-preview.6.21302.1 1.0.215101 From 2b27157559df6d7540421718c80af52820fa551f Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 2 Jun 2021 14:31:06 +0000 Subject: [PATCH 020/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210602.1 (#383) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 6a373ce2c00..d06361a6d9f 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - 564ef4aaca9c66495022d446414d23dc2e363361 + 26e01c7cff32b5994be8ef17afacffc8232b881d https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 714ce2762f4..31f2afeaf7a 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21281.1 - 6.0.0-preview.6.21281.6 + 6.0.0-preview.6.21302.1 5.0.0-preview.21301.1 5.0.0-preview.21301.1 From 5bfc4e957b98901790231f4c641947fd5e3915aa Mon Sep 17 00:00:00 2001 From: Justin Anderson Date: Wed, 2 Jun 2021 15:36:57 -0700 Subject: [PATCH 021/185] Fix translation of default process CommandLine filter key. (#387) --- .../DiagProcessFilter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/DiagProcessFilter.cs b/src/Microsoft.Diagnostics.Monitoring.RestServer/DiagProcessFilter.cs index 95f23c56485..a6ffd980730 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/DiagProcessFilter.cs +++ b/src/Microsoft.Diagnostics.Monitoring.RestServer/DiagProcessFilter.cs @@ -72,7 +72,7 @@ private static DiagProcessFilterEntry TransformDescriptor(ProcessFilterDescripto case ProcessFilterKey.CommandLine: return new DiagProcessFilterEntry { - Criteria = DiagProcessFilterCriteria.ProcessName, + Criteria = DiagProcessFilterCriteria.CommandLine, MatchType = (processFilterDescriptor.MatchType == ProcessFilterType.Exact) ? DiagProcessFilterMatchType.Exact : DiagProcessFilterMatchType.Contains, Value = processFilterDescriptor.Value }; From 626fefb55e2b60d71d34b28f1a27dcbfeeed8cc0 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 3 Jun 2021 12:31:38 +0000 Subject: [PATCH 022/185] Update dependencies from https://github.com/dotnet/diagnostics build 20210602.1 (#389) [main] Update dependencies from dotnet/diagnostics --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index d06361a6d9f..edfde3ca5d3 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics - deda6360a34d4479b85aa19f21b5cae35e5c3873 + 17f22ce2372e3e609684b6659def01e2e9ae257c - + https://github.com/dotnet/diagnostics - deda6360a34d4479b85aa19f21b5cae35e5c3873 + 17f22ce2372e3e609684b6659def01e2e9ae257c diff --git a/eng/Versions.props b/eng/Versions.props index 31f2afeaf7a..9958758e3b9 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-preview.6.21302.1 - 5.0.0-preview.21301.1 - 5.0.0-preview.21301.1 + 5.0.0-preview.21302.1 + 5.0.0-preview.21302.1 6.0.0-preview.6.21302.1 From ce4af93876b9b752450c0c61ad378f1a6254a347 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 3 Jun 2021 12:31:55 +0000 Subject: [PATCH 023/185] Update dependencies from https://github.com/dotnet/arcade build 20210602.1 (#390) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- global.json | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index edfde3ca5d3..677c3934c98 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -14,13 +14,13 @@ - + https://github.com/dotnet/arcade - c7d6bd607715f334cda90e01967bb0c02dee09be + 9945dc4ebbb511b027df34cb5ab579f6395d1dda - + https://github.com/dotnet/arcade - c7d6bd607715f334cda90e01967bb0c02dee09be + 9945dc4ebbb511b027df34cb5ab579f6395d1dda https://github.com/dotnet/symstore diff --git a/eng/Versions.props b/eng/Versions.props index 9958758e3b9..96d4b041ccc 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -27,7 +27,7 @@ --> - 6.0.0-beta.21281.1 + 6.0.0-beta.21302.1 6.0.0-preview.6.21302.1 diff --git a/global.json b/global.json index 1fa7a5cbcbc..749baa49107 100644 --- a/global.json +++ b/global.json @@ -16,6 +16,6 @@ }, "msbuild-sdks": { "Microsoft.Build.NoTargets": "2.0.1", - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21281.1" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21302.1" } } From c9d11d167679145cdd6f94f176c38336f8ce1118 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 3 Jun 2021 12:56:29 +0000 Subject: [PATCH 024/185] Update dependencies from https://github.com/dotnet/runtime build 20210603.1 (#391) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 677c3934c98..9932316ec37 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 26e01c7cff32b5994be8ef17afacffc8232b881d - + https://github.com/dotnet/runtime - dbb05eba3b229df3d4c15ce08de9f84c7febb7b3 + 3e1ddb05cd2a1f14729df91c8c429f3047a4b569 diff --git a/eng/Versions.props b/eng/Versions.props index 96d4b041ccc..997a5922d96 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21302.1 5.0.0-preview.21302.1 - 6.0.0-preview.6.21302.1 + 6.0.0-preview.6.21303.1 1.0.215101 From 03fc952cb634e12c0f36d4e19d30f25c2f543906 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 3 Jun 2021 13:01:41 +0000 Subject: [PATCH 025/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210602.15 (#392) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 9932316ec37..471d86c208d 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - 26e01c7cff32b5994be8ef17afacffc8232b881d + 836b622bf9bb98bfd59d95838470bb1351d32368 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 997a5922d96..4d131ce1ed8 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21302.1 - 6.0.0-preview.6.21302.1 + 6.0.0-preview.6.21302.15 5.0.0-preview.21302.1 5.0.0-preview.21302.1 From cfaf942dd7255d110193763f3d9f91e4541a861c Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 4 Jun 2021 12:31:47 +0000 Subject: [PATCH 026/185] Update dependencies from https://github.com/dotnet/diagnostics build 20210603.1 (#394) [main] Update dependencies from dotnet/diagnostics --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 471d86c208d..efdebb3e8c4 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics - 17f22ce2372e3e609684b6659def01e2e9ae257c + 31c28f26c1d025742e3d9dcf272672f2e5bc384c - + https://github.com/dotnet/diagnostics - 17f22ce2372e3e609684b6659def01e2e9ae257c + 31c28f26c1d025742e3d9dcf272672f2e5bc384c diff --git a/eng/Versions.props b/eng/Versions.props index 4d131ce1ed8..64a031e5e55 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-preview.6.21302.15 - 5.0.0-preview.21302.1 - 5.0.0-preview.21302.1 + 5.0.0-preview.21303.1 + 5.0.0-preview.21303.1 6.0.0-preview.6.21303.1 From 7d12ab4812e9bc592647137dd98155e19be7dbca Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 4 Jun 2021 12:50:59 +0000 Subject: [PATCH 027/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210604.1 (#397) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index efdebb3e8c4..8655722edf0 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - 836b622bf9bb98bfd59d95838470bb1351d32368 + 180b4ad56ceac9956b4b44187f33009ee671f40c https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 64a031e5e55..3fc4b7d6504 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21302.1 - 6.0.0-preview.6.21302.15 + 6.0.0-preview.6.21304.1 5.0.0-preview.21303.1 5.0.0-preview.21303.1 From 99e439e9f85e9cb9bc5b64faf1c83ea9c712ce88 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 4 Jun 2021 12:55:55 +0000 Subject: [PATCH 028/185] Update dependencies from https://github.com/dotnet/runtime build 20210604.1 (#396) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 8655722edf0..a369a5d0f13 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 180b4ad56ceac9956b4b44187f33009ee671f40c - + https://github.com/dotnet/runtime - 3e1ddb05cd2a1f14729df91c8c429f3047a4b569 + 5a1b8223dab2f7954e7f206095ba937e5d237299 diff --git a/eng/Versions.props b/eng/Versions.props index 3fc4b7d6504..d975a67f90a 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21303.1 5.0.0-preview.21303.1 - 6.0.0-preview.6.21303.1 + 6.0.0-preview.6.21304.1 1.0.215101 From 8aa303be5004f8cba8e5faa6a7dc018e7b19c7f2 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 4 Jun 2021 16:44:26 +0000 Subject: [PATCH 029/185] Update dependencies from https://github.com/dotnet/arcade build 20210603.2 (#395) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- global.json | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index a369a5d0f13..7b5a00efe81 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -14,13 +14,13 @@ - + https://github.com/dotnet/arcade - 9945dc4ebbb511b027df34cb5ab579f6395d1dda + 78da7776965b428ff31da8f1ff2cb073506212b7 - + https://github.com/dotnet/arcade - 9945dc4ebbb511b027df34cb5ab579f6395d1dda + 78da7776965b428ff31da8f1ff2cb073506212b7 https://github.com/dotnet/symstore diff --git a/eng/Versions.props b/eng/Versions.props index d975a67f90a..95ad64f9f8e 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -27,7 +27,7 @@ --> - 6.0.0-beta.21302.1 + 6.0.0-beta.21303.2 6.0.0-preview.6.21304.1 diff --git a/global.json b/global.json index 749baa49107..5b7a7e42463 100644 --- a/global.json +++ b/global.json @@ -16,6 +16,6 @@ }, "msbuild-sdks": { "Microsoft.Build.NoTargets": "2.0.1", - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21302.1" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21303.2" } } From 709c5e4ddff9c690ea0d505671c5caee19efc3fd Mon Sep 17 00:00:00 2001 From: Wiktor Kopec Date: Fri, 4 Jun 2021 11:45:09 -0700 Subject: [PATCH 030/185] Add unit tests for Process Filtering (#393) * Add unit tests for Process Filtering - Also rename existing unit test project * PR feedback --- dotnet-monitor.sln | 9 +- ...t.Diagnostics.Monitoring.RestServer.csproj | 1 + ...tics.Monitoring.ConfigurationSchema.csproj | 2 +- .../AuthenticationTests.cs | 0 .../DiagnosticPortHelper.cs | 0 .../DisposableBox.cs | 0 .../DumpTests.cs | 0 .../Fixtures/DefaultCollectionFixture.cs | 0 .../Fixtures/ServiceProviderFixture.cs | 0 .../HttpApi/ApiClient.cs | 0 .../HttpApi/ApiClientExtensions.cs | 0 .../HttpApi/ApiStatusCodeException.cs | 0 .../HttpApi/ContentTypes.cs | 0 .../HttpApi/ResponseStreamHolder.cs | 0 .../ValidationProblemDetailsException.cs | 0 .../LogsTests.cs | 0 .../MetricsTests.cs | 0 ...agnostics.Monitoring.Tool.UnitTests.csproj | 42 +++++ .../Models/LogEntry.cs | 0 .../Options/EgressOptions.cs | 0 .../Options/OptionsExtensions.cs | 0 .../Options/RootOptions.cs | 0 .../ProcessTests.cs | 0 .../Runners/AppRunner.cs | 0 .../Runners/AppRunnerExtensions.cs | 0 .../Runners/ConsoleLogEvent.cs | 0 .../Runners/MonitorRunner.cs | 0 .../Runners/MonitorRunnerExtensions.cs | 0 .../Runners/ScenarioRunner.cs | 0 .../TestConditions.cs | 0 .../TestTimeouts.cs | 0 .../DefaultProcessConfigurationTests.cs | 178 ++++++++++++++++++ ...ft.Diagnostics.Monitoring.UnitTests.csproj | 50 ++--- 33 files changed, 241 insertions(+), 41 deletions(-) rename src/Tests/{Microsoft.Diagnostics.Monitoring.UnitTests => Microsoft.Diagnostics.Monitoring.Tool.UnitTests}/AuthenticationTests.cs (100%) rename src/Tests/{Microsoft.Diagnostics.Monitoring.UnitTests => Microsoft.Diagnostics.Monitoring.Tool.UnitTests}/DiagnosticPortHelper.cs (100%) rename src/Tests/{Microsoft.Diagnostics.Monitoring.UnitTests => Microsoft.Diagnostics.Monitoring.Tool.UnitTests}/DisposableBox.cs (100%) rename src/Tests/{Microsoft.Diagnostics.Monitoring.UnitTests => Microsoft.Diagnostics.Monitoring.Tool.UnitTests}/DumpTests.cs (100%) rename src/Tests/{Microsoft.Diagnostics.Monitoring.UnitTests => Microsoft.Diagnostics.Monitoring.Tool.UnitTests}/Fixtures/DefaultCollectionFixture.cs (100%) rename src/Tests/{Microsoft.Diagnostics.Monitoring.UnitTests => Microsoft.Diagnostics.Monitoring.Tool.UnitTests}/Fixtures/ServiceProviderFixture.cs (100%) rename src/Tests/{Microsoft.Diagnostics.Monitoring.UnitTests => Microsoft.Diagnostics.Monitoring.Tool.UnitTests}/HttpApi/ApiClient.cs (100%) rename src/Tests/{Microsoft.Diagnostics.Monitoring.UnitTests => Microsoft.Diagnostics.Monitoring.Tool.UnitTests}/HttpApi/ApiClientExtensions.cs (100%) rename src/Tests/{Microsoft.Diagnostics.Monitoring.UnitTests => Microsoft.Diagnostics.Monitoring.Tool.UnitTests}/HttpApi/ApiStatusCodeException.cs (100%) rename src/Tests/{Microsoft.Diagnostics.Monitoring.UnitTests => Microsoft.Diagnostics.Monitoring.Tool.UnitTests}/HttpApi/ContentTypes.cs (100%) rename src/Tests/{Microsoft.Diagnostics.Monitoring.UnitTests => Microsoft.Diagnostics.Monitoring.Tool.UnitTests}/HttpApi/ResponseStreamHolder.cs (100%) rename src/Tests/{Microsoft.Diagnostics.Monitoring.UnitTests => Microsoft.Diagnostics.Monitoring.Tool.UnitTests}/HttpApi/ValidationProblemDetailsException.cs (100%) rename src/Tests/{Microsoft.Diagnostics.Monitoring.UnitTests => Microsoft.Diagnostics.Monitoring.Tool.UnitTests}/LogsTests.cs (100%) rename src/Tests/{Microsoft.Diagnostics.Monitoring.UnitTests => Microsoft.Diagnostics.Monitoring.Tool.UnitTests}/MetricsTests.cs (100%) create mode 100644 src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj rename src/Tests/{Microsoft.Diagnostics.Monitoring.UnitTests => Microsoft.Diagnostics.Monitoring.Tool.UnitTests}/Models/LogEntry.cs (100%) rename src/Tests/{Microsoft.Diagnostics.Monitoring.UnitTests => Microsoft.Diagnostics.Monitoring.Tool.UnitTests}/Options/EgressOptions.cs (100%) rename src/Tests/{Microsoft.Diagnostics.Monitoring.UnitTests => Microsoft.Diagnostics.Monitoring.Tool.UnitTests}/Options/OptionsExtensions.cs (100%) rename src/Tests/{Microsoft.Diagnostics.Monitoring.UnitTests => Microsoft.Diagnostics.Monitoring.Tool.UnitTests}/Options/RootOptions.cs (100%) rename src/Tests/{Microsoft.Diagnostics.Monitoring.UnitTests => Microsoft.Diagnostics.Monitoring.Tool.UnitTests}/ProcessTests.cs (100%) rename src/Tests/{Microsoft.Diagnostics.Monitoring.UnitTests => Microsoft.Diagnostics.Monitoring.Tool.UnitTests}/Runners/AppRunner.cs (100%) rename src/Tests/{Microsoft.Diagnostics.Monitoring.UnitTests => Microsoft.Diagnostics.Monitoring.Tool.UnitTests}/Runners/AppRunnerExtensions.cs (100%) rename src/Tests/{Microsoft.Diagnostics.Monitoring.UnitTests => Microsoft.Diagnostics.Monitoring.Tool.UnitTests}/Runners/ConsoleLogEvent.cs (100%) rename src/Tests/{Microsoft.Diagnostics.Monitoring.UnitTests => Microsoft.Diagnostics.Monitoring.Tool.UnitTests}/Runners/MonitorRunner.cs (100%) rename src/Tests/{Microsoft.Diagnostics.Monitoring.UnitTests => Microsoft.Diagnostics.Monitoring.Tool.UnitTests}/Runners/MonitorRunnerExtensions.cs (100%) rename src/Tests/{Microsoft.Diagnostics.Monitoring.UnitTests => Microsoft.Diagnostics.Monitoring.Tool.UnitTests}/Runners/ScenarioRunner.cs (100%) rename src/Tests/{Microsoft.Diagnostics.Monitoring.UnitTests => Microsoft.Diagnostics.Monitoring.Tool.UnitTests}/TestConditions.cs (100%) rename src/Tests/{Microsoft.Diagnostics.Monitoring.UnitTests => Microsoft.Diagnostics.Monitoring.Tool.UnitTests}/TestTimeouts.cs (100%) create mode 100644 src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/DefaultProcessConfigurationTests.cs diff --git a/dotnet-monitor.sln b/dotnet-monitor.sln index 079e5a2e1f7..0da23f8ea33 100644 --- a/dotnet-monitor.sln +++ b/dotnet-monitor.sln @@ -27,7 +27,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Diagnostics.Monit EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Diagnostics.Monitoring.OpenApiGen.UnitTests", "src\Tests\Microsoft.Diagnostics.Monitoring.OpenApiGen.UnitTests\Microsoft.Diagnostics.Monitoring.OpenApiGen.UnitTests.csproj", "{FCEC25E0-9EE1-416E-A7C4-2898E5640157}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Diagnostics.Monitoring.UnitTests", "src\Tests\Microsoft.Diagnostics.Monitoring.UnitTests\Microsoft.Diagnostics.Monitoring.UnitTests.csproj", "{04427BC9-8F54-4633-9BBB-6661715BD271}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Diagnostics.Monitoring.Tool.UnitTests", "src\Tests\Microsoft.Diagnostics.Monitoring.Tool.UnitTests\Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj", "{04427BC9-8F54-4633-9BBB-6661715BD271}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Diagnostics.Monitoring.UnitTestApp", "src\Tests\Microsoft.Diagnostics.Monitoring.UnitTestApp\Microsoft.Diagnostics.Monitoring.UnitTestApp.csproj", "{DC672D2F-3A21-40BD-B495-660850EBC5F7}" EndProject @@ -35,6 +35,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Diagnostics.Monit EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.Diagnostics.Monitoring.ConfigurationSchema", "src\Tests\Microsoft.Diagnostics.Monitoring.ConfigurationSchema\Microsoft.Diagnostics.Monitoring.ConfigurationSchema.csproj", "{422ABBF6-6236-4042-AACA-09531DBDFBAA}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Diagnostics.Monitoring.UnitTests", "src\Tests\Microsoft.Diagnostics.Monitoring.UnitTests\Microsoft.Diagnostics.Monitoring.UnitTests.csproj", "{3AD0A40B-C569-4712-9764-7A788B9CD811}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -77,6 +79,10 @@ Global {422ABBF6-6236-4042-AACA-09531DBDFBAA}.Debug|Any CPU.Build.0 = Debug|Any CPU {422ABBF6-6236-4042-AACA-09531DBDFBAA}.Release|Any CPU.ActiveCfg = Release|Any CPU {422ABBF6-6236-4042-AACA-09531DBDFBAA}.Release|Any CPU.Build.0 = Release|Any CPU + {3AD0A40B-C569-4712-9764-7A788B9CD811}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3AD0A40B-C569-4712-9764-7A788B9CD811}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3AD0A40B-C569-4712-9764-7A788B9CD811}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3AD0A40B-C569-4712-9764-7A788B9CD811}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -94,6 +100,7 @@ Global {DC672D2F-3A21-40BD-B495-660850EBC5F7} = {C7568468-1C79-4944-8136-18812A7F9EA7} {886D1FD5-125F-435B-934C-30DF2938E7F6} = {C7568468-1C79-4944-8136-18812A7F9EA7} {422ABBF6-6236-4042-AACA-09531DBDFBAA} = {C7568468-1C79-4944-8136-18812A7F9EA7} + {3AD0A40B-C569-4712-9764-7A788B9CD811} = {C7568468-1C79-4944-8136-18812A7F9EA7} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {46465737-C938-44FC-BE1A-4CE139EBB5E0} diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/Microsoft.Diagnostics.Monitoring.RestServer.csproj b/src/Microsoft.Diagnostics.Monitoring.RestServer/Microsoft.Diagnostics.Monitoring.RestServer.csproj index 1b2a7d7f17e..ba89288847f 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/Microsoft.Diagnostics.Monitoring.RestServer.csproj +++ b/src/Microsoft.Diagnostics.Monitoring.RestServer/Microsoft.Diagnostics.Monitoring.RestServer.csproj @@ -41,5 +41,6 @@ + \ No newline at end of file diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.ConfigurationSchema/Microsoft.Diagnostics.Monitoring.ConfigurationSchema.csproj b/src/Tests/Microsoft.Diagnostics.Monitoring.ConfigurationSchema/Microsoft.Diagnostics.Monitoring.ConfigurationSchema.csproj index 965493b3fed..91d547c3c9e 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.ConfigurationSchema/Microsoft.Diagnostics.Monitoring.ConfigurationSchema.csproj +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.ConfigurationSchema/Microsoft.Diagnostics.Monitoring.ConfigurationSchema.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/AuthenticationTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/AuthenticationTests.cs similarity index 100% rename from src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/AuthenticationTests.cs rename to src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/AuthenticationTests.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/DiagnosticPortHelper.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/DiagnosticPortHelper.cs similarity index 100% rename from src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/DiagnosticPortHelper.cs rename to src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/DiagnosticPortHelper.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/DisposableBox.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/DisposableBox.cs similarity index 100% rename from src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/DisposableBox.cs rename to src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/DisposableBox.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/DumpTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/DumpTests.cs similarity index 100% rename from src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/DumpTests.cs rename to src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/DumpTests.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Fixtures/DefaultCollectionFixture.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Fixtures/DefaultCollectionFixture.cs similarity index 100% rename from src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Fixtures/DefaultCollectionFixture.cs rename to src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Fixtures/DefaultCollectionFixture.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Fixtures/ServiceProviderFixture.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Fixtures/ServiceProviderFixture.cs similarity index 100% rename from src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Fixtures/ServiceProviderFixture.cs rename to src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Fixtures/ServiceProviderFixture.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/HttpApi/ApiClient.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClient.cs similarity index 100% rename from src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/HttpApi/ApiClient.cs rename to src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClient.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/HttpApi/ApiClientExtensions.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClientExtensions.cs similarity index 100% rename from src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/HttpApi/ApiClientExtensions.cs rename to src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClientExtensions.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/HttpApi/ApiStatusCodeException.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiStatusCodeException.cs similarity index 100% rename from src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/HttpApi/ApiStatusCodeException.cs rename to src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiStatusCodeException.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/HttpApi/ContentTypes.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ContentTypes.cs similarity index 100% rename from src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/HttpApi/ContentTypes.cs rename to src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ContentTypes.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/HttpApi/ResponseStreamHolder.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ResponseStreamHolder.cs similarity index 100% rename from src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/HttpApi/ResponseStreamHolder.cs rename to src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ResponseStreamHolder.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/HttpApi/ValidationProblemDetailsException.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ValidationProblemDetailsException.cs similarity index 100% rename from src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/HttpApi/ValidationProblemDetailsException.cs rename to src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ValidationProblemDetailsException.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/LogsTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/LogsTests.cs similarity index 100% rename from src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/LogsTests.cs rename to src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/LogsTests.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/MetricsTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/MetricsTests.cs similarity index 100% rename from src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/MetricsTests.cs rename to src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/MetricsTests.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj new file mode 100644 index 00000000000..fe3afd6e559 --- /dev/null +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj @@ -0,0 +1,42 @@ + + + + netcoreapp3.1;net5.0;net6.0 + $(DefineConstants);UNITTEST + + + + + + + + + + + + + + + + + + + + + + + + + + + + false + + + + + + + + + diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Models/LogEntry.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Models/LogEntry.cs similarity index 100% rename from src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Models/LogEntry.cs rename to src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Models/LogEntry.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Options/EgressOptions.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Options/EgressOptions.cs similarity index 100% rename from src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Options/EgressOptions.cs rename to src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Options/EgressOptions.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Options/OptionsExtensions.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Options/OptionsExtensions.cs similarity index 100% rename from src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Options/OptionsExtensions.cs rename to src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Options/OptionsExtensions.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Options/RootOptions.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Options/RootOptions.cs similarity index 100% rename from src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Options/RootOptions.cs rename to src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Options/RootOptions.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/ProcessTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/ProcessTests.cs similarity index 100% rename from src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/ProcessTests.cs rename to src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/ProcessTests.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Runners/AppRunner.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Runners/AppRunner.cs similarity index 100% rename from src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Runners/AppRunner.cs rename to src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Runners/AppRunner.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Runners/AppRunnerExtensions.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Runners/AppRunnerExtensions.cs similarity index 100% rename from src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Runners/AppRunnerExtensions.cs rename to src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Runners/AppRunnerExtensions.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Runners/ConsoleLogEvent.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Runners/ConsoleLogEvent.cs similarity index 100% rename from src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Runners/ConsoleLogEvent.cs rename to src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Runners/ConsoleLogEvent.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Runners/MonitorRunner.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Runners/MonitorRunner.cs similarity index 100% rename from src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Runners/MonitorRunner.cs rename to src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Runners/MonitorRunner.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Runners/MonitorRunnerExtensions.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Runners/MonitorRunnerExtensions.cs similarity index 100% rename from src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Runners/MonitorRunnerExtensions.cs rename to src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Runners/MonitorRunnerExtensions.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Runners/ScenarioRunner.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Runners/ScenarioRunner.cs similarity index 100% rename from src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Runners/ScenarioRunner.cs rename to src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Runners/ScenarioRunner.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/TestConditions.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/TestConditions.cs similarity index 100% rename from src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/TestConditions.cs rename to src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/TestConditions.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/TestTimeouts.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/TestTimeouts.cs similarity index 100% rename from src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/TestTimeouts.cs rename to src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/TestTimeouts.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/DefaultProcessConfigurationTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/DefaultProcessConfigurationTests.cs new file mode 100644 index 00000000000..357e82efbae --- /dev/null +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/DefaultProcessConfigurationTests.cs @@ -0,0 +1,178 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Diagnostics.Monitoring.RestServer; +using Microsoft.Diagnostics.Monitoring.TestCommon; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Globalization; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Security.Cryptography; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.Diagnostics.Monitoring.UnitTests +{ + public class DefaultProcessConfigurationTests + { + [Fact] + public void ConvertProcessKeyTest() + { + var processKey = new ProcessKey("processName"); + var filter = CreateFilterEntry(processKey); + ValidateProcessFilter(DiagProcessFilterCriteria.ProcessName, processKey.ProcessName, filter); + + processKey = new ProcessKey(Guid.NewGuid()); + filter = CreateFilterEntry(processKey); + ValidateProcessFilter(DiagProcessFilterCriteria.RuntimeId, processKey.RuntimeInstanceCookie.Value.ToString("D"), filter); + + processKey = new ProcessKey(5); + filter = CreateFilterEntry(processKey); + ValidateProcessFilter(DiagProcessFilterCriteria.ProcessId, processKey.ProcessId.Value.ToString(CultureInfo.InvariantCulture), filter); + } + + [Fact] + public void ConvertProcessConfig() + { + var filterDescriptorPid = new ProcessFilterDescriptor + { + Key = ProcessFilterKey.ProcessId, + MatchType = ProcessFilterType.Exact, + Value = "5" + }; + + var filterDescriptorPidContains = new ProcessFilterDescriptor + { + Key = ProcessFilterKey.ProcessId, + MatchType = ProcessFilterType.Contains, + Value = "6" + }; + + var filterDescriptorName = new ProcessFilterDescriptor + { + Key = ProcessFilterKey.ProcessName, + MatchType = ProcessFilterType.Exact, + Value = "name1" + }; + + var filterDescriptorNameContains = new ProcessFilterDescriptor + { + Key = ProcessFilterKey.ProcessName, + MatchType = ProcessFilterType.Contains, + Value = "namePartial" + }; + + var filterDescriptorCommand = new ProcessFilterDescriptor + { + Key = ProcessFilterKey.CommandLine, + MatchType = ProcessFilterType.Exact, + Value = "command arg" + }; + + var filterDescriptorCommandContains = new ProcessFilterDescriptor + { + Key = ProcessFilterKey.CommandLine, + MatchType = ProcessFilterType.Contains, + Value = "arg1" + }; + + var filter = CreateFilterEntry(filterDescriptorPid); + ValidateProcessFilter(DiagProcessFilterCriteria.ProcessId, filterDescriptorPid.Value, filter); + + //Contains still becomes Exact for ProcessId + filter = CreateFilterEntry(filterDescriptorPidContains); + ValidateProcessFilter(DiagProcessFilterCriteria.ProcessId, filterDescriptorPidContains.Value, filter); + + filter = CreateFilterEntry(filterDescriptorName); + ValidateProcessFilter(DiagProcessFilterCriteria.ProcessName, filterDescriptorName.Value, filter); + + filter = CreateFilterEntry(filterDescriptorNameContains); + ValidateProcessFilter(DiagProcessFilterCriteria.ProcessName, filterDescriptorNameContains.Value, DiagProcessFilterMatchType.Contains, filter); + + filter = CreateFilterEntry(filterDescriptorCommand); + ValidateProcessFilter(DiagProcessFilterCriteria.CommandLine, filterDescriptorCommand.Value, filter); + + filter = CreateFilterEntry(filterDescriptorCommandContains); + ValidateProcessFilter(DiagProcessFilterCriteria.CommandLine, filterDescriptorCommandContains.Value, DiagProcessFilterMatchType.Contains, filter); + + //This filter doesn't make any sense but we are just testing that we can combine multiple filters + var options = CreateOptions(filterDescriptorPid, filterDescriptorName, filterDescriptorNameContains, filterDescriptorCommand, filterDescriptorCommandContains); + + ValidateProcessFilter(DiagProcessFilterCriteria.ProcessId, filterDescriptorPid.Value, options.Filters[0]); + ValidateProcessFilter(DiagProcessFilterCriteria.ProcessName, filterDescriptorName.Value, options.Filters[1]); + ValidateProcessFilter(DiagProcessFilterCriteria.ProcessName, filterDescriptorNameContains.Value, DiagProcessFilterMatchType.Contains, options.Filters[2]); + ValidateProcessFilter(DiagProcessFilterCriteria.CommandLine, filterDescriptorCommand.Value, options.Filters[3]); + ValidateProcessFilter(DiagProcessFilterCriteria.CommandLine, filterDescriptorCommandContains.Value, DiagProcessFilterMatchType.Contains, options.Filters[4]); + } + + [Fact] + public void NewCriteriaTest() + { + //When new enumerations (such as Entrypoint) are added to DiagProcessFilterCriteria, + //this test will fail. This means new unit tests should be written for that criteria and this test can be updated. + + //Sorted by unsigned integer value + var expectedValues = Enum.GetValues(typeof(DiagProcessFilterCriteria)); + + var actualValues = new[] + { + DiagProcessFilterCriteria.ProcessId, + DiagProcessFilterCriteria.RuntimeId, + DiagProcessFilterCriteria.CommandLine, + DiagProcessFilterCriteria.ProcessName, + }; + + Assert.Equal(expectedValues.Length, actualValues.Length); + for (int i = 0; i < expectedValues.Length; i++) + { + Assert.Equal(expectedValues.GetValue(i), actualValues[i]); + } + } + + private static void ValidateProcessFilter(DiagProcessFilterCriteria expectedCriteria, + string expectedvalue, + DiagProcessFilterEntry actualFilter) + { + ValidateProcessFilter(expectedCriteria, expectedvalue, DiagProcessFilterMatchType.Exact, actualFilter); + } + + private static void ValidateProcessFilter(DiagProcessFilterCriteria expectedCriteria, + string expectedvalue, + DiagProcessFilterMatchType expectedMatchType, + DiagProcessFilterEntry actualFilter) + { + Assert.Equal(expectedvalue, actualFilter.Value); + Assert.Equal(expectedCriteria, actualFilter.Criteria); + Assert.Equal(expectedMatchType, actualFilter.MatchType); + } + + private static DiagProcessFilterEntry CreateFilterEntry(ProcessKey processKey) + { + var processFilter = DiagProcessFilter.FromProcessKey(processKey); + Assert.Single(processFilter.Filters); + return processFilter.Filters.First(); + } + + private static DiagProcessFilterEntry CreateFilterEntry(ProcessFilterDescriptor filter) + { + return CreateOptions(filter).Filters.First(); + } + + private static DiagProcessFilter CreateOptions(params ProcessFilterDescriptor[] filters) + { + var filterOptions = new ProcessFilterOptions(); + foreach(var processFilter in filters) + { + filterOptions.Filters.Add(processFilter); + } + var filter = DiagProcessFilter.FromConfiguration(filterOptions); + Assert.Equal(filters.Length, filter.Filters.Count); + + return filter; + } + } +} diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Microsoft.Diagnostics.Monitoring.UnitTests.csproj b/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Microsoft.Diagnostics.Monitoring.UnitTests.csproj index fe3afd6e559..64a990c716f 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Microsoft.Diagnostics.Monitoring.UnitTests.csproj +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Microsoft.Diagnostics.Monitoring.UnitTests.csproj @@ -1,42 +1,14 @@  - - netcoreapp3.1;net5.0;net6.0 - $(DefineConstants);UNITTEST - - - - - - - - - - - - - - - - - - - - - - - - - - - - false - - - - - - - - + + net6.0 + $(DefineConstants);UNITTEST + + + + + + + + From e5ab0e5c2265ceb2b39348187208d6f22229c646 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 5 Jun 2021 12:26:33 +0000 Subject: [PATCH 031/185] Update dependencies from https://github.com/dotnet/arcade build 20210604.1 (#401) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- global.json | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 7b5a00efe81..cf86e085aec 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -14,13 +14,13 @@ - + https://github.com/dotnet/arcade - 78da7776965b428ff31da8f1ff2cb073506212b7 + 85a65ea1fca1d0867f699fed44d191358270bf6a - + https://github.com/dotnet/arcade - 78da7776965b428ff31da8f1ff2cb073506212b7 + 85a65ea1fca1d0867f699fed44d191358270bf6a https://github.com/dotnet/symstore diff --git a/eng/Versions.props b/eng/Versions.props index 95ad64f9f8e..98e476d3abb 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -27,7 +27,7 @@ --> - 6.0.0-beta.21303.2 + 6.0.0-beta.21304.1 6.0.0-preview.6.21304.1 diff --git a/global.json b/global.json index 5b7a7e42463..a04f0564d50 100644 --- a/global.json +++ b/global.json @@ -16,6 +16,6 @@ }, "msbuild-sdks": { "Microsoft.Build.NoTargets": "2.0.1", - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21303.2" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21304.1" } } From 5e16c1f6abbae5e776da161484ba78f4a2fd9e61 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 5 Jun 2021 12:31:21 +0000 Subject: [PATCH 032/185] Update dependencies from https://github.com/dotnet/diagnostics build 20210604.1 (#400) [main] Update dependencies from dotnet/diagnostics --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index cf86e085aec..11544ee8343 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics - 31c28f26c1d025742e3d9dcf272672f2e5bc384c + 2b97d468c419a9bfc5bdbb8a14dbed67697f2461 - + https://github.com/dotnet/diagnostics - 31c28f26c1d025742e3d9dcf272672f2e5bc384c + 2b97d468c419a9bfc5bdbb8a14dbed67697f2461 diff --git a/eng/Versions.props b/eng/Versions.props index 98e476d3abb..99fdfefeee0 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-preview.6.21304.1 - 5.0.0-preview.21303.1 - 5.0.0-preview.21303.1 + 5.0.0-preview.21304.1 + 5.0.0-preview.21304.1 6.0.0-preview.6.21304.1 From df74707ccea4b9f9bbb300a1d09dd910c7561c63 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 5 Jun 2021 12:38:31 +0000 Subject: [PATCH 033/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210604.9 (#403) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 11544ee8343..74b0172654a 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - 180b4ad56ceac9956b4b44187f33009ee671f40c + d09b931628258850ba0c56d17b3731b72ddf88f5 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 99fdfefeee0..2fa2029ba54 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21304.1 - 6.0.0-preview.6.21304.1 + 6.0.0-preview.6.21304.9 5.0.0-preview.21304.1 5.0.0-preview.21304.1 From 217b10ae3da4bb8a7dc5f3691e9a3ada701b8374 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 5 Jun 2021 12:43:25 +0000 Subject: [PATCH 034/185] Update dependencies from https://github.com/dotnet/runtime build 20210605.1 (#402) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 74b0172654a..044155ee22a 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore d09b931628258850ba0c56d17b3731b72ddf88f5 - + https://github.com/dotnet/runtime - 5a1b8223dab2f7954e7f206095ba937e5d237299 + 00c4a492a5d34547457936be2a56f894ce5eb241 diff --git a/eng/Versions.props b/eng/Versions.props index 2fa2029ba54..0ba509591bb 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21304.1 5.0.0-preview.21304.1 - 6.0.0-preview.6.21304.1 + 6.0.0-preview.6.21305.1 1.0.215101 From ab717afccac06617d1203bccae65c003a6617ef2 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sun, 6 Jun 2021 12:30:15 +0000 Subject: [PATCH 035/185] Update dependencies from https://github.com/dotnet/runtime build 20210606.1 (#404) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 044155ee22a..d77b9e6f840 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore d09b931628258850ba0c56d17b3731b72ddf88f5 - + https://github.com/dotnet/runtime - 00c4a492a5d34547457936be2a56f894ce5eb241 + 5b8e1780ad7740e632c285bc2af13a8d0b20c5a9 diff --git a/eng/Versions.props b/eng/Versions.props index 0ba509591bb..3d13c2356f9 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21304.1 5.0.0-preview.21304.1 - 6.0.0-preview.6.21305.1 + 6.0.0-preview.6.21306.1 1.0.215101 From 53d220c436e1305802cd79c7be584b66beb2b65d Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sun, 6 Jun 2021 12:30:24 +0000 Subject: [PATCH 036/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210605.2 (#405) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index d77b9e6f840..2934a750d5f 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - d09b931628258850ba0c56d17b3731b72ddf88f5 + 98ce09fb4c891901f73c7cf8faa0602af19848ad https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 3d13c2356f9..29a936cee22 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21304.1 - 6.0.0-preview.6.21304.9 + 6.0.0-preview.6.21305.2 5.0.0-preview.21304.1 5.0.0-preview.21304.1 From a3d47a5b65ef69d2f31d048c1ac388fe7404a951 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 7 Jun 2021 12:39:30 +0000 Subject: [PATCH 037/185] Update dependencies from https://github.com/dotnet/runtime build 20210607.1 (#406) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 2934a750d5f..f15f2d4a30a 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 98ce09fb4c891901f73c7cf8faa0602af19848ad - + https://github.com/dotnet/runtime - 5b8e1780ad7740e632c285bc2af13a8d0b20c5a9 + 1d2aa13ffc256a8c3f645de9c4d0f1d4f3296711 diff --git a/eng/Versions.props b/eng/Versions.props index 29a936cee22..cfbd1b91745 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21304.1 5.0.0-preview.21304.1 - 6.0.0-preview.6.21306.1 + 6.0.0-preview.6.21307.1 1.0.215101 From ef1018c202dfa98b2d53bf6702e92ea3d83bd832 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 7 Jun 2021 12:39:38 +0000 Subject: [PATCH 038/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210606.3 (#407) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index f15f2d4a30a..68b8d1087f9 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - 98ce09fb4c891901f73c7cf8faa0602af19848ad + 30e2d2265545c006c5feba3ebfdf39f7e2db3730 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index cfbd1b91745..2c4684552a0 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21304.1 - 6.0.0-preview.6.21305.2 + 6.0.0-preview.6.21306.3 5.0.0-preview.21304.1 5.0.0-preview.21304.1 From bf39b748ce9c9039796d81fe95c5b249443b07a8 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 8 Jun 2021 12:28:48 +0000 Subject: [PATCH 039/185] Update dependencies from https://github.com/dotnet/diagnostics build 20210607.1 (#408) [main] Update dependencies from dotnet/diagnostics --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 68b8d1087f9..766dee99ba9 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics - 2b97d468c419a9bfc5bdbb8a14dbed67697f2461 + 73d2fa7d4c88d140b79dffea8a12f089af0c135f - + https://github.com/dotnet/diagnostics - 2b97d468c419a9bfc5bdbb8a14dbed67697f2461 + 73d2fa7d4c88d140b79dffea8a12f089af0c135f diff --git a/eng/Versions.props b/eng/Versions.props index 2c4684552a0..fa5834c7f7c 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-preview.6.21306.3 - 5.0.0-preview.21304.1 - 5.0.0-preview.21304.1 + 5.0.0-preview.21307.1 + 5.0.0-preview.21307.1 6.0.0-preview.6.21307.1 From 2913d93672cda3b45ee9c5c78274563fae7be9ab Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 8 Jun 2021 12:36:19 +0000 Subject: [PATCH 040/185] Update dependencies from https://github.com/dotnet/runtime build 20210608.1 (#409) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 766dee99ba9..e7163d3cac3 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 30e2d2265545c006c5feba3ebfdf39f7e2db3730 - + https://github.com/dotnet/runtime - 1d2aa13ffc256a8c3f645de9c4d0f1d4f3296711 + d52f925042937397bef2db312d11ae0c2ed76c7f diff --git a/eng/Versions.props b/eng/Versions.props index fa5834c7f7c..4f83411d9c2 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21307.1 5.0.0-preview.21307.1 - 6.0.0-preview.6.21307.1 + 6.0.0-preview.6.21308.1 1.0.215101 From 5a46e07178ad091b7f77a39410183214e9c2ebb1 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 8 Jun 2021 12:36:28 +0000 Subject: [PATCH 041/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210608.1 (#410) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index e7163d3cac3..32b7a82cabc 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - 30e2d2265545c006c5feba3ebfdf39f7e2db3730 + 49a10149bc62df40ac21c1227f792c8b4edb0d8d https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 4f83411d9c2..b6cf1b2fa5d 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21304.1 - 6.0.0-preview.6.21306.3 + 6.0.0-preview.6.21308.1 5.0.0-preview.21307.1 5.0.0-preview.21307.1 From b04260225d0547c67caa332e9b7887f17fc95b44 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 9 Jun 2021 12:37:32 +0000 Subject: [PATCH 042/185] Update dependencies from https://github.com/dotnet/runtime build 20210609.2 (#414) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 32b7a82cabc..398fde6755b 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 49a10149bc62df40ac21c1227f792c8b4edb0d8d - + https://github.com/dotnet/runtime - d52f925042937397bef2db312d11ae0c2ed76c7f + c3096469dd6d9c9c07b56d5d5009a54ed4f0e715 diff --git a/eng/Versions.props b/eng/Versions.props index b6cf1b2fa5d..3e1fbc8aefd 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21307.1 5.0.0-preview.21307.1 - 6.0.0-preview.6.21308.1 + 6.0.0-preview.6.21309.2 1.0.215101 From 2ca893e3b9bb98baa2c16fe1532df9382223f5ee Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 9 Jun 2021 12:37:41 +0000 Subject: [PATCH 043/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210608.15 (#415) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 398fde6755b..85d1c9a656d 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - 49a10149bc62df40ac21c1227f792c8b4edb0d8d + c9ed7e65d667d5f2e6d659ee0ac7c46f82a1305b https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 3e1fbc8aefd..7e4f269657f 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21304.1 - 6.0.0-preview.6.21308.1 + 6.0.0-preview.6.21308.15 5.0.0-preview.21307.1 5.0.0-preview.21307.1 From 866bbd5b050cb57aafd15565d639cd89df6e894e Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 9 Jun 2021 18:57:48 +0000 Subject: [PATCH 044/185] Update dependencies from https://github.com/dotnet/diagnostics build 20210608.1 (#413) [main] Update dependencies from dotnet/diagnostics --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 85d1c9a656d..64e9f04c8f1 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics - 73d2fa7d4c88d140b79dffea8a12f089af0c135f + 1cad2e2e693eacd118a81f633d0cb9a0847f1b44 - + https://github.com/dotnet/diagnostics - 73d2fa7d4c88d140b79dffea8a12f089af0c135f + 1cad2e2e693eacd118a81f633d0cb9a0847f1b44 diff --git a/eng/Versions.props b/eng/Versions.props index 7e4f269657f..9e01584abca 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-preview.6.21308.15 - 5.0.0-preview.21307.1 - 5.0.0-preview.21307.1 + 5.0.0-preview.21308.1 + 5.0.0-preview.21308.1 6.0.0-preview.6.21309.2 From ad61b3237e91c1542b1a9a1118cfd8655bf11564 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 10 Jun 2021 12:29:24 +0000 Subject: [PATCH 045/185] Update dependencies from https://github.com/dotnet/diagnostics build 20210609.1 (#417) [main] Update dependencies from dotnet/diagnostics --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 64e9f04c8f1..15b3e0bfcad 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics - 1cad2e2e693eacd118a81f633d0cb9a0847f1b44 + 0c9868f5ad552226acf324c1e9324e7db6a9e3d0 - + https://github.com/dotnet/diagnostics - 1cad2e2e693eacd118a81f633d0cb9a0847f1b44 + 0c9868f5ad552226acf324c1e9324e7db6a9e3d0 diff --git a/eng/Versions.props b/eng/Versions.props index 9e01584abca..64ecd92baf4 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-preview.6.21308.15 - 5.0.0-preview.21308.1 - 5.0.0-preview.21308.1 + 5.0.0-preview.21309.1 + 5.0.0-preview.21309.1 6.0.0-preview.6.21309.2 From 9886e8bb9fbcbdb0a4cc5e38231d39dd572de382 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 10 Jun 2021 12:37:40 +0000 Subject: [PATCH 046/185] Update dependencies from https://github.com/dotnet/runtime build 20210610.1 (#418) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 15b3e0bfcad..c7d381a3858 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore c9ed7e65d667d5f2e6d659ee0ac7c46f82a1305b - + https://github.com/dotnet/runtime - c3096469dd6d9c9c07b56d5d5009a54ed4f0e715 + 00ee1c18715723e62484c9bc8a14f517455fc3b3 diff --git a/eng/Versions.props b/eng/Versions.props index 64ecd92baf4..b9d9bbdbdb8 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21309.1 5.0.0-preview.21309.1 - 6.0.0-preview.6.21309.2 + 6.0.0-preview.6.21310.1 1.0.215101 From 4dba3888ff452261f33dae38895533501be25555 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 10 Jun 2021 15:34:52 +0000 Subject: [PATCH 047/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210609.7 (#419) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index c7d381a3858..8575d545069 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - c9ed7e65d667d5f2e6d659ee0ac7c46f82a1305b + 6a929c3796f048d619bdd05969972d3a84669aac https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index b9d9bbdbdb8..8d970d02a50 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21304.1 - 6.0.0-preview.6.21308.15 + 6.0.0-preview.6.21309.7 5.0.0-preview.21309.1 5.0.0-preview.21309.1 From 21e68043900e828fa027a97f06da0787c579423f Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 11 Jun 2021 12:23:59 +0000 Subject: [PATCH 048/185] Update dependencies from https://github.com/dotnet/diagnostics build 20210610.1 (#421) [main] Update dependencies from dotnet/diagnostics --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 8575d545069..a2f4a32d8df 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics - 0c9868f5ad552226acf324c1e9324e7db6a9e3d0 + 3d57bee719e6db6b19dce4026bdc7c47b1c3519b - + https://github.com/dotnet/diagnostics - 0c9868f5ad552226acf324c1e9324e7db6a9e3d0 + 3d57bee719e6db6b19dce4026bdc7c47b1c3519b diff --git a/eng/Versions.props b/eng/Versions.props index 8d970d02a50..531ceaebfe2 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-preview.6.21309.7 - 5.0.0-preview.21309.1 - 5.0.0-preview.21309.1 + 5.0.0-preview.21310.1 + 5.0.0-preview.21310.1 6.0.0-preview.6.21310.1 From 9db82bc518807309239c256a5b4e7776f0c652af Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 11 Jun 2021 12:35:59 +0000 Subject: [PATCH 049/185] Update dependencies from https://github.com/dotnet/runtime build 20210611.1 (#422) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index a2f4a32d8df..b6724d538e9 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 6a929c3796f048d619bdd05969972d3a84669aac - + https://github.com/dotnet/runtime - 00ee1c18715723e62484c9bc8a14f517455fc3b3 + ddbce77f82aa22d66905ec017d01dbdb8dd0ca1d diff --git a/eng/Versions.props b/eng/Versions.props index 531ceaebfe2..8f46ff6fbaf 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21310.1 5.0.0-preview.21310.1 - 6.0.0-preview.6.21310.1 + 6.0.0-preview.6.21311.1 1.0.215101 From 8ecd260471389d521975b250d944220493804116 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 11 Jun 2021 12:36:08 +0000 Subject: [PATCH 050/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210610.11 (#423) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index b6724d538e9..9d3224824a6 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - 6a929c3796f048d619bdd05969972d3a84669aac + b72c0657573fb1f25f580ff51f73f268943837f1 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 8f46ff6fbaf..95a1cc4544b 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21304.1 - 6.0.0-preview.6.21309.7 + 6.0.0-preview.6.21310.11 5.0.0-preview.21310.1 5.0.0-preview.21310.1 From bb49eee5f295f5887de001ab3105a4bb2d1ad67f Mon Sep 17 00:00:00 2001 From: Justin Anderson Date: Fri, 11 Jun 2021 16:02:09 -0700 Subject: [PATCH 051/185] Add release process docs (#398) --- documentation/README.md | 1 + documentation/official-build-instructions.md | 14 ++--- documentation/release-process.md | 65 ++++++++++++++++++++ 3 files changed, 71 insertions(+), 9 deletions(-) create mode 100644 documentation/release-process.md diff --git a/documentation/README.md b/documentation/README.md index 84f3f5cd680..05e30c901e0 100644 --- a/documentation/README.md +++ b/documentation/README.md @@ -29,3 +29,4 @@ When running a dotnet application differences in diverse local and production en - [Troubleshooting](./troubleshooting.md) - [Clone, build, and test the repo](./building.md) - [Official Build Instructions](./official-build-instructions.md) +- [Release Process](./release-process.md) \ No newline at end of file diff --git a/documentation/official-build-instructions.md b/documentation/official-build-instructions.md index f513657e781..4c88fb8c77a 100644 --- a/documentation/official-build-instructions.md +++ b/documentation/official-build-instructions.md @@ -2,15 +2,11 @@ > *WARNING*: These instructions will only work internally at Microsoft. -This signs and publishes the following packages to the tools feed (https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json): +To produce an official build, invoke the [internal pipeline](https://dev.azure.com/dnceng/internal/_build?definitionId=954). + +This signs and publishes the following packages to the [dotnet-tools](https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json) feed: - dotnet-monitor - - Microsoft.Diagnostics.NETCore.Client -## To release the latest tools: +The packages are only published to the feed from builds of the `main` and `release/*` branches. -1. Merge the desired commits for this release from the master branch to the release branch. -2. Kick off an official build in the [internal pipeline](https://dev.azure.com/dnceng/internal/_build?definitionId=954) for the desired branch after the changes have been properly mirrored. -3. Change all the package version references as needed in any documentation if needed. -4. Download the above packages from the successful official build under "Artifacts" -> "PackageArtifacts". -5. Upload these packages to NuGet.org. -6. Create a new "release" in the [releases](https://github.com/dotnet/dotnet-monitor/releases) dotnet-monitor repo release tab with the package version (not the official build id) as the "tag". Add any release notes about known issues, issues fixed and new features. +The release process is documented at [Release Process](./release-process.md). \ No newline at end of file diff --git a/documentation/release-process.md b/documentation/release-process.md new file mode 100644 index 00000000000..dffea5643fa --- /dev/null +++ b/documentation/release-process.md @@ -0,0 +1,65 @@ +# Release Process + +## Merge to Release Branch + +1. Merge from the `main` branch to the appropriate release branch (e.g. `release/5.0`). +1. In `/eng/Versions.props`, update `dotnet/diagnostics` dependencies to versions from the corresponding release of the `dotnet/diagnostics` repo. +1. In `/eng/Version.props`, ensure that `` is set appropriately. See the documentation next to this setting for the appropriate values. In release branches, its value should either be `prerelease` or `release`. This setting, in combination with the version settings, determine for which 'channel' the aks.ms links are created. +4. Complete at least one successful build. + +## Build Release Branch + +The official build will not automatically trigger for release branches. Each time a new build is needed, the pipeline will need to be invoked manually. + +1. Wait for changes to be mirrored from [GitHub repository](https://github.com/dotnet/dotnet-monitor) to the [internal repository](https://dev.azure.com/dnceng/internal/_git/dotnet-dotnet-monitor). +1. Invoke the [internal pipeline](https://dev.azure.com/dnceng/internal/_build?definitionId=954) for the release branch. + +The result of the successful build pushes packages to the [dotnet-tools](https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json) feed, pushes symbols to symbol feeds, and generates aka.ms links for the following: +- `aka.ms/dotnet/diagnostics/monitor{channel}/dotnet-monitor.nupkg.version` +- `aka.ms/dotnet/diagnostics/monitor{channel}/dotnet-monitor.nupkg.sha512` + +The `channel` value is used by the `dotnet-docker` repository to consume the correct latest version. This value is: +- `{major}.{minor}/daily` for builds from non-release branches. For example, `channel` is `5.0/daily` for the `main` branch. +- `{major}.{minor}/{preReleaseVersionLabel}.{preReleaseVersionIteration}` for non-final releases in release branches. For example, `channel` is `5.0/preview.5` for the `release/5.0` branch. +- `{majorVersion}.{minorVersion}/release` for final release in release branches. For example, `channel` is `5.0/release` for the `release/5.0` if its `` is set to `release`. + +## Update Nightly Docker Ingestion + +### Update Pipeline Variable for Release + +The `dotnet-docker` repository runs an update process each day that detects the latest version of a given `dotnet-monitor` channel. During the stabilization/testing/release period for a release of `dotnet-monitor`, the update process should be changed to pick up builds for the release branch. + +The `monitorChannel` pipeline variable of the [dotnet-docker-update-dependencies](https://dev.azure.com/dnceng/internal/_build?definitionId=470) pipeline instructs the update process of which channel to use in order to update the `nightly` branch. Normally, its value is `5.0/daily` to pull the latest daily build. However, during the stabilization and release of dotnet-monitor, it should be set to the prerelease channel (e.g. `5.0/preview.5`) or release channel (e.g. `5.0/release`) value. + +### Revert Pipeline Variable After Release + +After the release has been completed, this pipeline variable should be changed to the appropriate daily channel (e.g. `5.0/daily`). + +### Image Update Process + +The `dotnet-docker` repository typically updates the `nightly` branch with newer versions each morning by creating a pull request that targets the `nightly` branch with the new version information which needs to be approved by the `dotnet-docker` team. Upon completion, the `nightly` branch build will automatically run and create the new nightly images. + +The nightly image is `mcr.microsoft.com/dotnet/nightly/monitor`. The tag list is https://mcr.microsoft.com/v2/dotnet/nightly/monitor/tags/list. + +## Stabilization + +1. Fix issues for the release in the release branch. Backport fixes to `main` branch and other prior release branches as needed. +1. Invoke [build](<#Build Release Branch>) pipeline as needed. +1. After successful build, test changes from [dotnet-tools](https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json) feed. Images from the `nightly` branch of the `dotnet-docker` repository will be recreated the next day after the successful build of the release branch. + +## Release to nuget.org and Add GitHub Release + +1. Start [release pipeline](https://dev.azure.com/dnceng/internal/_release?_a=releases&view=mine&definitionId=105). + 1. Set BAR_ID from value of the [internal pipeline](https://dev.azure.com/dnceng/internal/_build?definitionId=954). + 1. Set release notes path to a file share path that contains the release notes for this release. +1. Approve the sign off step when ready to publish. + +The remainder of the release will automatically push NuGet packages to nuget.org, [tag](https://github.com/dotnet/dotnet-monitor/tags) the commit from the build with the release version, and add a new [GitHub release](https://github.com/dotnet/dotnet-monitor/releases). + +## Release Docker Images + +1. Contact `dotnet-docker` team with final version that should be released. This version should be latest version in the `nightly` branch. +1. The `dotnet-docker` team will merge from `nightly` branch to `main` branch and wait for `dotnet-monitor` team approval. Typically, these changes are completed the day before the release date. +1. The `dotnet-docker` team will start the build ahead of the release and wait for the all-clear from `dotnet-monitor` team before publishing the images. + +The release image is `mcr.microsoft.com/dotnet/monitor`. The tag list is https://mcr.microsoft.com/v2/dotnet/monitor/tags/list. \ No newline at end of file From 96f41af9a99f461fef2bc4f3b7b9f37aa5bb0750 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 12 Jun 2021 12:26:56 +0000 Subject: [PATCH 052/185] Update dependencies from https://github.com/dotnet/arcade build 20210611.3 (#427) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 8 +- eng/Versions.props | 2 +- eng/common/dotnet-install.sh | 2 +- eng/common/internal-feed-operations.ps1 | 6 +- eng/common/internal-feed-operations.sh | 2 +- eng/common/sdk-task.ps1 | 4 +- eng/common/sdl/execute-all-sdl-tools.ps1 | 2 +- eng/common/sdl/init-sdl.ps1 | 2 +- eng/common/sdl/run-sdl.ps1 | 2 +- eng/common/templates/job/onelocbuild.yml | 8 ++ eng/common/tools.ps1 | 99 +++++++++++------------- eng/common/tools.sh | 9 ++- global.json | 4 +- 13 files changed, 76 insertions(+), 74 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 9d3224824a6..28470372a2d 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -14,13 +14,13 @@ - + https://github.com/dotnet/arcade - 85a65ea1fca1d0867f699fed44d191358270bf6a + 4a2b475948d498b89fedef7cf890883f49bc1ea3 - + https://github.com/dotnet/arcade - 85a65ea1fca1d0867f699fed44d191358270bf6a + 4a2b475948d498b89fedef7cf890883f49bc1ea3 https://github.com/dotnet/symstore diff --git a/eng/Versions.props b/eng/Versions.props index 95a1cc4544b..194087189b5 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -27,7 +27,7 @@ --> - 6.0.0-beta.21304.1 + 6.0.0-beta.21311.3 6.0.0-preview.6.21310.11 diff --git a/eng/common/dotnet-install.sh b/eng/common/dotnet-install.sh index d6efeb44340..fdfeea66e7d 100755 --- a/eng/common/dotnet-install.sh +++ b/eng/common/dotnet-install.sh @@ -70,7 +70,7 @@ case $cpuname in ;; esac -dotnetRoot="$repo_root/.dotnet" +dotnetRoot="${repo_root}.dotnet" if [[ $architecture != "" ]] && [[ $architecture != $buildarch ]]; then dotnetRoot="$dotnetRoot/$architecture" fi diff --git a/eng/common/internal-feed-operations.ps1 b/eng/common/internal-feed-operations.ps1 index 418c09930cf..92b77347d99 100644 --- a/eng/common/internal-feed-operations.ps1 +++ b/eng/common/internal-feed-operations.ps1 @@ -45,11 +45,11 @@ function SetupCredProvider { # Then, we set the 'VSS_NUGET_EXTERNAL_FEED_ENDPOINTS' environment variable to restore from the stable # feeds successfully - $nugetConfigPath = "$RepoRoot\NuGet.config" + $nugetConfigPath = Join-Path $RepoRoot "NuGet.config" if (-Not (Test-Path -Path $nugetConfigPath)) { Write-PipelineTelemetryError -Category 'Build' -Message 'NuGet.config file not found in repo root!' - ExitWithExitCode 1 + ExitWithExitCode 1 } $endpoints = New-Object System.Collections.ArrayList @@ -85,7 +85,7 @@ function SetupCredProvider { #Workaround for https://github.com/microsoft/msbuild/issues/4430 function InstallDotNetSdkAndRestoreArcade { - $dotnetTempDir = "$RepoRoot\dotnet" + $dotnetTempDir = Join-Path $RepoRoot "dotnet" $dotnetSdkVersion="2.1.507" # After experimentation we know this version works when restoring the SDK (compared to 3.0.*) $dotnet = "$dotnetTempDir\dotnet.exe" $restoreProjPath = "$PSScriptRoot\restore.proj" diff --git a/eng/common/internal-feed-operations.sh b/eng/common/internal-feed-operations.sh index e2233e78122..9378223ba09 100644 --- a/eng/common/internal-feed-operations.sh +++ b/eng/common/internal-feed-operations.sh @@ -39,7 +39,7 @@ function SetupCredProvider { # Then, we set the 'VSS_NUGET_EXTERNAL_FEED_ENDPOINTS' environment variable to restore from the stable # feeds successfully - local nugetConfigPath="$repo_root/NuGet.config" + local nugetConfigPath="{$repo_root}NuGet.config" if [ ! "$nugetConfigPath" ]; then Write-PipelineTelemetryError -category 'Build' "NuGet.config file not found in repo's root!" diff --git a/eng/common/sdk-task.ps1 b/eng/common/sdk-task.ps1 index 65f1d75f3d3..b1bca63ab1d 100644 --- a/eng/common/sdk-task.ps1 +++ b/eng/common/sdk-task.ps1 @@ -34,7 +34,7 @@ function Print-Usage() { function Build([string]$target) { $logSuffix = if ($target -eq 'Execute') { '' } else { ".$target" } $log = Join-Path $LogDir "$task$logSuffix.binlog" - $outputPath = Join-Path $ToolsetDir "$task\\" + $outputPath = Join-Path $ToolsetDir "$task\" MSBuild $taskProject ` /bl:$log ` @@ -64,7 +64,7 @@ try { $GlobalJson.tools | Add-Member -Name "vs" -Value (ConvertFrom-Json "{ `"version`": `"16.5`" }") -MemberType NoteProperty } if( -not ($GlobalJson.tools.PSObject.Properties.Name -match "xcopy-msbuild" )) { - $GlobalJson.tools | Add-Member -Name "xcopy-msbuild" -Value "16.8.0-preview3" -MemberType NoteProperty + $GlobalJson.tools | Add-Member -Name "xcopy-msbuild" -Value "16.10.0-preview2" -MemberType NoteProperty } if ($GlobalJson.tools."xcopy-msbuild".Trim() -ine "none") { $xcopyMSBuildToolsFolder = InitializeXCopyMSBuild $GlobalJson.tools."xcopy-msbuild" -install $true diff --git a/eng/common/sdl/execute-all-sdl-tools.ps1 b/eng/common/sdl/execute-all-sdl-tools.ps1 index 81b729f74a4..2881a56083c 100644 --- a/eng/common/sdl/execute-all-sdl-tools.ps1 +++ b/eng/common/sdl/execute-all-sdl-tools.ps1 @@ -32,7 +32,7 @@ try { $ErrorActionPreference = 'Stop' Set-StrictMode -Version 2.0 $disableConfigureToolsetImport = $true - $LASTEXITCODE = 0 + $global:LASTEXITCODE = 0 # `tools.ps1` checks $ci to perform some actions. Since the SDL # scripts don't necessarily execute in the same agent that run the diff --git a/eng/common/sdl/init-sdl.ps1 b/eng/common/sdl/init-sdl.ps1 index 1fe9271193c..3ac1d92b370 100644 --- a/eng/common/sdl/init-sdl.ps1 +++ b/eng/common/sdl/init-sdl.ps1 @@ -10,7 +10,7 @@ Param( $ErrorActionPreference = 'Stop' Set-StrictMode -Version 2.0 $disableConfigureToolsetImport = $true -$LASTEXITCODE = 0 +$global:LASTEXITCODE = 0 # `tools.ps1` checks $ci to perform some actions. Since the SDL # scripts don't necessarily execute in the same agent that run the diff --git a/eng/common/sdl/run-sdl.ps1 b/eng/common/sdl/run-sdl.ps1 index fe95ab35aa5..3d9c87aba6a 100644 --- a/eng/common/sdl/run-sdl.ps1 +++ b/eng/common/sdl/run-sdl.ps1 @@ -13,7 +13,7 @@ Param( $ErrorActionPreference = 'Stop' Set-StrictMode -Version 2.0 $disableConfigureToolsetImport = $true -$LASTEXITCODE = 0 +$global:LASTEXITCODE = 0 try { # `tools.ps1` checks $ci to perform some actions. Since the SDL diff --git a/eng/common/templates/job/onelocbuild.yml b/eng/common/templates/job/onelocbuild.yml index 2acdd5256dd..e8bc77d2ebb 100644 --- a/eng/common/templates/job/onelocbuild.yml +++ b/eng/common/templates/job/onelocbuild.yml @@ -18,6 +18,9 @@ parameters: LclSource: lclFilesInRepo LclPackageId: '' RepoType: gitHub + GitHubOrg: dotnet + MirrorRepo: '' + MirrorBranch: main condition: '' jobs: @@ -66,6 +69,11 @@ jobs: ${{ if eq(parameters.RepoType, 'gitHub') }}: repoType: ${{ parameters.RepoType }} gitHubPatVariable: "${{ parameters.GithubPat }}" + ${{ if ne(parameters.MirrorRepo, '') }}: + isMirrorRepoSelected: true + gitHubOrganization: ${{ parameters.GitHubOrg }} + mirrorRepo: ${{ parameters.MirrorRepo }} + mirrorBranch: ${{ parameters.MirrorBranch }} condition: ${{ parameters.condition }} - task: PublishBuildArtifacts@1 diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1 index 2d8a74f7d9e..5619c7aaee1 100644 --- a/eng/common/tools.ps1 +++ b/eng/common/tools.ps1 @@ -193,38 +193,42 @@ function InitializeDotNetCli([bool]$install, [bool]$createSdkLocationFile) { return $global:_DotNetInstallDir = $dotnetRoot } +function Retry($downloadBlock, $maxRetries = 5) { + $retries = 1 + + while($true) { + try { + & $downloadBlock + break + } + catch { + Write-PipelineTelemetryError -Category 'InitializeToolset' -Message $_ + } + + if (++$retries -le $maxRetries) { + $delayInSeconds = [math]::Pow(2, $retries) - 1 # Exponential backoff + Write-Host "Retrying. Waiting for $delayInSeconds seconds before next attempt ($retries of $maxRetries)." + Start-Sleep -Seconds $delayInSeconds + } + else { + Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "Unable to download file in $maxRetries attempts." + break + } + + } +} + function GetDotNetInstallScript([string] $dotnetRoot) { $installScript = Join-Path $dotnetRoot 'dotnet-install.ps1' if (!(Test-Path $installScript)) { Create-Directory $dotnetRoot $ProgressPreference = 'SilentlyContinue' # Don't display the console progress UI - it's a huge perf hit - - $maxRetries = 5 - $retries = 1 - $uri = "https://dot.net/$dotnetInstallScriptVersion/dotnet-install.ps1" - while($true) { - try { - Write-Host "GET $uri" - Invoke-WebRequest $uri -OutFile $installScript - break - } - catch { - Write-Host "Failed to download '$uri'" - Write-Error $_.Exception.Message -ErrorAction Continue - } - - if (++$retries -le $maxRetries) { - $delayInSeconds = [math]::Pow(2, $retries) - 1 # Exponential backoff - Write-Host "Retrying. Waiting for $delayInSeconds seconds before next attempt ($retries of $maxRetries)." - Start-Sleep -Seconds $delayInSeconds - } - else { - throw "Unable to download file in $maxRetries attempts." - } - - } + Retry({ + Write-Host "GET $uri" + Invoke-WebRequest $uri -OutFile $installScript + }) } return $installScript @@ -308,8 +312,8 @@ function InitializeVisualStudioMSBuild([bool]$install, [object]$vsRequirements = # If the version of msbuild is going to be xcopied, # use this version. Version matches a package here: - # https://dev.azure.com/dnceng/public/_packaging?_a=package&feed=dotnet-eng&package=RoslynTools.MSBuild&protocolType=NuGet&version=16.8.0-preview3&view=overview - $defaultXCopyMSBuildVersion = '16.8.0-preview3' + # https://dev.azure.com/dnceng/public/_packaging?_a=package&feed=dotnet-eng&package=RoslynTools.MSBuild&protocolType=NuGet&version=16.10.0-preview2&view=overview + $defaultXCopyMSBuildVersion = '16.10.0-preview2' if (!$vsRequirements) { $vsRequirements = $GlobalJson.tools.vs } $vsMinVersionStr = if ($vsRequirements.version) { $vsRequirements.version } else { $vsMinVersionReqdStr } @@ -403,9 +407,13 @@ function InitializeXCopyMSBuild([string]$packageVersion, [bool]$install) { } Create-Directory $packageDir + Write-Host "Downloading $packageName $packageVersion" $ProgressPreference = 'SilentlyContinue' # Don't display the console progress UI - it's a huge perf hit - Invoke-WebRequest "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/flat2/$packageName/$packageVersion/$packageName.$packageVersion.nupkg" -OutFile $packagePath + Retry({ + Invoke-WebRequest "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-eng/nuget/v3/flat2/$packageName/$packageVersion/$packageName.$packageVersion.nupkg" -OutFile $packagePath + }) + Unzip $packagePath $packageDir } @@ -442,27 +450,9 @@ function LocateVisualStudio([object]$vsRequirements = $null){ if (!(Test-Path $vsWhereExe)) { Create-Directory $vsWhereDir Write-Host 'Downloading vswhere' - $maxRetries = 5 - $retries = 1 - - while($true) { - try { - Invoke-WebRequest "https://netcorenativeassets.blob.core.windows.net/resource-packages/external/windows/vswhere/$vswhereVersion/vswhere.exe" -OutFile $vswhereExe - break - } - catch{ - Write-PipelineTelemetryError -Category 'InitializeToolset' -Message $_ - } - - if (++$retries -le $maxRetries) { - $delayInSeconds = [math]::Pow(2, $retries) - 1 # Exponential backoff - Write-Host "Retrying. Waiting for $delayInSeconds seconds before next attempt ($retries of $maxRetries)." - Start-Sleep -Seconds $delayInSeconds - } - else { - Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "Unable to download file in $maxRetries attempts." - } - } + Retry({ + Invoke-WebRequest "https://netcorenativeassets.blob.core.windows.net/resource-packages/external/windows/vswhere/$vswhereVersion/vswhere.exe" -OutFile $vswhereExe + }) } if (!$vsRequirements) { $vsRequirements = $GlobalJson.tools.vs } @@ -498,7 +488,7 @@ function InitializeBuildTool() { if (Test-Path variable:global:_BuildTool) { # If the requested msbuild parameters do not match, clear the cached variables. if($global:_BuildTool.Contains('ExcludePrereleaseVS') -and $global:_BuildTool.ExcludePrereleaseVS -ne $excludePrereleaseVS) { - Remove-Item variable:global:_BuildTool + Remove-Item variable:global:_BuildTool Remove-Item variable:global:_MSBuildExe } else { return $global:_BuildTool @@ -555,7 +545,7 @@ function GetDefaultMSBuildEngine() { function GetNuGetPackageCachePath() { if ($env:NUGET_PACKAGES -eq $null) { - # Use local cache on CI to ensure deterministic build. + # Use local cache on CI to ensure deterministic build. # Avoid using the http cache as workaround for https://github.com/NuGet/Home/issues/3116 # use global cache in dev builds to avoid cost of downloading packages. # For directory normalization, see also: https://github.com/NuGet/Home/issues/7968 @@ -712,7 +702,10 @@ function MSBuild-Core() { } foreach ($arg in $args) { - if ($arg -ne $null -and $arg.Trim() -ne "") { + if ($null -ne $arg -and $arg.Trim() -ne "") { + if ($arg.EndsWith('\')) { + $arg = $arg + "\" + } $cmdArgs += " `"$arg`"" } } @@ -784,7 +777,7 @@ function Get-Darc($version) { . $PSScriptRoot\pipeline-logging-functions.ps1 -$RepoRoot = Resolve-Path (Join-Path $PSScriptRoot '..\..') +$RepoRoot = Resolve-Path (Join-Path $PSScriptRoot '..\..\') $EngRoot = Resolve-Path (Join-Path $PSScriptRoot '..') $ArtifactsDir = Join-Path $RepoRoot 'artifacts' $ToolsetDir = Join-Path $ArtifactsDir 'toolset' diff --git a/eng/common/tools.sh b/eng/common/tools.sh index 5fad1846e5a..05ca99c6b28 100644 --- a/eng/common/tools.sh +++ b/eng/common/tools.sh @@ -485,13 +485,14 @@ _script_dir=`dirname "$_ResolvePath"` eng_root=`cd -P "$_script_dir/.." && pwd` repo_root=`cd -P "$_script_dir/../.." && pwd` -artifacts_dir="$repo_root/artifacts" +repo_root="${repo_root}/" +artifacts_dir="${repo_root}artifacts" toolset_dir="$artifacts_dir/toolset" -tools_dir="$repo_root/.tools" +tools_dir="${repo_root}.tools" log_dir="$artifacts_dir/log/$configuration" temp_dir="$artifacts_dir/tmp/$configuration" -global_json_file="$repo_root/global.json" +global_json_file="${repo_root}global.json" # determine if global.json contains a "runtimes" entry global_json_has_runtimes=false if command -v jq &> /dev/null; then @@ -504,7 +505,7 @@ fi # HOME may not be defined in some scenarios, but it is required by NuGet if [[ -z $HOME ]]; then - export HOME="$repo_root/artifacts/.home/" + export HOME="${repo_root}artifacts/.home/" mkdir -p "$HOME" fi diff --git a/global.json b/global.json index a04f0564d50..4dac87d987c 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "tools": { - "dotnet": "6.0.100-preview.3.21202.5", + "dotnet": "6.0.100-preview.4.21255.9", "runtimes": { "aspnetcore": [ "$(MicrosoftAspNetCoreApp31Version)", @@ -16,6 +16,6 @@ }, "msbuild-sdks": { "Microsoft.Build.NoTargets": "2.0.1", - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21304.1" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21311.3" } } From 49789cc7b333c9a0151cdd8c750f976c6369ad4f Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 12 Jun 2021 12:31:41 +0000 Subject: [PATCH 053/185] Update dependencies from https://github.com/dotnet/diagnostics build 20210611.1 (#426) [main] Update dependencies from dotnet/diagnostics --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 28470372a2d..b8a1e1e54d0 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics - 3d57bee719e6db6b19dce4026bdc7c47b1c3519b + 74a10577cb40711420783ee2f6e57bd91eae2ff9 - + https://github.com/dotnet/diagnostics - 3d57bee719e6db6b19dce4026bdc7c47b1c3519b + 74a10577cb40711420783ee2f6e57bd91eae2ff9 diff --git a/eng/Versions.props b/eng/Versions.props index 194087189b5..d2c4e9872f3 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-preview.6.21310.11 - 5.0.0-preview.21310.1 - 5.0.0-preview.21310.1 + 5.0.0-preview.21311.1 + 5.0.0-preview.21311.1 6.0.0-preview.6.21311.1 From 832d812203ce603265d2b1090b328708c51e8e9b Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 12 Jun 2021 12:36:55 +0000 Subject: [PATCH 054/185] Update dependencies from https://github.com/dotnet/runtime build 20210611.11 (#428) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index b8a1e1e54d0..2123ef43b16 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore b72c0657573fb1f25f580ff51f73f268943837f1 - + https://github.com/dotnet/runtime - ddbce77f82aa22d66905ec017d01dbdb8dd0ca1d + 2a011f802b83051d1381f7800131ca5734b4c59e diff --git a/eng/Versions.props b/eng/Versions.props index d2c4e9872f3..b7f5ebb9cc7 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21311.1 5.0.0-preview.21311.1 - 6.0.0-preview.6.21311.1 + 6.0.0-preview.6.21311.11 1.0.215101 From 1c0acacaa5891397177dba17ec2fc936898433a5 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 12 Jun 2021 12:37:05 +0000 Subject: [PATCH 055/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210611.10 (#429) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 2123ef43b16..3b4eedbb9f5 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - b72c0657573fb1f25f580ff51f73f268943837f1 + 40fdcfd3d9cb93908eb9d99e878d132dc3b51b38 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index b7f5ebb9cc7..00a5f86d4e5 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21311.3 - 6.0.0-preview.6.21310.11 + 6.0.0-preview.6.21311.10 5.0.0-preview.21311.1 5.0.0-preview.21311.1 From 09b9af7e0113340de5f14b8717d5af5b1a163fe9 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sun, 13 Jun 2021 12:30:59 +0000 Subject: [PATCH 056/185] Update dependencies from https://github.com/dotnet/runtime build 20210612.3 (#431) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 3b4eedbb9f5..c5a031e1113 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 40fdcfd3d9cb93908eb9d99e878d132dc3b51b38 - + https://github.com/dotnet/runtime - 2a011f802b83051d1381f7800131ca5734b4c59e + feae07921934805dc84d8d1c830b22008246b869 diff --git a/eng/Versions.props b/eng/Versions.props index 00a5f86d4e5..325ee6892d3 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21311.1 5.0.0-preview.21311.1 - 6.0.0-preview.6.21311.11 + 6.0.0-preview.6.21312.3 1.0.215101 From aa6184863120b35f0d3ea273d7c1139b201b6b62 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sun, 13 Jun 2021 12:31:07 +0000 Subject: [PATCH 057/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210612.4 (#432) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index c5a031e1113..730066d81ab 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - 40fdcfd3d9cb93908eb9d99e878d132dc3b51b38 + 5f8fce6221c5cdfa9f337b9694ee4bee527be275 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 325ee6892d3..a076b6d2fd3 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21311.3 - 6.0.0-preview.6.21311.10 + 6.0.0-preview.6.21312.4 5.0.0-preview.21311.1 5.0.0-preview.21311.1 From 2aee7277c19387565b01a0e38a91412b97d72c96 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 14 Jun 2021 12:35:46 +0000 Subject: [PATCH 058/185] Update dependencies from https://github.com/dotnet/runtime build 20210614.1 (#433) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 730066d81ab..09a3ac09978 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 5f8fce6221c5cdfa9f337b9694ee4bee527be275 - + https://github.com/dotnet/runtime - feae07921934805dc84d8d1c830b22008246b869 + af5c238556e204583b129cc8f5c7338f84dc2c40 diff --git a/eng/Versions.props b/eng/Versions.props index a076b6d2fd3..d791c413cc6 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21311.1 5.0.0-preview.21311.1 - 6.0.0-preview.6.21312.3 + 6.0.0-preview.6.21314.1 1.0.215101 From 5f6127c45bb118706327f7c6665bce8f2e76dad3 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 14 Jun 2021 18:04:42 +0000 Subject: [PATCH 059/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210613.2 (#434) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 09a3ac09978..ada2bee6273 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - 5f8fce6221c5cdfa9f337b9694ee4bee527be275 + 374a7a8ab46408f655e95eb4dc4e5cdc0aba182f https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index d791c413cc6..dbfa4696367 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21311.3 - 6.0.0-preview.6.21312.4 + 6.0.0-preview.6.21313.2 5.0.0-preview.21311.1 5.0.0-preview.21311.1 From eb67cb2a185439c9426daabd0d4e2bb8f68dd491 Mon Sep 17 00:00:00 2001 From: Justin Anderson Date: Mon, 14 Jun 2021 17:24:26 -0700 Subject: [PATCH 060/185] Fix obsolete type usage error in tests. (#435) --- .../AuthenticationTests.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/AuthenticationTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/AuthenticationTests.cs index 0dec4682b84..1d8cdf69a78 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/AuthenticationTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/AuthenticationTests.cs @@ -286,10 +286,7 @@ public async Task NegotiateAuthenticationSchemeTest() private static byte[] GenerateApiKey() { byte[] apiKey = new byte[32]; // 256 bits - - using RNGCryptoServiceProvider rngProvider = new(); - rngProvider.GetBytes(apiKey); - + RandomNumberGenerator.Fill(apiKey); return apiKey; } } From fca44ff5f546d08d02e93bd22d90eeb5c3f996ae Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 15 Jun 2021 15:59:34 +0000 Subject: [PATCH 061/185] Update dependencies from https://github.com/dotnet/runtime build 20210614.2 (#437) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index ada2bee6273..22032e4e41c 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 374a7a8ab46408f655e95eb4dc4e5cdc0aba182f - + https://github.com/dotnet/runtime - af5c238556e204583b129cc8f5c7338f84dc2c40 + bc16a7bd2dcca7f1f8ce70e75dc86a3fac3ffcd2 diff --git a/eng/Versions.props b/eng/Versions.props index dbfa4696367..d859bf0610c 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21311.1 5.0.0-preview.21311.1 - 6.0.0-preview.6.21314.1 + 6.0.0-preview.6.21314.2 1.0.215101 From 8b778905fb226423c31b59d961404224d9fe2551 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 15 Jun 2021 15:59:40 +0000 Subject: [PATCH 062/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210614.7 (#438) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 22032e4e41c..b66d4b715db 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - 374a7a8ab46408f655e95eb4dc4e5cdc0aba182f + 2713df3bc4f9364775785410827124a2c1c8864e https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index d859bf0610c..33307d223b6 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21311.3 - 6.0.0-preview.6.21313.2 + 6.0.0-preview.6.21314.7 5.0.0-preview.21311.1 5.0.0-preview.21311.1 From 7632e06019e1ee30f724912254a84063e17bab9d Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 15 Jun 2021 16:10:21 +0000 Subject: [PATCH 063/185] Update dependencies from https://github.com/dotnet/arcade build 20210614.1 (#436) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- global.json | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index b66d4b715db..51f551423ca 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -14,13 +14,13 @@ - + https://github.com/dotnet/arcade - 4a2b475948d498b89fedef7cf890883f49bc1ea3 + fc067a0928f1c8ca4ab3471e9f8edb592e96dec4 - + https://github.com/dotnet/arcade - 4a2b475948d498b89fedef7cf890883f49bc1ea3 + fc067a0928f1c8ca4ab3471e9f8edb592e96dec4 https://github.com/dotnet/symstore diff --git a/eng/Versions.props b/eng/Versions.props index 33307d223b6..9d9bffbc7ae 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -27,7 +27,7 @@ --> - 6.0.0-beta.21311.3 + 6.0.0-beta.21314.1 6.0.0-preview.6.21314.7 diff --git a/global.json b/global.json index 4dac87d987c..94db4b0dc63 100644 --- a/global.json +++ b/global.json @@ -16,6 +16,6 @@ }, "msbuild-sdks": { "Microsoft.Build.NoTargets": "2.0.1", - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21311.3" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21314.1" } } From a49fab2e0d015b301096f5eb60c6bb374ccbde7c Mon Sep 17 00:00:00 2001 From: Justin Anderson Date: Tue, 15 Jun 2021 09:31:04 -0700 Subject: [PATCH 064/185] Increase ASP.NET Core logging verbosity during tests. (#441) --- .../Runners/MonitorRunner.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Runners/MonitorRunner.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Runners/MonitorRunner.cs index 2e6b9b0aef9..7bbc31c4c5e 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Runners/MonitorRunner.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Runners/MonitorRunner.cs @@ -203,6 +203,8 @@ public async Task StartAsync(CancellationToken token) _adapter.Environment.Add("COMPlus_EnableDiagnostics", "0"); // Console output in JSON for easy parsing _adapter.Environment.Add("Logging__Console__FormatterName", "json"); + // Enable Information on ASP.NET Core logs for better ability to diagnose issues. + _adapter.Environment.Add("Logging__LogLevel__Microsoft.AspNetCore", "Information"); // Enable Debug on Startup class to get lifetime and address events _adapter.Environment.Add("Logging__LogLevel__Microsoft.Diagnostics.Tools.Monitor.Startup", "Debug"); From 190fa1c2d241158800f15db32a151524381d7bac Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 15 Jun 2021 17:01:15 +0000 Subject: [PATCH 065/185] Update dependencies from https://github.com/dotnet/diagnostics build 20210614.1 (#442) [main] Update dependencies from dotnet/diagnostics --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 51f551423ca..9b9f88bce01 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics - 74a10577cb40711420783ee2f6e57bd91eae2ff9 + b1420fc8dfb701ecd6095716c6deaa4ac885cafc - + https://github.com/dotnet/diagnostics - 74a10577cb40711420783ee2f6e57bd91eae2ff9 + b1420fc8dfb701ecd6095716c6deaa4ac885cafc diff --git a/eng/Versions.props b/eng/Versions.props index 9d9bffbc7ae..297f06ae4b9 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-preview.6.21314.7 - 5.0.0-preview.21311.1 - 5.0.0-preview.21311.1 + 5.0.0-preview.21314.1 + 5.0.0-preview.21314.1 6.0.0-preview.6.21314.2 From d94cc0c9d1f5c86ecf581bbe9fb158b18e407c84 Mon Sep 17 00:00:00 2001 From: Justin Anderson Date: Tue, 15 Jun 2021 11:01:12 -0700 Subject: [PATCH 066/185] Rename RestServer to WebApi (#420) --- dotnet-monitor.sln | 2 +- .../ActionContextExtensions.cs | 2 +- .../ArtifactMetadataNames.cs | 2 +- .../Auth/AuthConstants.cs | 2 +- .../ConfigurationHelper.cs | 2 +- .../ContentTypes.cs | 2 +- .../Controllers/DiagController.cs | 4 ++-- .../Controllers/DiagControllerExtensions.cs | 2 +- .../Controllers/MetricsController.cs | 2 +- .../CorsConfiguration.cs | 2 +- .../DiagProcessFilter.cs | 2 +- .../DiagnosticServices.cs | 2 +- .../EgressResult.cs | 2 +- .../EgressStreamResult.cs | 2 +- .../ExceptionExtensions.cs | 2 +- .../HostRestrictionAttribute.cs | 2 +- .../IDiagnosticServices.cs | 2 +- .../IEgressService.cs | 2 +- .../IMetricsPortsProvider.cs | 2 +- .../IMetricsStore.cs | 0 .../KeyValueLogScope.cs | 2 +- .../KeyValueLogScopeExtensions.cs | 2 +- .../LogFormat.cs | 2 +- .../LoggingExtensions.cs | 2 +- .../MetricsLogger.cs | 0 .../MetricsOptions.cs | 2 +- .../MetricsOptionsDefaults.cs | 2 +- .../MetricsService.cs | 2 +- .../MetricsStore.cs | 0 .../MetricsStoreService.cs | 2 +- ...osoft.Diagnostics.Monitoring.WebApi.csproj} | 2 +- .../Models/DumpType.cs | 2 +- .../Models/EventPipeConfiguration.cs | 2 +- .../Models/EventPipeProvider.cs | 4 ++-- .../Models/LogsConfiguration.cs | 2 +- .../Models/ProcessIdentifier.cs | 2 +- .../Models/ProcessInfo.cs | 2 +- .../Models/TraceProfile.cs | 2 +- .../OutputStreamResult.cs | 2 +- .../ProcessFilterOptions.cs | 2 +- .../ProcessKey.cs | 0 .../ProducesWithProblemDetailsAttribute.cs | 4 ++-- .../RequestThrottling/RequestLimitAttribute.cs | 2 +- .../ScopeState.cs | 0 .../StorageOptions.cs | 2 +- .../StorageOptionsDefaults.cs | 2 +- .../StreamingLogger.cs | 2 +- .../Validation/IntegerOrHexStringAttribute.cs | 2 +- .../BadRequestResponseDocumentFilter.cs | 2 +- .../Program.cs | 2 +- ...RemoveFailureContentTypesOperationFilter.cs | 2 +- ...iagnostics.Monitoring.Tool.UnitTests.csproj | 18 +++++++++--------- .../DefaultProcessConfigurationTests.cs | 2 +- ...oft.Diagnostics.Monitoring.UnitTests.csproj | 2 +- .../Auth/ApiKeyAuthenticationHandler.cs | 2 +- .../Auth/UserAuthorizationHandler.cs | 2 +- .../DiagnosticsMonitorCommandHandler.cs | 2 +- .../Egress/AzureBlobEgressFactory.cs | 2 +- .../Configuration/EgressConfigureOptions.cs | 2 +- .../Egress/ConfiguredEgressProvider.cs | 2 +- .../dotnet-monitor/Egress/EgressService.cs | 2 +- .../Egress/FileSystemEgressFactory.cs | 2 +- .../GenerateApiKeyCommandHandler.cs | 2 +- src/Tools/dotnet-monitor/LoggingExtensions.cs | 2 +- .../dotnet-monitor/MetricsPortsProvider.cs | 2 +- .../ServiceCollectionExtensions.cs | 2 +- src/Tools/dotnet-monitor/Startup.cs | 4 ++-- src/Tools/dotnet-monitor/Throttling.cs | 2 +- src/Tools/dotnet-monitor/dotnet-monitor.csproj | 2 +- 69 files changed, 76 insertions(+), 76 deletions(-) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/ActionContextExtensions.cs (98%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/ArtifactMetadataNames.cs (95%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/Auth/AuthConstants.cs (91%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/ConfigurationHelper.cs (93%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/ContentTypes.cs (92%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/Controllers/DiagController.cs (99%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/Controllers/DiagControllerExtensions.cs (98%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/Controllers/MetricsController.cs (97%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/CorsConfiguration.cs (92%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/DiagProcessFilter.cs (99%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/DiagnosticServices.cs (99%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/EgressResult.cs (89%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/EgressStreamResult.cs (98%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/ExceptionExtensions.cs (91%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/HostRestrictionAttribute.cs (96%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/IDiagnosticServices.cs (97%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/IEgressService.cs (94%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/IMetricsPortsProvider.cs (91%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/IMetricsStore.cs (100%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/KeyValueLogScope.cs (97%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/KeyValueLogScopeExtensions.cs (94%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/LogFormat.cs (88%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/LoggingExtensions.cs (98%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/MetricsLogger.cs (100%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/MetricsOptions.cs (97%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/MetricsOptionsDefaults.cs (91%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/MetricsService.cs (98%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/MetricsStore.cs (100%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/MetricsStoreService.cs (92%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer/Microsoft.Diagnostics.Monitoring.RestServer.csproj => Microsoft.Diagnostics.Monitoring.WebApi/Microsoft.Diagnostics.Monitoring.WebApi.csproj} (95%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/Models/DumpType.cs (86%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/Models/EventPipeConfiguration.cs (92%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/Models/EventPipeProvider.cs (88%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/Models/LogsConfiguration.cs (95%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/Models/ProcessIdentifier.cs (91%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/Models/ProcessInfo.cs (93%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/Models/TraceProfile.cs (85%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/OutputStreamResult.cs (97%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/ProcessFilterOptions.cs (97%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/ProcessKey.cs (100%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/ProducesWithProblemDetailsAttribute.cs (93%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/RequestThrottling/RequestLimitAttribute.cs (90%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/ScopeState.cs (100%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/StorageOptions.cs (92%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/StorageOptionsDefaults.cs (89%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/StreamingLogger.cs (99%) rename src/{Microsoft.Diagnostics.Monitoring.RestServer => Microsoft.Diagnostics.Monitoring.WebApi}/Validation/IntegerOrHexStringAttribute.cs (97%) diff --git a/dotnet-monitor.sln b/dotnet-monitor.sln index 0da23f8ea33..1e0d0587aa8 100644 --- a/dotnet-monitor.sln +++ b/dotnet-monitor.sln @@ -9,7 +9,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{B62728C8 EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "dotnet-monitor", "src\Tools\dotnet-monitor\dotnet-monitor.csproj", "{C57F7656-6663-4A3C-BE38-B75C6C57E77D}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Diagnostics.Monitoring.RestServer", "src\Microsoft.Diagnostics.Monitoring.RestServer\Microsoft.Diagnostics.Monitoring.RestServer.csproj", "{B54DE8DD-6591-45C2-B9F7-22C4A23A384C}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Diagnostics.Monitoring.WebApi", "src\Microsoft.Diagnostics.Monitoring.WebApi\Microsoft.Diagnostics.Monitoring.WebApi.csproj", "{B54DE8DD-6591-45C2-B9F7-22C4A23A384C}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{B24CD8F2-D809-4DB8-89A1-D45FA9218020}" ProjectSection(SolutionItems) = preProject diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/ActionContextExtensions.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/ActionContextExtensions.cs similarity index 98% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/ActionContextExtensions.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/ActionContextExtensions.cs index 4f05615a8f6..ad81d41cda4 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/ActionContextExtensions.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/ActionContextExtensions.cs @@ -12,7 +12,7 @@ using System.Threading; using System.Threading.Tasks; -namespace Microsoft.Diagnostics.Monitoring.RestServer +namespace Microsoft.Diagnostics.Monitoring.WebApi { internal static class ActionContextExtensions { diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/ArtifactMetadataNames.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/ArtifactMetadataNames.cs similarity index 95% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/ArtifactMetadataNames.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/ArtifactMetadataNames.cs index 5aebdc9b107..bd06fc53489 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/ArtifactMetadataNames.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/ArtifactMetadataNames.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -namespace Microsoft.Diagnostics.Monitoring.RestServer +namespace Microsoft.Diagnostics.Monitoring.WebApi { /// /// Metadata keys that represent artfiact information. diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/Auth/AuthConstants.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Auth/AuthConstants.cs similarity index 91% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/Auth/AuthConstants.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/Auth/AuthConstants.cs index 0d2ec739eb1..fde16fec49b 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/Auth/AuthConstants.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Auth/AuthConstants.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -namespace Microsoft.Diagnostics.Monitoring.RestServer +namespace Microsoft.Diagnostics.Monitoring.WebApi { internal static class AuthConstants { diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/ConfigurationHelper.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/ConfigurationHelper.cs similarity index 93% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/ConfigurationHelper.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/ConfigurationHelper.cs index 3c66b1b3e52..31346c0e2be 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/ConfigurationHelper.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/ConfigurationHelper.cs @@ -4,7 +4,7 @@ using System; -namespace Microsoft.Diagnostics.Monitoring.RestServer +namespace Microsoft.Diagnostics.Monitoring.WebApi { internal static class ConfigurationHelper { diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/ContentTypes.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/ContentTypes.cs similarity index 92% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/ContentTypes.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/ContentTypes.cs index e67496772cd..00fdcad7d60 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/ContentTypes.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/ContentTypes.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -namespace Microsoft.Diagnostics.Monitoring.RestServer +namespace Microsoft.Diagnostics.Monitoring.WebApi { internal static class ContentTypes { diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/Controllers/DiagController.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.cs similarity index 99% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/Controllers/DiagController.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.cs index 6b37f552c04..4683fcf78ca 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/Controllers/DiagController.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.cs @@ -7,7 +7,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Diagnostics.Monitoring.EventPipe; -using Microsoft.Diagnostics.Monitoring.RestServer.Validation; +using Microsoft.Diagnostics.Monitoring.WebApi.Validation; using Microsoft.Diagnostics.NETCore.Client; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -22,7 +22,7 @@ using System.Threading; using System.Threading.Tasks; -namespace Microsoft.Diagnostics.Monitoring.RestServer.Controllers +namespace Microsoft.Diagnostics.Monitoring.WebApi.Controllers { [Route("")] // Root [ApiController] diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/Controllers/DiagControllerExtensions.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagControllerExtensions.cs similarity index 98% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/Controllers/DiagControllerExtensions.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagControllerExtensions.cs index 3dc273c21fe..af240697c6e 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/Controllers/DiagControllerExtensions.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagControllerExtensions.cs @@ -13,7 +13,7 @@ // For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860 -namespace Microsoft.Diagnostics.Monitoring.RestServer.Controllers +namespace Microsoft.Diagnostics.Monitoring.WebApi.Controllers { internal static class DiagControllerExtensions { diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/Controllers/MetricsController.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/MetricsController.cs similarity index 97% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/Controllers/MetricsController.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/MetricsController.cs index 22abf5df6d3..558c015fb60 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/Controllers/MetricsController.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/MetricsController.cs @@ -9,7 +9,7 @@ using Microsoft.Extensions.Options; using System; -namespace Microsoft.Diagnostics.Monitoring.RestServer.Controllers +namespace Microsoft.Diagnostics.Monitoring.WebApi.Controllers { [Route("")] [ApiController] diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/CorsConfiguration.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/CorsConfiguration.cs similarity index 92% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/CorsConfiguration.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/CorsConfiguration.cs index 4be2bf5ffbb..75c7df2371f 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/CorsConfiguration.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/CorsConfiguration.cs @@ -8,7 +8,7 @@ #if UNITTEST namespace Microsoft.Diagnostics.Monitoring.UnitTests.Options #else -namespace Microsoft.Diagnostics.Monitoring.RestServer +namespace Microsoft.Diagnostics.Monitoring.WebApi #endif { public class CorsConfiguration diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/DiagProcessFilter.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/DiagProcessFilter.cs similarity index 99% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/DiagProcessFilter.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/DiagProcessFilter.cs index a6ffd980730..70f3be886dd 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/DiagProcessFilter.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/DiagProcessFilter.cs @@ -9,7 +9,7 @@ using System.Linq; using System.Threading.Tasks; -namespace Microsoft.Diagnostics.Monitoring.RestServer +namespace Microsoft.Diagnostics.Monitoring.WebApi { /// /// There are effectively 3 sets of models for this: diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/DiagnosticServices.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/DiagnosticServices.cs similarity index 99% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/DiagnosticServices.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/DiagnosticServices.cs index 9f368432739..c21c023e84b 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/DiagnosticServices.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/DiagnosticServices.cs @@ -14,7 +14,7 @@ using Microsoft.Diagnostics.NETCore.Client; using Microsoft.Extensions.Options; -namespace Microsoft.Diagnostics.Monitoring.RestServer +namespace Microsoft.Diagnostics.Monitoring.WebApi { internal sealed class DiagnosticServices : IDiagnosticServices { diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/EgressResult.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/EgressResult.cs similarity index 89% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/EgressResult.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/EgressResult.cs index 446702dc7aa..71a9fcd2c8f 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/EgressResult.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/EgressResult.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -namespace Microsoft.Diagnostics.Monitoring.RestServer +namespace Microsoft.Diagnostics.Monitoring.WebApi { internal struct EgressResult { diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/EgressStreamResult.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/EgressStreamResult.cs similarity index 98% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/EgressStreamResult.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/EgressStreamResult.cs index e3d143b2f7c..0af1c3ec1be 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/EgressStreamResult.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/EgressStreamResult.cs @@ -11,7 +11,7 @@ using System.Threading; using System.Threading.Tasks; -namespace Microsoft.Diagnostics.Monitoring.RestServer +namespace Microsoft.Diagnostics.Monitoring.WebApi { internal class EgressStreamResult : ActionResult { diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/ExceptionExtensions.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/ExceptionExtensions.cs similarity index 91% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/ExceptionExtensions.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/ExceptionExtensions.cs index 30cf8a1babf..5e0d4039676 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/ExceptionExtensions.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/ExceptionExtensions.cs @@ -5,7 +5,7 @@ using Microsoft.AspNetCore.Mvc; using System; -namespace Microsoft.Diagnostics.Monitoring.RestServer +namespace Microsoft.Diagnostics.Monitoring.WebApi { internal static class ExceptionExtensions { diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/HostRestrictionAttribute.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/HostRestrictionAttribute.cs similarity index 96% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/HostRestrictionAttribute.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/HostRestrictionAttribute.cs index d85fab12e78..3effee6ca02 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/HostRestrictionAttribute.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/HostRestrictionAttribute.cs @@ -7,7 +7,7 @@ using System; using System.Linq; -namespace Microsoft.Diagnostics.Monitoring.RestServer +namespace Microsoft.Diagnostics.Monitoring.WebApi { /// /// We want to restrict the Prometheus scraping endpoint to only the /metrics call. diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/IDiagnosticServices.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/IDiagnosticServices.cs similarity index 97% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/IDiagnosticServices.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/IDiagnosticServices.cs index 62fd1aa6ec8..ccde596bd00 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/IDiagnosticServices.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/IDiagnosticServices.cs @@ -8,7 +8,7 @@ using System.Threading; using System.Threading.Tasks; -namespace Microsoft.Diagnostics.Monitoring.RestServer +namespace Microsoft.Diagnostics.Monitoring.WebApi { /// /// Set of services provided by the monitoring tool. These are consumed by diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/IEgressService.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/IEgressService.cs similarity index 94% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/IEgressService.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/IEgressService.cs index adb60feb4c6..8bb1a19531b 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/IEgressService.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/IEgressService.cs @@ -7,7 +7,7 @@ using System.Threading; using System.Threading.Tasks; -namespace Microsoft.Diagnostics.Monitoring.RestServer +namespace Microsoft.Diagnostics.Monitoring.WebApi { internal interface IEgressService { diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/IMetricsPortsProvider.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/IMetricsPortsProvider.cs similarity index 91% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/IMetricsPortsProvider.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/IMetricsPortsProvider.cs index d57e2cdcc8c..c17c6f27ac5 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/IMetricsPortsProvider.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/IMetricsPortsProvider.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; -namespace Microsoft.Diagnostics.Monitoring.RestServer +namespace Microsoft.Diagnostics.Monitoring.WebApi { /// /// Provides port information about the metrics URLs that were successfully bound. diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/IMetricsStore.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/IMetricsStore.cs similarity index 100% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/IMetricsStore.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/IMetricsStore.cs diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/KeyValueLogScope.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/KeyValueLogScope.cs similarity index 97% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/KeyValueLogScope.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/KeyValueLogScope.cs index 9e689637db0..1191d0f90cd 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/KeyValueLogScope.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/KeyValueLogScope.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; using System.Text; -namespace Microsoft.Diagnostics.Monitoring.RestServer +namespace Microsoft.Diagnostics.Monitoring.WebApi { // Logger implementations have different ways of serializing log scopes. This class helps those loggers // serialize the scope information in the best way possible for each of the implementations. diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/KeyValueLogScopeExtensions.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/KeyValueLogScopeExtensions.cs similarity index 94% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/KeyValueLogScopeExtensions.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/KeyValueLogScopeExtensions.cs index 3a25e2c0884..e6de9eb7c51 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/KeyValueLogScopeExtensions.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/KeyValueLogScopeExtensions.cs @@ -4,7 +4,7 @@ using System.Globalization; -namespace Microsoft.Diagnostics.Monitoring.RestServer +namespace Microsoft.Diagnostics.Monitoring.WebApi { internal static class KeyValueLogScopeExtensions { diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/LogFormat.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/LogFormat.cs similarity index 88% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/LogFormat.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/LogFormat.cs index b111f6d6123..285ed532e38 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/LogFormat.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/LogFormat.cs @@ -7,7 +7,7 @@ using System.Linq; using System.Threading.Tasks; -namespace Microsoft.Diagnostics.Monitoring.RestServer +namespace Microsoft.Diagnostics.Monitoring.WebApi { public enum LogFormat { diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/LoggingExtensions.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/LoggingExtensions.cs similarity index 98% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/LoggingExtensions.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/LoggingExtensions.cs index 87b29954e10..1d3c5fcda8c 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/LoggingExtensions.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/LoggingExtensions.cs @@ -5,7 +5,7 @@ using Microsoft.Extensions.Logging; using System; -namespace Microsoft.Diagnostics.Monitoring.RestServer +namespace Microsoft.Diagnostics.Monitoring.WebApi { internal static class LoggingExtensions { diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/MetricsLogger.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/MetricsLogger.cs similarity index 100% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/MetricsLogger.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/MetricsLogger.cs diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/MetricsOptions.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/MetricsOptions.cs similarity index 97% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/MetricsOptions.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/MetricsOptions.cs index 56ceeb476a6..13305d815b9 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/MetricsOptions.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/MetricsOptions.cs @@ -9,7 +9,7 @@ #if UNITTEST namespace Microsoft.Diagnostics.Monitoring.UnitTests.Options #else -namespace Microsoft.Diagnostics.Monitoring.RestServer +namespace Microsoft.Diagnostics.Monitoring.WebApi #endif { /// diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/MetricsOptionsDefaults.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/MetricsOptionsDefaults.cs similarity index 91% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/MetricsOptionsDefaults.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/MetricsOptionsDefaults.cs index 6a1ea768f41..04fd9d5da13 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/MetricsOptionsDefaults.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/MetricsOptionsDefaults.cs @@ -5,7 +5,7 @@ #if UNITTEST namespace Microsoft.Diagnostics.Monitoring.UnitTests.Options #else -namespace Microsoft.Diagnostics.Monitoring.RestServer +namespace Microsoft.Diagnostics.Monitoring.WebApi #endif { internal class MetricsOptionsDefaults diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/MetricsService.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/MetricsService.cs similarity index 98% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/MetricsService.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/MetricsService.cs index 6e15e1c48a6..43b2f3842e5 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/MetricsService.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/MetricsService.cs @@ -12,7 +12,7 @@ using System.Threading; using System.Threading.Tasks; -namespace Microsoft.Diagnostics.Monitoring.RestServer +namespace Microsoft.Diagnostics.Monitoring.WebApi { /// /// Periodically gets metrics from the app, and persists these to a metrics store. diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/MetricsStore.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/MetricsStore.cs similarity index 100% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/MetricsStore.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/MetricsStore.cs diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/MetricsStoreService.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/MetricsStoreService.cs similarity index 92% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/MetricsStoreService.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/MetricsStoreService.cs index cf9b0897e3f..41fbdda91c2 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/MetricsStoreService.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/MetricsStoreService.cs @@ -5,7 +5,7 @@ using Microsoft.Extensions.Options; using System; -namespace Microsoft.Diagnostics.Monitoring.RestServer +namespace Microsoft.Diagnostics.Monitoring.WebApi { internal sealed class MetricsStoreService : IDisposable { diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/Microsoft.Diagnostics.Monitoring.RestServer.csproj b/src/Microsoft.Diagnostics.Monitoring.WebApi/Microsoft.Diagnostics.Monitoring.WebApi.csproj similarity index 95% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/Microsoft.Diagnostics.Monitoring.RestServer.csproj rename to src/Microsoft.Diagnostics.Monitoring.WebApi/Microsoft.Diagnostics.Monitoring.WebApi.csproj index ba89288847f..d6f89afb2b1 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/Microsoft.Diagnostics.Monitoring.RestServer.csproj +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Microsoft.Diagnostics.Monitoring.WebApi.csproj @@ -25,7 +25,7 @@ diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/Models/DumpType.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/DumpType.cs similarity index 86% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/Models/DumpType.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/Models/DumpType.cs index eaa644318ee..f3757ed8e6f 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/Models/DumpType.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/DumpType.cs @@ -5,7 +5,7 @@ #if UNITTEST namespace Microsoft.Diagnostics.Monitoring.UnitTests.Models #else -namespace Microsoft.Diagnostics.Monitoring.RestServer.Models +namespace Microsoft.Diagnostics.Monitoring.WebApi.Models #endif { public enum DumpType diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/Models/EventPipeConfiguration.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/EventPipeConfiguration.cs similarity index 92% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/Models/EventPipeConfiguration.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/Models/EventPipeConfiguration.cs index 014f6511d45..ad88ebbff50 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/Models/EventPipeConfiguration.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/EventPipeConfiguration.cs @@ -5,7 +5,7 @@ using System.ComponentModel.DataAnnotations; using System.Text.Json.Serialization; -namespace Microsoft.Diagnostics.Monitoring.RestServer.Models +namespace Microsoft.Diagnostics.Monitoring.WebApi.Models { public class EventPipeConfiguration { diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/Models/EventPipeProvider.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/EventPipeProvider.cs similarity index 88% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/Models/EventPipeProvider.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/Models/EventPipeProvider.cs index 2d42f282c91..69048db41d8 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/Models/EventPipeProvider.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/EventPipeProvider.cs @@ -2,13 +2,13 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Microsoft.Diagnostics.Monitoring.RestServer.Validation; +using Microsoft.Diagnostics.Monitoring.WebApi.Validation; using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using System.Diagnostics.Tracing; using System.Text.Json.Serialization; -namespace Microsoft.Diagnostics.Monitoring.RestServer.Models +namespace Microsoft.Diagnostics.Monitoring.WebApi.Models { public class EventPipeProvider { diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/Models/LogsConfiguration.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/LogsConfiguration.cs similarity index 95% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/Models/LogsConfiguration.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/Models/LogsConfiguration.cs index 83d101fc481..86cde45627f 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/Models/LogsConfiguration.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/LogsConfiguration.cs @@ -10,7 +10,7 @@ #if UNITTEST namespace Microsoft.Diagnostics.Monitoring.UnitTests.Models #else -namespace Microsoft.Diagnostics.Monitoring.RestServer.Models +namespace Microsoft.Diagnostics.Monitoring.WebApi.Models #endif { public class LogsConfiguration diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/Models/ProcessIdentifier.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/ProcessIdentifier.cs similarity index 91% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/Models/ProcessIdentifier.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/Models/ProcessIdentifier.cs index 5313ff99720..5799c263551 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/Models/ProcessIdentifier.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/ProcessIdentifier.cs @@ -8,7 +8,7 @@ #if UNITTEST namespace Microsoft.Diagnostics.Monitoring.UnitTests.Models #else -namespace Microsoft.Diagnostics.Monitoring.RestServer.Models +namespace Microsoft.Diagnostics.Monitoring.WebApi.Models #endif { public class ProcessIdentifier diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/Models/ProcessInfo.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/ProcessInfo.cs similarity index 93% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/Models/ProcessInfo.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/Models/ProcessInfo.cs index 4b116ef0060..e535a76c7c1 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/Models/ProcessInfo.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/ProcessInfo.cs @@ -8,7 +8,7 @@ #if UNITTEST namespace Microsoft.Diagnostics.Monitoring.UnitTests.Models #else -namespace Microsoft.Diagnostics.Monitoring.RestServer.Models +namespace Microsoft.Diagnostics.Monitoring.WebApi.Models #endif { public class ProcessInfo diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/Models/TraceProfile.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/TraceProfile.cs similarity index 85% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/Models/TraceProfile.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/Models/TraceProfile.cs index 980d0267c72..a3964da0584 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/Models/TraceProfile.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/TraceProfile.cs @@ -4,7 +4,7 @@ using System; -namespace Microsoft.Diagnostics.Monitoring.RestServer.Models +namespace Microsoft.Diagnostics.Monitoring.WebApi.Models { [Flags] public enum TraceProfile diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/OutputStreamResult.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/OutputStreamResult.cs similarity index 97% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/OutputStreamResult.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/OutputStreamResult.cs index 7765bd52c53..427f8280f37 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/OutputStreamResult.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/OutputStreamResult.cs @@ -12,7 +12,7 @@ using System.Threading; using System.Threading.Tasks; -namespace Microsoft.Diagnostics.Monitoring.RestServer +namespace Microsoft.Diagnostics.Monitoring.WebApi { internal sealed class OutputStreamResult : ActionResult { diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/ProcessFilterOptions.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/ProcessFilterOptions.cs similarity index 97% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/ProcessFilterOptions.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/ProcessFilterOptions.cs index f603426b9b8..248e15f4d7e 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/ProcessFilterOptions.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/ProcessFilterOptions.cs @@ -13,7 +13,7 @@ #if UNITTEST namespace Microsoft.Diagnostics.Monitoring.UnitTests.Options #else -namespace Microsoft.Diagnostics.Monitoring.RestServer +namespace Microsoft.Diagnostics.Monitoring.WebApi #endif { [JsonConverter(typeof(JsonStringEnumConverter))] diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/ProcessKey.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/ProcessKey.cs similarity index 100% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/ProcessKey.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/ProcessKey.cs diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/ProducesWithProblemDetailsAttribute.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/ProducesWithProblemDetailsAttribute.cs similarity index 93% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/ProducesWithProblemDetailsAttribute.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/ProducesWithProblemDetailsAttribute.cs index 7b74a03884d..a7ab0b0c870 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/ProducesWithProblemDetailsAttribute.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/ProducesWithProblemDetailsAttribute.cs @@ -6,7 +6,7 @@ using Microsoft.AspNetCore.Mvc.Filters; using System; -namespace Microsoft.Diagnostics.Monitoring.RestServer +namespace Microsoft.Diagnostics.Monitoring.WebApi { /// /// Overrides the behavior of the Produces attribute, which clears all content types from the result and @@ -35,7 +35,7 @@ public override void OnResultExecuting(ResultExecutingContext context) { if (context.Result is BadRequestObjectResult badRequestResult && badRequestResult.Value is ProblemDetails) { - badRequestResult.ContentTypes.Add(RestServer.ContentTypes.ApplicationProblemJson); + badRequestResult.ContentTypes.Add(WebApi.ContentTypes.ApplicationProblemJson); } else { diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/RequestThrottling/RequestLimitAttribute.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/RequestThrottling/RequestLimitAttribute.cs similarity index 90% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/RequestThrottling/RequestLimitAttribute.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/RequestThrottling/RequestLimitAttribute.cs index 0cf4e578c21..2eb7c281856 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/RequestThrottling/RequestLimitAttribute.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/RequestThrottling/RequestLimitAttribute.cs @@ -7,7 +7,7 @@ using System.Linq; using System.Threading.Tasks; -namespace Microsoft.Diagnostics.Monitoring.RestServer +namespace Microsoft.Diagnostics.Monitoring.WebApi { [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] internal sealed class RequestLimitAttribute : Attribute diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/ScopeState.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/ScopeState.cs similarity index 100% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/ScopeState.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/ScopeState.cs diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/StorageOptions.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/StorageOptions.cs similarity index 92% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/StorageOptions.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/StorageOptions.cs index 05f61eb4e6f..574cb5b7fc1 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/StorageOptions.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/StorageOptions.cs @@ -11,7 +11,7 @@ #if UNITTEST namespace Microsoft.Diagnostics.Monitoring.UnitTests.Options #else -namespace Microsoft.Diagnostics.Monitoring.RestServer +namespace Microsoft.Diagnostics.Monitoring.WebApi #endif { internal class StorageOptions diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/StorageOptionsDefaults.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/StorageOptionsDefaults.cs similarity index 89% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/StorageOptionsDefaults.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/StorageOptionsDefaults.cs index 7081049ac19..12464611e77 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/StorageOptionsDefaults.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/StorageOptionsDefaults.cs @@ -8,7 +8,7 @@ using System.Linq; using System.Threading.Tasks; -namespace Microsoft.Diagnostics.Monitoring.RestServer +namespace Microsoft.Diagnostics.Monitoring.WebApi { internal sealed class StorageOptionsDefaults { diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/StreamingLogger.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/StreamingLogger.cs similarity index 99% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/StreamingLogger.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/StreamingLogger.cs index 7b4ad80da7c..935812f17d7 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/StreamingLogger.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/StreamingLogger.cs @@ -10,7 +10,7 @@ using System.Text; using System.Text.Json; -namespace Microsoft.Diagnostics.Monitoring.RestServer +namespace Microsoft.Diagnostics.Monitoring.WebApi { /// /// This class is used to write structured event data in json format to an output stream. diff --git a/src/Microsoft.Diagnostics.Monitoring.RestServer/Validation/IntegerOrHexStringAttribute.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Validation/IntegerOrHexStringAttribute.cs similarity index 97% rename from src/Microsoft.Diagnostics.Monitoring.RestServer/Validation/IntegerOrHexStringAttribute.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/Validation/IntegerOrHexStringAttribute.cs index 1f563274400..891f409504a 100644 --- a/src/Microsoft.Diagnostics.Monitoring.RestServer/Validation/IntegerOrHexStringAttribute.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Validation/IntegerOrHexStringAttribute.cs @@ -6,7 +6,7 @@ using System.ComponentModel.DataAnnotations; using System.Globalization; -namespace Microsoft.Diagnostics.Monitoring.RestServer.Validation +namespace Microsoft.Diagnostics.Monitoring.WebApi.Validation { public class IntegerOrHexStringAttribute : ValidationAttribute { diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.OpenApiGen/BadRequestResponseDocumentFilter.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.OpenApiGen/BadRequestResponseDocumentFilter.cs index fa217bad302..cf3059d15e1 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.OpenApiGen/BadRequestResponseDocumentFilter.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.OpenApiGen/BadRequestResponseDocumentFilter.cs @@ -3,7 +3,7 @@ // See the LICENSE file in the project root for more information. using Microsoft.AspNetCore.Mvc; -using Microsoft.Diagnostics.Monitoring.RestServer; +using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.OpenApiGen/Program.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.OpenApiGen/Program.cs index bf21bc55d80..cfe55cf1ca1 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.OpenApiGen/Program.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.OpenApiGen/Program.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Microsoft.Diagnostics.Monitoring.RestServer.Controllers; +using Microsoft.Diagnostics.Monitoring.WebApi.Controllers; using Microsoft.Diagnostics.Tools.Monitor; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.OpenApiGen/RemoveFailureContentTypesOperationFilter.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.OpenApiGen/RemoveFailureContentTypesOperationFilter.cs index 62003c81f73..c137de5b7cd 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.OpenApiGen/RemoveFailureContentTypesOperationFilter.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.OpenApiGen/RemoveFailureContentTypesOperationFilter.cs @@ -1,4 +1,4 @@ -using Microsoft.Diagnostics.Monitoring.RestServer; +using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; using System; diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj index fe3afd6e559..98981fa8535 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj @@ -10,15 +10,15 @@ - - - - - - - - - + + + + + + + + + diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/DefaultProcessConfigurationTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/DefaultProcessConfigurationTests.cs index 357e82efbae..00892c82351 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/DefaultProcessConfigurationTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/DefaultProcessConfigurationTests.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Microsoft.Diagnostics.Monitoring.RestServer; +using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Diagnostics.Monitoring.TestCommon; using Microsoft.Extensions.DependencyInjection; using System; diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Microsoft.Diagnostics.Monitoring.UnitTests.csproj b/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Microsoft.Diagnostics.Monitoring.UnitTests.csproj index 64a990c716f..4f865643f4b 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Microsoft.Diagnostics.Monitoring.UnitTests.csproj +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Microsoft.Diagnostics.Monitoring.UnitTests.csproj @@ -6,7 +6,7 @@ - + diff --git a/src/Tools/dotnet-monitor/Auth/ApiKeyAuthenticationHandler.cs b/src/Tools/dotnet-monitor/Auth/ApiKeyAuthenticationHandler.cs index d9de0db2aa9..3aaf313f600 100644 --- a/src/Tools/dotnet-monitor/Auth/ApiKeyAuthenticationHandler.cs +++ b/src/Tools/dotnet-monitor/Auth/ApiKeyAuthenticationHandler.cs @@ -3,7 +3,7 @@ // See the LICENSE file in the project root for more information. using Microsoft.AspNetCore.Authentication; -using Microsoft.Diagnostics.Monitoring.RestServer; +using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.Extensions.Primitives; diff --git a/src/Tools/dotnet-monitor/Auth/UserAuthorizationHandler.cs b/src/Tools/dotnet-monitor/Auth/UserAuthorizationHandler.cs index 31ea2b315c7..2d7184752d7 100644 --- a/src/Tools/dotnet-monitor/Auth/UserAuthorizationHandler.cs +++ b/src/Tools/dotnet-monitor/Auth/UserAuthorizationHandler.cs @@ -4,7 +4,7 @@ using Microsoft.AspNetCore.Authentication.Negotiate; using Microsoft.AspNetCore.Authorization; -using Microsoft.Diagnostics.Monitoring.RestServer; +using Microsoft.Diagnostics.Monitoring.WebApi; using System; using System.Collections.Generic; using System.Linq; diff --git a/src/Tools/dotnet-monitor/DiagnosticsMonitorCommandHandler.cs b/src/Tools/dotnet-monitor/DiagnosticsMonitorCommandHandler.cs index 8070ca80348..24c6713eda1 100644 --- a/src/Tools/dotnet-monitor/DiagnosticsMonitorCommandHandler.cs +++ b/src/Tools/dotnet-monitor/DiagnosticsMonitorCommandHandler.cs @@ -7,7 +7,7 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.Diagnostics.Monitoring; -using Microsoft.Diagnostics.Monitoring.RestServer; +using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; diff --git a/src/Tools/dotnet-monitor/Egress/AzureBlobEgressFactory.cs b/src/Tools/dotnet-monitor/Egress/AzureBlobEgressFactory.cs index 4bbb8a9274b..9aa6de25d75 100644 --- a/src/Tools/dotnet-monitor/Egress/AzureBlobEgressFactory.cs +++ b/src/Tools/dotnet-monitor/Egress/AzureBlobEgressFactory.cs @@ -3,7 +3,7 @@ // See the LICENSE file in the project root for more information. using Microsoft.Diagnostics.Monitoring; -using Microsoft.Diagnostics.Monitoring.RestServer; +using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Diagnostics.Tools.Monitor.Egress.AzureStorage; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; diff --git a/src/Tools/dotnet-monitor/Egress/Configuration/EgressConfigureOptions.cs b/src/Tools/dotnet-monitor/Egress/Configuration/EgressConfigureOptions.cs index f1a617c152b..44e2ab7e9f6 100644 --- a/src/Tools/dotnet-monitor/Egress/Configuration/EgressConfigureOptions.cs +++ b/src/Tools/dotnet-monitor/Egress/Configuration/EgressConfigureOptions.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Microsoft.Diagnostics.Monitoring.RestServer; +using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; diff --git a/src/Tools/dotnet-monitor/Egress/ConfiguredEgressProvider.cs b/src/Tools/dotnet-monitor/Egress/ConfiguredEgressProvider.cs index 65f787f8431..dc4c363918f 100644 --- a/src/Tools/dotnet-monitor/Egress/ConfiguredEgressProvider.cs +++ b/src/Tools/dotnet-monitor/Egress/ConfiguredEgressProvider.cs @@ -3,7 +3,7 @@ // See the LICENSE file in the project root for more information. using Microsoft.Diagnostics.Monitoring; -using Microsoft.Diagnostics.Monitoring.RestServer; +using Microsoft.Diagnostics.Monitoring.WebApi; using System; using System.IO; using System.Threading; diff --git a/src/Tools/dotnet-monitor/Egress/EgressService.cs b/src/Tools/dotnet-monitor/Egress/EgressService.cs index 61145203b90..62180075bc0 100644 --- a/src/Tools/dotnet-monitor/Egress/EgressService.cs +++ b/src/Tools/dotnet-monitor/Egress/EgressService.cs @@ -3,7 +3,7 @@ // See the LICENSE file in the project root for more information. using Microsoft.Diagnostics.Monitoring; -using Microsoft.Diagnostics.Monitoring.RestServer; +using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Diagnostics.Tools.Monitor.Egress.Configuration; using Microsoft.Extensions.Options; using System; diff --git a/src/Tools/dotnet-monitor/Egress/FileSystemEgressFactory.cs b/src/Tools/dotnet-monitor/Egress/FileSystemEgressFactory.cs index ff455813251..08742f08d50 100644 --- a/src/Tools/dotnet-monitor/Egress/FileSystemEgressFactory.cs +++ b/src/Tools/dotnet-monitor/Egress/FileSystemEgressFactory.cs @@ -3,7 +3,7 @@ // See the LICENSE file in the project root for more information. using Microsoft.Diagnostics.Monitoring; -using Microsoft.Diagnostics.Monitoring.RestServer; +using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Diagnostics.Tools.Monitor.Egress.FileSystem; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; diff --git a/src/Tools/dotnet-monitor/GenerateApiKeyCommandHandler.cs b/src/Tools/dotnet-monitor/GenerateApiKeyCommandHandler.cs index 45f6d7a3f4b..71da0bcb2fb 100644 --- a/src/Tools/dotnet-monitor/GenerateApiKeyCommandHandler.cs +++ b/src/Tools/dotnet-monitor/GenerateApiKeyCommandHandler.cs @@ -21,7 +21,7 @@ public Task GenerateApiKey(CancellationToken token, IConsole console) { GeneratedApiKey newKey = GeneratedApiKey.Create(); - console.Out.WriteLine(FormattableString.Invariant($"Authorization: {Monitoring.RestServer.AuthConstants.ApiKeySchema} {newKey.MonitorApiKey}")); + console.Out.WriteLine(FormattableString.Invariant($"Authorization: {Monitoring.WebApi.AuthConstants.ApiKeySchema} {newKey.MonitorApiKey}")); console.Out.WriteLine(FormattableString.Invariant($"ApiKeyHash: {newKey.HashValue}")); console.Out.WriteLine(FormattableString.Invariant($"ApiKeyHashType: {newKey.HashAlgorithm}")); diff --git a/src/Tools/dotnet-monitor/LoggingExtensions.cs b/src/Tools/dotnet-monitor/LoggingExtensions.cs index dd289ea1ea6..7f95bbff921 100644 --- a/src/Tools/dotnet-monitor/LoggingExtensions.cs +++ b/src/Tools/dotnet-monitor/LoggingExtensions.cs @@ -282,7 +282,7 @@ public static void ApiKeyAuthenticationOptionsChanged(this ILogger logger) public static void LogTempKey(this ILogger logger, string monitorApiKey) { - _logTempKey(logger, Environment.NewLine, HeaderNames.Authorization, Monitoring.RestServer.AuthConstants.ApiKeySchema, monitorApiKey, null); + _logTempKey(logger, Environment.NewLine, HeaderNames.Authorization, Monitoring.WebApi.AuthConstants.ApiKeySchema, monitorApiKey, null); } private static string Redact(string value) diff --git a/src/Tools/dotnet-monitor/MetricsPortsProvider.cs b/src/Tools/dotnet-monitor/MetricsPortsProvider.cs index db350e66c04..4214e3d0ebb 100644 --- a/src/Tools/dotnet-monitor/MetricsPortsProvider.cs +++ b/src/Tools/dotnet-monitor/MetricsPortsProvider.cs @@ -5,7 +5,7 @@ using Microsoft.AspNetCore.Hosting.Server; using Microsoft.AspNetCore.Hosting.Server.Features; using Microsoft.AspNetCore.Http; -using Microsoft.Diagnostics.Monitoring.RestServer; +using Microsoft.Diagnostics.Monitoring.WebApi; using System; using System.Collections.Generic; using System.Diagnostics; diff --git a/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs b/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs index 2f10f773f62..cde226dbcee 100644 --- a/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs +++ b/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Microsoft.Diagnostics.Monitoring.RestServer; +using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Diagnostics.Tools.Monitor.Egress; using Microsoft.Diagnostics.Tools.Monitor.Egress.Configuration; using Microsoft.Extensions.Configuration; diff --git a/src/Tools/dotnet-monitor/Startup.cs b/src/Tools/dotnet-monitor/Startup.cs index 5e19386d54e..19378655b9c 100644 --- a/src/Tools/dotnet-monitor/Startup.cs +++ b/src/Tools/dotnet-monitor/Startup.cs @@ -11,8 +11,8 @@ using Microsoft.AspNetCore.ResponseCompression; using Microsoft.AspNetCore.Server.Kestrel.Core; using Microsoft.Diagnostics.Monitoring; -using Microsoft.Diagnostics.Monitoring.RestServer; -using Microsoft.Diagnostics.Monitoring.RestServer.Controllers; +using Microsoft.Diagnostics.Monitoring.WebApi; +using Microsoft.Diagnostics.Monitoring.WebApi.Controllers; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; diff --git a/src/Tools/dotnet-monitor/Throttling.cs b/src/Tools/dotnet-monitor/Throttling.cs index 5059fe1b6b1..08c7cc4ff68 100644 --- a/src/Tools/dotnet-monitor/Throttling.cs +++ b/src/Tools/dotnet-monitor/Throttling.cs @@ -3,7 +3,7 @@ // See the LICENSE file in the project root for more information. using Microsoft.AspNetCore.Http; -using Microsoft.Diagnostics.Monitoring.RestServer; +using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Extensions.Logging; using System; using System.Collections.Concurrent; diff --git a/src/Tools/dotnet-monitor/dotnet-monitor.csproj b/src/Tools/dotnet-monitor/dotnet-monitor.csproj index 0f3dded4cbb..d7555136994 100644 --- a/src/Tools/dotnet-monitor/dotnet-monitor.csproj +++ b/src/Tools/dotnet-monitor/dotnet-monitor.csproj @@ -50,7 +50,7 @@ - + From e49f2d5bff89aaaea5cdfb36545cc6635a6e09d2 Mon Sep 17 00:00:00 2001 From: Patrick Fenelon Date: Tue, 15 Jun 2021 13:34:36 -0700 Subject: [PATCH 067/185] Work to implement configurable MonitorApiKey (#361), issues #359 + #360 * Work to implement configurable MonitorApiKey * Add tests to api auth config --- .../AuthenticationTests.cs | 71 ++++++++++++++++--- .../Options/OptionsExtensions.cs | 5 +- .../Auth/ApiKeyAuthenticationHandler.cs | 38 ++++++++-- ...piKeyAuthenticationPostConfigureOptions.cs | 49 +------------ .../dotnet-monitor/Auth/GeneratedApiKey.cs | 20 +++++- .../Auth/HashAlgorithmChecker.cs | 40 +++++++++++ .../GenerateApiKeyCommandHandler.cs | 16 ++++- src/Tools/dotnet-monitor/Program.cs | 19 ++++- 8 files changed, 187 insertions(+), 71 deletions(-) create mode 100644 src/Tools/dotnet-monitor/Auth/HashAlgorithmChecker.cs diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/AuthenticationTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/AuthenticationTests.cs index 1d8cdf69a78..fb6dfaa5545 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/AuthenticationTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/AuthenticationTests.cs @@ -116,18 +116,18 @@ public async Task DisableAuthenticationTest() [Fact] public async Task ApiKeyAuthenticationSchemeTest() { - const string AlgorithmName = "SHA256"; - + const int keyLength = 32; + const string hashAlgorithm = "SHA256"; await using MonitorRunner toolRunner = new(_outputHelper); _outputHelper.WriteLine("Generating API key."); // Generate initial API key - byte[] apiKey = GenerateApiKey(); + byte[] apiKey = GenerateApiKey(keyLength); // Set API key via key-per-file RootOptions options = new(); - options.UseApiKey(AlgorithmName, apiKey); + options.UseApiKey(hashAlgorithm, apiKey); toolRunner.WriteKeyPerValueConfiguration(options); // Start dotnet-monitor @@ -146,9 +146,9 @@ public async Task ApiKeyAuthenticationSchemeTest() _outputHelper.WriteLine("Rotating API key."); // Rotate the API key - byte[] apiKey2 = GenerateApiKey(); + byte[] apiKey2 = GenerateApiKey(keyLength); - options.UseApiKey(AlgorithmName, apiKey2); + options.UseApiKey(hashAlgorithm, apiKey2); toolRunner.WriteKeyPerValueConfiguration(options); // Wait for the key rotation to be consumed by dotnet-monitor; detect this @@ -185,6 +185,61 @@ public async Task ApiKeyAuthenticationSchemeTest() Assert.NotNull(processes); } + /// + /// Tests that limits on API key length and + /// disallowed algorithms are enforced. + /// + [Theory] + [InlineData(32, "SHA256", HttpStatusCode.OK)] + [InlineData(33, "SHA256", HttpStatusCode.OK)] + [InlineData(34, "SHA256", HttpStatusCode.OK)] + [InlineData(2048, "SHA256", HttpStatusCode.OK)] + [InlineData(32, "SHA512", HttpStatusCode.OK)] + [InlineData(2048, "SHA512", HttpStatusCode.OK)] + [InlineData(0, "SHA256", HttpStatusCode.Unauthorized)] + [InlineData(31, "SHA256", HttpStatusCode.Unauthorized)] + [InlineData(2049, "SHA256", HttpStatusCode.Unauthorized)] + [InlineData(100000, "SHA256", HttpStatusCode.RequestHeaderFieldsTooLarge)] + [InlineData(32, "SHA1", HttpStatusCode.Unauthorized)] + [InlineData(32, "MD5", HttpStatusCode.Unauthorized)] + public async Task ApiKeyLimitsTest(int keyLength, string hashAlgorithm, HttpStatusCode expectedCode) + { + await using MonitorRunner toolRunner = new(_outputHelper); + + _outputHelper.WriteLine("Generating API key."); + + // Generate initial API key + byte[] apiKey = GenerateApiKey(keyLength); + + // Set API key via key-per-file + RootOptions options = new(); + options.UseApiKey(hashAlgorithm, apiKey); + toolRunner.WriteKeyPerValueConfiguration(options); + + // Start dotnet-monitor + await toolRunner.StartAsync(); + + // Create HttpClient with default request headers + using HttpClient httpClient = await toolRunner.CreateHttpClientDefaultAddressAsync(_httpClientFactory); + httpClient.DefaultRequestHeaders.Authorization = + new AuthenticationHeaderValue(ApiKeyScheme, Convert.ToBase64String(apiKey)); + ApiClient apiClient = new(_outputHelper, httpClient); + + if (expectedCode == HttpStatusCode.OK) + { + // We expect the combo to work + var processes = await apiClient.GetProcessesAsync(); + Assert.NotNull(processes); + } + else + { + // We expect the authentication handler to reject our request + var statusCodeException = await Assert.ThrowsAsync( + () => apiClient.GetProcessesAsync()); + Assert.Equal(expectedCode, statusCodeException.StatusCode); + } + } + /// /// Tests that --temp-apikey flag can be used to generate a key. /// @@ -283,9 +338,9 @@ public async Task NegotiateAuthenticationSchemeTest() } } - private static byte[] GenerateApiKey() + private static byte[] GenerateApiKey(int keyLength = 32) { - byte[] apiKey = new byte[32]; // 256 bits + byte[] apiKey = new byte[keyLength]; // 256 bits RandomNumberGenerator.Fill(apiKey); return apiKey; } diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Options/OptionsExtensions.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Options/OptionsExtensions.cs index b7570211754..82dffeda9e3 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Options/OptionsExtensions.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Options/OptionsExtensions.cs @@ -52,8 +52,9 @@ public static RootOptions UseApiKey(this RootOptions options, string algorithmNa } using var hashAlgorithm = HashAlgorithm.Create(algorithmName); - - options.ApiAuthentication.ApiKeyHash = ToHexString(hashAlgorithm.ComputeHash(apiKey)); + + byte[] hash = hashAlgorithm.ComputeHash(apiKey); + options.ApiAuthentication.ApiKeyHash = ToHexString(hash); options.ApiAuthentication.ApiKeyHashType = algorithmName; return options; diff --git a/src/Tools/dotnet-monitor/Auth/ApiKeyAuthenticationHandler.cs b/src/Tools/dotnet-monitor/Auth/ApiKeyAuthenticationHandler.cs index 3aaf313f600..c33094bb8f6 100644 --- a/src/Tools/dotnet-monitor/Auth/ApiKeyAuthenticationHandler.cs +++ b/src/Tools/dotnet-monitor/Auth/ApiKeyAuthenticationHandler.cs @@ -9,6 +9,7 @@ using Microsoft.Extensions.Primitives; using Microsoft.Net.Http.Headers; using System; +using System.Buffers.Text; using System.Diagnostics; using System.Linq; using System.Net.Http.Headers; @@ -24,7 +25,10 @@ namespace Microsoft.Diagnostics.Tools.Monitor /// internal sealed class ApiKeyAuthenticationHandler : AuthenticationHandler { - public const int ApiKeyNumBytes = 32; + public const int ApiKeyByteMinLength = 32; + public const int ApiKeyByteMaxLength = 2048; + // This is the max length to efficiently encode an ApiKey of the length ApiKeyByteMaxLength. + private readonly int ApiKeyBase64MaxLength = Base64.GetMaxEncodedToUtf8Length(ApiKeyByteMaxLength); public ApiKeyAuthenticationHandler( IOptionsMonitor options, @@ -63,11 +67,31 @@ protected override Task HandleAuthenticateAsync() return Task.FromResult(AuthenticateResult.NoResult()); } - //The user is passing a base 64-encoded version of the secret - //We will be hash this and compare it to the secret in our configuration. - byte[] secret = new byte[ApiKeyAuthenticationHandler.ApiKeyNumBytes]; - Span span = new Span(secret); - if (!Convert.TryFromBase64String(authHeader.Parameter, span, out int bytesWritten) || bytesWritten < 32) + if (authHeader.Parameter == null) + { + return Task.FromResult(AuthenticateResult.Fail("Invalid API key format.")); + } + + if (authHeader.Parameter.Length > ApiKeyBase64MaxLength) + { + return Task.FromResult(AuthenticateResult.Fail("Invalid API key format.")); + } + + // Calculate the max length of the base64 encoded value, + // the rules to decode this are really complex and allow white space in the + // string which should be ignored, simply calculate the max it can be. + int byteLen = Base64.GetMaxDecodedFromUtf8Length(authHeader.Parameter.Length); + + if (byteLen < ApiKeyByteMinLength) + { + return Task.FromResult(AuthenticateResult.Fail("Invalid API key format.")); + } + + // The user is passing a base 64-encoded version of the secret + // We will be hash this and compare it to the secret in our configuration. + byte[] buffer = new byte[byteLen]; + Span span = new Span(buffer); + if (!Convert.TryFromBase64String(authHeader.Parameter, span, out int bytesWritten) || bytesWritten < ApiKeyByteMinLength || bytesWritten > ApiKeyByteMaxLength) { return Task.FromResult(AuthenticateResult.Fail("Invalid API key format.")); } @@ -76,7 +100,7 @@ protected override Task HandleAuthenticateAsync() using HashAlgorithm algorithm = HashAlgorithm.Create(options.HashAlgorithm); Debug.Assert(null != algorithm); - byte[] hashedSecret = algorithm.ComputeHash(secret); + byte[] hashedSecret = algorithm.ComputeHash(buffer, 0, bytesWritten); Debug.Assert(null != options.HashValue); if (hashedSecret.SequenceEqual(options.HashValue)) diff --git a/src/Tools/dotnet-monitor/Auth/ApiKeyAuthenticationPostConfigureOptions.cs b/src/Tools/dotnet-monitor/Auth/ApiKeyAuthenticationPostConfigureOptions.cs index 89ec4297b27..2d693635e84 100644 --- a/src/Tools/dotnet-monitor/Auth/ApiKeyAuthenticationPostConfigureOptions.cs +++ b/src/Tools/dotnet-monitor/Auth/ApiKeyAuthenticationPostConfigureOptions.cs @@ -18,53 +18,6 @@ namespace Microsoft.Diagnostics.Tools.Monitor internal sealed class ApiKeyAuthenticationPostConfigureOptions : IPostConfigureOptions { - private static readonly string[] DisallowedHashAlgorithms = new string[] - { - // ------------------ SHA1 ------------------ - "SHA", - "SHA1", - "System.Security.Cryptography.SHA1", - "System.Security.Cryptography.SHA1Cng", - "System.Security.Cryptography.HashAlgorithm", - "http://www.w3.org/2000/09/xmldsig#sha1", - // These give a KeyedHashAlgorith based on SHA1 - "System.Security.Cryptography.HMAC", - "System.Security.Cryptography.KeyedHashAlgorithm", - "HMACSHA1", - "System.Security.Cryptography.HMACSHA1", - "http://www.w3.org/2000/09/xmldsig#hmac-sha1", - - // ------------------ MD5 ------------------ - "MD5", - "System.Security.Cryptography.MD5", - "System.Security.Cryptography.MD5Cng", - "http://www.w3.org/2001/04/xmldsig-more#md5", - // These give a KeyedHashAlgorith based on MD5 - "HMACMD5", - "System.Security.Cryptography.HMACMD5", - "http://www.w3.org/2001/04/xmldsig-more#hmac-md5", - - // These are defined in .net framework but currently not supported - // supported in .net core. Lets add these to the list for future - // proofing, in the event that support is expanded. - // See: https://github.com/dotnet/runtime/blob/01b7e73cd378145264a7cb7a09365b41ed42b240/src/libraries/System.Security.Cryptography.Algorithms/src/System/Security/Cryptography/CryptoConfig.cs#L275 - // ------------------ RIPEMD160 ------------------ - "RIPEMD160", - "RIPEMD-160", - "System.Security.Cryptography.RIPEMD160", - "System.Security.Cryptography.RIPEMD160Managed", - "http://www.w3.org/2001/04/xmlenc#ripemd160", - // These give a KeyedHashAlgorith based on RIPEMD160 - "HMACRIPEMD160", - "System.Security.Cryptography.HMACRIPEMD160", - "http://www.w3.org/2001/04/xmldsig-more#hmac-ripemd160", - - // ------------------ MAC3DES ------------------ - // This is .net specific non-crypto hash algorithm, don't allow it - "MACTripleDES", - "System.Security.Cryptography.MACTripleDES", - }; - private readonly IOptionsMonitor _apiAuthOptions; public ApiKeyAuthenticationPostConfigureOptions( @@ -88,7 +41,7 @@ public void PostConfigure(string name, ApiKeyAuthenticationOptions options) // Validate hash algorithm is allowed and is supported. if (!string.IsNullOrEmpty(sourceOptions.ApiKeyHashType)) { - if (DisallowedHashAlgorithms.Contains(sourceOptions.ApiKeyHashType, StringComparer.OrdinalIgnoreCase)) + if (!HashAlgorithmChecker.IsAllowedAlgorithm(sourceOptions.ApiKeyHashType)) { errors.Add(new ValidationResult($"The {nameof(ApiAuthenticationOptions.ApiKeyHashType)} field value '{sourceOptions.ApiKeyHashType}' is not allowed.", new string[] { nameof(ApiAuthenticationOptions.ApiKeyHashType) })); } diff --git a/src/Tools/dotnet-monitor/Auth/GeneratedApiKey.cs b/src/Tools/dotnet-monitor/Auth/GeneratedApiKey.cs index 6b329a588e8..cc484f21850 100644 --- a/src/Tools/dotnet-monitor/Auth/GeneratedApiKey.cs +++ b/src/Tools/dotnet-monitor/Auth/GeneratedApiKey.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Linq; using System.Security.Cryptography; using System.Text; @@ -10,6 +11,9 @@ namespace Microsoft.Diagnostics.Tools.Monitor { internal sealed class GeneratedApiKey { + public const int DefaultKeyLength = 32; + public const string DefaultHashAlgorithm = "SHA256"; + public readonly string MonitorApiKey; public readonly string HashAlgorithm; public readonly string HashValue; @@ -23,15 +27,25 @@ private GeneratedApiKey(string monitorApiKey, string hashAlgorithm, string hashV public static GeneratedApiKey Create() { - return GeneratedApiKey.Create("SHA256"); + return GeneratedApiKey.Create(DefaultKeyLength, DefaultHashAlgorithm); } - private static GeneratedApiKey Create(string hashAlgorithm) + public static GeneratedApiKey Create(int keyLength, string hashAlgorithm) { + if (!HashAlgorithmChecker.IsAllowedAlgorithm(hashAlgorithm)) + { + throw new ArgumentOutOfRangeException(nameof(hashAlgorithm)); + } + + if (keyLength < ApiKeyAuthenticationHandler.ApiKeyByteMinLength || keyLength > ApiKeyAuthenticationHandler.ApiKeyByteMaxLength) + { + throw new ArgumentOutOfRangeException(nameof(keyLength)); + } + using RandomNumberGenerator rng = RandomNumberGenerator.Create(); using HashAlgorithm hasher = System.Security.Cryptography.HashAlgorithm.Create(hashAlgorithm); - byte[] secret = new byte[ApiKeyAuthenticationHandler.ApiKeyNumBytes]; + byte[] secret = new byte[keyLength]; rng.GetBytes(secret); byte[] hash = hasher.ComputeHash(secret); diff --git a/src/Tools/dotnet-monitor/Auth/HashAlgorithmChecker.cs b/src/Tools/dotnet-monitor/Auth/HashAlgorithmChecker.cs new file mode 100644 index 00000000000..fc4de152b02 --- /dev/null +++ b/src/Tools/dotnet-monitor/Auth/HashAlgorithmChecker.cs @@ -0,0 +1,40 @@ +using System; +using System.Linq; + +namespace Microsoft.Diagnostics.Tools.Monitor +{ + class HashAlgorithmChecker + { + private static readonly string[] DisallowedHashAlgorithms = new string[] + { + // ------------------ SHA1 ------------------ + "SHA", + "SHA1", + "System.Security.Cryptography.SHA1", + "System.Security.Cryptography.SHA1Cng", + "System.Security.Cryptography.HashAlgorithm", + "http://www.w3.org/2000/09/xmldsig#sha1", + // These give a KeyedHashAlgorith based on SHA1 + "System.Security.Cryptography.HMAC", + "System.Security.Cryptography.KeyedHashAlgorithm", + "HMACSHA1", + "System.Security.Cryptography.HMACSHA1", + "http://www.w3.org/2000/09/xmldsig#hmac-sha1", + + // ------------------ MD5 ------------------ + "MD5", + "System.Security.Cryptography.MD5", + "System.Security.Cryptography.MD5Cng", + "http://www.w3.org/2001/04/xmldsig-more#md5", + // These give a KeyedHashAlgorith based on MD5 + "HMACMD5", + "System.Security.Cryptography.HMACMD5", + "http://www.w3.org/2001/04/xmldsig-more#hmac-md5", + }; + + public static bool IsAllowedAlgorithm(string hashAlgorithmName) + { + return !DisallowedHashAlgorithms.Contains(hashAlgorithmName, StringComparer.OrdinalIgnoreCase); + } + } +} diff --git a/src/Tools/dotnet-monitor/GenerateApiKeyCommandHandler.cs b/src/Tools/dotnet-monitor/GenerateApiKeyCommandHandler.cs index 71da0bcb2fb..9a7ee883ddd 100644 --- a/src/Tools/dotnet-monitor/GenerateApiKeyCommandHandler.cs +++ b/src/Tools/dotnet-monitor/GenerateApiKeyCommandHandler.cs @@ -17,9 +17,21 @@ namespace Microsoft.Diagnostics.Tools.Monitor /// internal sealed class GenerateApiKeyCommandHandler { - public Task GenerateApiKey(CancellationToken token, IConsole console) + public Task GenerateApiKey(CancellationToken token, int keyLength, string hashAlgorithm, IConsole console) { - GeneratedApiKey newKey = GeneratedApiKey.Create(); + if (!HashAlgorithmChecker.IsAllowedAlgorithm(hashAlgorithm)) + { + console.Error.WriteLine(FormattableString.CurrentCulture($"The {nameof(hashAlgorithm)} parameter value '{hashAlgorithm}' is not allowed.")); + return Task.FromResult(1); + } + + if (keyLength < ApiKeyAuthenticationHandler.ApiKeyByteMinLength || keyLength > ApiKeyAuthenticationHandler.ApiKeyByteMaxLength) + { + console.Error.WriteLine(FormattableString.CurrentCulture($"The {nameof(keyLength)} parameter value '{keyLength}' is not allowed. Must be between {ApiKeyAuthenticationHandler.ApiKeyByteMinLength} and {ApiKeyAuthenticationHandler.ApiKeyByteMaxLength} bytes.")); + return Task.FromResult(1); + } + + GeneratedApiKey newKey = GeneratedApiKey.Create(keyLength, hashAlgorithm); console.Out.WriteLine(FormattableString.Invariant($"Authorization: {Monitoring.WebApi.AuthConstants.ApiKeySchema} {newKey.MonitorApiKey}")); console.Out.WriteLine(FormattableString.Invariant($"ApiKeyHash: {newKey.HashValue}")); diff --git a/src/Tools/dotnet-monitor/Program.cs b/src/Tools/dotnet-monitor/Program.cs index e7330af312c..1c3f620a3ea 100644 --- a/src/Tools/dotnet-monitor/Program.cs +++ b/src/Tools/dotnet-monitor/Program.cs @@ -23,7 +23,8 @@ private static Command GenerateApiKeyCommand() => name: "generatekey", description: "Generate api key and hash for authentication") { - CommandHandler.Create(new GenerateApiKeyCommandHandler().GenerateApiKey) + CommandHandler.Create(new GenerateApiKeyCommandHandler().GenerateApiKey), + HashAlgorithm(), KeyLength() }; private static Command CollectCommand() => @@ -108,6 +109,22 @@ private static Option TempApiKey() => Argument = new Argument(name: "tempApiKey", getDefaultValue: () => false) }; + private static Option HashAlgorithm() => + new Option( + aliases: new[] { "-h", "--hash-algorithm" }, + description: "The string representing the hash algorithm used to compute ApiKeyHash store in configuration") + { + Argument = new Argument(name: "hashAlgorithm", getDefaultValue: () => GeneratedApiKey.DefaultHashAlgorithm) + }; + + private static Option KeyLength() => + new Option( + aliases: new[] { "-l", "--key-length" }, + description: "The length of the MonitorApiKey in bytes. ") + { + Argument = new Argument(name: "keyLength", getDefaultValue: () => GeneratedApiKey.DefaultKeyLength) + }; + private static Option ConfigLevel() => new Option( alias: "--level", From 8ac2f73908438b0303f0e81ed988ff8d6d450464 Mon Sep 17 00:00:00 2001 From: Sourabh Shirhatti Date: Wed, 16 Jun 2021 09:39:20 -0700 Subject: [PATCH 068/185] Update versions in the docs (#443) --- documentation/setup.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/documentation/setup.md b/documentation/setup.md index d4647a2d8a3..2c7826fceaf 100644 --- a/documentation/setup.md +++ b/documentation/setup.md @@ -12,13 +12,13 @@ The `dotnet monitor` global tool requires a .NET 3.1 or newer SDK installed as a The latest public preview of `dotnet monitor` is available on Nuget. You can download the latest version using the following command: ```cmd -dotnet tool install -g dotnet-monitor --version 5.0.0-preview.4.* +dotnet tool install -g dotnet-monitor --version 5.0.0-preview.5.* ``` If you already have `dotnet monitor` installed and want to update: ```cmd -dotnet tool update -g dotnet-monitor --version 5.0.0-preview.4.* +dotnet tool update -g dotnet-monitor --version 5.0.0-preview.5.* ``` ### Container image @@ -26,7 +26,7 @@ dotnet tool update -g dotnet-monitor --version 5.0.0-preview.4.* The latest public preview of the `dotnet monitor` container image is avaialbe on MCR. You can pull the latest image using the following command: ```cmd -docker pull mcr.microsoft.com/dotnet/monitor:5.0.0-preview.4 +docker pull mcr.microsoft.com/dotnet/monitor:5.0.0-preview.5 ``` ### Working with CI builds @@ -36,17 +36,17 @@ In addition to public previews, we also publish last-known-good (LKG) builds for The LKG build of `dotnet monitor` is available on a private package feed. You can download the latest versionof the .NET global tool using the following command: ```cmd -dotnet tool install -g dotnet-monitor --add-source https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet-tools/nuget/v3/index.json --version 5.0.0-preview.5.* +dotnet tool install -g dotnet-monitor --add-source https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet-tools/nuget/v3/index.json --version 5.0.0-preview.6.* ``` If you already have `dotnet monitor` installed and want to update: ```cmd -dotnet tool update -g dotnet-monitor --add-source https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet-tools/nuget/v3/index.json --version 5.0.0-preview.5.* +dotnet tool update -g dotnet-monitor --add-source https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet-tools/nuget/v3/index.json --version 5.0.0-preview.6.* ``` The LKG build of `dotnet monitor` is also available as a container image. You can pull the image using the following command: ```cmd -docker pull mcr.microsoft.com/dotnet/nightly/monitor:5.0.0-preview.5 +docker pull mcr.microsoft.com/dotnet/nightly/monitor:5.0.0-preview.6 ``` From 0b6d8ed899dd62cd2545dadffb0191556f8fe864 Mon Sep 17 00:00:00 2001 From: kkeirstead <85592574+kkeirstead@users.noreply.github.com> Date: Wed, 16 Jun 2021 10:51:02 -0700 Subject: [PATCH 069/185] Handles incorrectly formatted settings.json files by catching the System.FormatException and outputting a readable error message for the user. (#446) --- .../DiagnosticsMonitorCommandHandler.cs | 60 ++++++++++++------- 1 file changed, 37 insertions(+), 23 deletions(-) diff --git a/src/Tools/dotnet-monitor/DiagnosticsMonitorCommandHandler.cs b/src/Tools/dotnet-monitor/DiagnosticsMonitorCommandHandler.cs index 24c6713eda1..f0ed4ccda0a 100644 --- a/src/Tools/dotnet-monitor/DiagnosticsMonitorCommandHandler.cs +++ b/src/Tools/dotnet-monitor/DiagnosticsMonitorCommandHandler.cs @@ -69,36 +69,50 @@ private const string UserConfigDirectoryOverrideEnvironmentVariable public async Task Start(CancellationToken token, IConsole console, string[] urls, string[] metricUrls, bool metrics, string diagnosticPort, bool noAuth, bool tempApiKey) { //CONSIDER The console logger uses the standard AddConsole, and therefore disregards IConsole. - using IHost host = CreateHostBuilder(console, urls, metricUrls, metrics, diagnosticPort, noAuth, tempApiKey, configOnly: false).Build(); try { - await host.StartAsync(token); + using IHost host = CreateHostBuilder(console, urls, metricUrls, metrics, diagnosticPort, noAuth, tempApiKey, configOnly: false).Build(); + try + { + await host.StartAsync(token); - await host.WaitForShutdownAsync(token); - } - catch (MonitoringException) - { - // It is the responsibility of throwers to ensure that the exceptions are logged. - return -1; - } - catch (OptionsValidationException ex) - { - host.Services.GetRequiredService() - .CreateLogger(typeof(DiagnosticsMonitorCommandHandler)) - .OptionsValidationFailure(ex); - return -1; - } - finally - { - if (host is IAsyncDisposable asyncDisposable) + await host.WaitForShutdownAsync(token); + } + catch (MonitoringException) + { + // It is the responsibility of throwers to ensure that the exceptions are logged. + return -1; + } + catch (OptionsValidationException ex) { - await asyncDisposable.DisposeAsync(); + host.Services.GetRequiredService() + .CreateLogger(typeof(DiagnosticsMonitorCommandHandler)) + .OptionsValidationFailure(ex); + return -1; } - else + finally { - host.Dispose(); + if (host is IAsyncDisposable asyncDisposable) + { + await asyncDisposable.DisposeAsync(); + } + else + { + host.Dispose(); + } + } + } + catch (FormatException ex) + { + Console.Error.WriteLine(ex.Message); + if (ex.InnerException != null) + { + Console.Error.WriteLine(ex.InnerException.Message); } + + return -1; } + return 0; } @@ -108,7 +122,7 @@ public Task ShowConfig(CancellationToken token, IConsole console, string[] IConfiguration configuration = host.Services.GetRequiredService(); using ConfigurationJsonWriter writer = new ConfigurationJsonWriter(Console.OpenStandardOutput()); writer.Write(configuration, full: level == ConfigDisplayLevel.Full); - + return Task.FromResult(0); } From 6ad15dbf34cc6e7f352849d56a0bc07780280afc Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 16 Jun 2021 20:56:02 +0000 Subject: [PATCH 070/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210615.18 (#449) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 9b9f88bce01..f03b5282ccc 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - 2713df3bc4f9364775785410827124a2c1c8864e + 963242a12c8b149caee5a9fa3215a8452a4be999 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 297f06ae4b9..42fd28c8530 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21314.1 - 6.0.0-preview.6.21314.7 + 6.0.0-preview.7.21315.18 5.0.0-preview.21314.1 5.0.0-preview.21314.1 From cb52c8a7e4dddf24347f9b925deb60580ba026a9 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 16 Jun 2021 21:31:15 +0000 Subject: [PATCH 071/185] Update dependencies from https://github.com/dotnet/runtime build 20210616.2 (#450) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index f03b5282ccc..6c2167c1898 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 963242a12c8b149caee5a9fa3215a8452a4be999 - + https://github.com/dotnet/runtime - bc16a7bd2dcca7f1f8ce70e75dc86a3fac3ffcd2 + 6b015e2e24461313622575ca56fb76d4ad469ab5 diff --git a/eng/Versions.props b/eng/Versions.props index 42fd28c8530..30678965a08 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21314.1 5.0.0-preview.21314.1 - 6.0.0-preview.6.21314.2 + 6.0.0-preview.7.21316.2 1.0.215101 From c57a8f1cf54b2e3a396e1600451d8cef74fe2cb0 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 17 Jun 2021 01:18:58 +0000 Subject: [PATCH 072/185] Update dependencies from https://github.com/dotnet/diagnostics build 20210615.1 (#448) [main] Update dependencies from dotnet/diagnostics --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 6c2167c1898..1a65d827826 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,11 +4,11 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics b1420fc8dfb701ecd6095716c6deaa4ac885cafc - + https://github.com/dotnet/diagnostics b1420fc8dfb701ecd6095716c6deaa4ac885cafc diff --git a/eng/Versions.props b/eng/Versions.props index 30678965a08..da0ceaa0446 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-preview.7.21315.18 - 5.0.0-preview.21314.1 - 5.0.0-preview.21314.1 + 5.0.0-preview.21315.1 + 5.0.0-preview.21315.1 6.0.0-preview.7.21316.2 From 09ba56b65e4deed71dedc0f16b8705c5b2f78f87 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 17 Jun 2021 12:31:41 +0000 Subject: [PATCH 073/185] Update dependencies from https://github.com/dotnet/diagnostics build 20210616.1 (#453) [main] Update dependencies from dotnet/diagnostics --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 1a65d827826..fd0506880d3 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics - b1420fc8dfb701ecd6095716c6deaa4ac885cafc + 605d5481c4aa09c801a55785d523811696e3fe2e - + https://github.com/dotnet/diagnostics - b1420fc8dfb701ecd6095716c6deaa4ac885cafc + 605d5481c4aa09c801a55785d523811696e3fe2e diff --git a/eng/Versions.props b/eng/Versions.props index da0ceaa0446..b409c4f1787 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-preview.7.21315.18 - 5.0.0-preview.21315.1 - 5.0.0-preview.21315.1 + 5.0.0-preview.21316.1 + 5.0.0-preview.21316.1 6.0.0-preview.7.21316.2 From 8990b42b0525b08b8b0653160795e378a4e46926 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 17 Jun 2021 12:31:59 +0000 Subject: [PATCH 074/185] Update dependencies from https://github.com/dotnet/arcade build 20210616.3 (#454) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- eng/common/templates/job/source-index-stage1.yml | 6 +++++- global.json | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index fd0506880d3..8697ca074ab 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -14,13 +14,13 @@ - + https://github.com/dotnet/arcade - fc067a0928f1c8ca4ab3471e9f8edb592e96dec4 + d8967a1e57275aa682c7639ef95b4d148722ba4e - + https://github.com/dotnet/arcade - fc067a0928f1c8ca4ab3471e9f8edb592e96dec4 + d8967a1e57275aa682c7639ef95b4d148722ba4e https://github.com/dotnet/symstore diff --git a/eng/Versions.props b/eng/Versions.props index b409c4f1787..a3948789b92 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -27,7 +27,7 @@ --> - 6.0.0-beta.21314.1 + 6.0.0-beta.21316.3 6.0.0-preview.7.21315.18 diff --git a/eng/common/templates/job/source-index-stage1.yml b/eng/common/templates/job/source-index-stage1.yml index a649d2b5990..b58d42364b9 100644 --- a/eng/common/templates/job/source-index-stage1.yml +++ b/eng/common/templates/job/source-index-stage1.yml @@ -1,15 +1,19 @@ parameters: runAsPublic: false - sourceIndexPackageVersion: 1.0.1-20210421.1 + sourceIndexPackageVersion: 1.0.1-20210614.1 sourceIndexPackageSource: https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json sourceIndexBuildCommand: powershell -NoLogo -NoProfile -ExecutionPolicy Bypass -Command "eng/common/build.ps1 -restore -build -binarylog -ci" preSteps: [] binlogPath: artifacts/log/Debug/Build.binlog pool: vmImage: vs2017-win2016 + condition: '' + dependsOn: '' jobs: - job: SourceIndexStage1 + dependsOn: ${{ parameters.dependsOn }} + condition: ${{ parameters.condition }} variables: - name: SourceIndexPackageVersion value: ${{ parameters.sourceIndexPackageVersion }} diff --git a/global.json b/global.json index 94db4b0dc63..14005765f1d 100644 --- a/global.json +++ b/global.json @@ -16,6 +16,6 @@ }, "msbuild-sdks": { "Microsoft.Build.NoTargets": "2.0.1", - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21314.1" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21316.3" } } From b6b5f3e23ebe6f8db3f01b5101e70c27166760ba Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 17 Jun 2021 12:48:00 +0000 Subject: [PATCH 075/185] Update dependencies from https://github.com/dotnet/runtime build 20210617.1 (#455) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 8697ca074ab..80f015f60c0 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 963242a12c8b149caee5a9fa3215a8452a4be999 - + https://github.com/dotnet/runtime - 6b015e2e24461313622575ca56fb76d4ad469ab5 + 96a4671bc52e70024da409f5f48b0abaa30cb901 diff --git a/eng/Versions.props b/eng/Versions.props index a3948789b92..92b496ae441 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21316.1 5.0.0-preview.21316.1 - 6.0.0-preview.7.21316.2 + 6.0.0-preview.7.21317.1 1.0.215101 From 8df07a17b3b6a592af62558c4b6774d3d762abfa Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 17 Jun 2021 12:48:09 +0000 Subject: [PATCH 076/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210616.11 (#456) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 80f015f60c0..1e94ab09151 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - 963242a12c8b149caee5a9fa3215a8452a4be999 + 4fc4748c196de4bae8da1e146638f484e7e4b99c https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 92b496ae441..09ec642e0e4 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21316.3 - 6.0.0-preview.7.21315.18 + 6.0.0-preview.7.21316.11 5.0.0-preview.21316.1 5.0.0-preview.21316.1 From 11889818629a8368d63f749b7360c13d46bdb28d Mon Sep 17 00:00:00 2001 From: Justin Anderson Date: Thu, 17 Jun 2021 17:14:18 -0700 Subject: [PATCH 077/185] Increase dump collection timeout and log request durations. (#452) --- .../HttpApi/ApiClient.cs | 4 ++++ .../TestTimeouts.cs | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClient.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClient.cs index c68adc80b12..6a73351f49e 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClient.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClient.cs @@ -8,6 +8,7 @@ using Microsoft.Net.Http.Headers; using System; using System.Collections.Generic; +using System.Diagnostics; using System.Globalization; using System.IO; using System.Net; @@ -318,10 +319,12 @@ private static Task> ReadContentEnumerableAsync(HttpResponseMessage r private async Task SendAndLogAsync(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationToken token) { + Stopwatch sw = Stopwatch.StartNew(); HttpResponseMessage response; try { response = await _httpClient.SendAsync(request, completionOption, token).ConfigureAwait(false); + sw.Stop(); } finally { @@ -329,6 +332,7 @@ private async Task SendAndLogAsync(HttpRequestMessage reque } _outputHelper.WriteLine("<- {0}", response.ToString()); + _outputHelper.WriteLine($"Request duration: {sw.ElapsedMilliseconds} ms"); return response; } diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/TestTimeouts.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/TestTimeouts.cs index 68cb7fedd93..0eea5c20b38 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/TestTimeouts.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/TestTimeouts.cs @@ -36,6 +36,9 @@ internal static class TestTimeouts /// /// Default timeout for dump collection. /// - public static readonly TimeSpan DumpTimeout = TimeSpan.FromMinutes(1); + /// + /// Dumps (especially full dumps) can be quite large and take a significant amount of time to transfer. + /// + public static readonly TimeSpan DumpTimeout = TimeSpan.FromMinutes(3); } } From 367bfc5be623fc25a48526493cefe87441a4bce1 Mon Sep 17 00:00:00 2001 From: Justin Anderson Date: Thu, 17 Jun 2021 17:14:36 -0700 Subject: [PATCH 078/185] Remove boilerplate code for single target tests. (#457) --- .../DumpTests.cs | 167 ++++++++---------- .../LogsTests.cs | 8 +- .../ProcessTests.cs | 56 +++--- .../Runners/ScenarioRunner.cs | 22 ++- 4 files changed, 123 insertions(+), 130 deletions(-) diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/DumpTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/DumpTests.cs index a2e4a4a7779..02cfede528d 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/DumpTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/DumpTests.cs @@ -48,112 +48,99 @@ public DumpTests(ITestOutputHelper outputHelper, ServiceProviderFixture serviceP [InlineData(DiagnosticPortConnectionMode.Listen, DumpType.Triage)] [InlineData(DiagnosticPortConnectionMode.Listen, DumpType.WithHeap)] #endif - public async Task DumpTest(DiagnosticPortConnectionMode mode, DumpType type) + public Task DumpTest(DiagnosticPortConnectionMode mode, DumpType type) { - DiagnosticPortHelper.Generate( + return ScenarioRunner.SingleTarget( + _outputHelper, + _httpClientFactory, mode, - out DiagnosticPortConnectionMode appConnectionMode, - out string diagnosticPortPath); - - await using MonitorRunner toolRunner = new(_outputHelper); - toolRunner.ConnectionMode = mode; - toolRunner.DiagnosticPortPath = diagnosticPortPath; - toolRunner.DisableAuthentication = true; - await toolRunner.StartAsync(); - - using HttpClient httpClient = await toolRunner.CreateHttpClientDefaultAddressAsync(_httpClientFactory); - ApiClient apiClient = new(_outputHelper, httpClient); - - AppRunner appRunner = new(_outputHelper); - appRunner.ConnectionMode = appConnectionMode; - appRunner.DiagnosticPortPath = diagnosticPortPath; - appRunner.ScenarioName = TestAppScenarios.AsyncWait.Name; - - // 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) - { - appRunner.Environment.Add(EnableElfDumpOnMacOS, "1"); - } - - await appRunner.ExecuteAsync(async () => - { - ProcessInfo processInfo = await apiClient.GetProcessAsync(appRunner.ProcessId); - Assert.NotNull(processInfo); - - using ResponseStreamHolder holder = await apiClient.CaptureDumpAsync(appRunner.ProcessId, type); - Assert.NotNull(holder); - - byte[] headerBuffer = new byte[64]; - - // Read enough to deserialize the header. - int read; - int total = 0; - using CancellationTokenSource cancellation = new(TestTimeouts.DumpTimeout); - while (total < headerBuffer.Length && 0 != (read = await holder.Stream.ReadAsync(headerBuffer, total, headerBuffer.Length - total, cancellation.Token))) + TestAppScenarios.AsyncWait.Name, + appValidate: async (runner, client) => { - total += read; - } - Assert.Equal(headerBuffer.Length, total); + ProcessInfo processInfo = await client.GetProcessAsync(runner.ProcessId); + Assert.NotNull(processInfo); - // Read header and validate - using MemoryStream headerStream = new(headerBuffer); + using ResponseStreamHolder holder = await client.CaptureDumpAsync(runner.ProcessId, type); + Assert.NotNull(holder); - StreamAddressSpace dumpAddressSpace = new(headerStream); - Reader dumpReader = new(dumpAddressSpace); + byte[] headerBuffer = new byte[64]; - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - MinidumpHeader header = dumpReader.Read(0); - // Validate Signature - Assert.True(header.IsSignatureValid.Check()); - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) - { - ELFHeaderIdent ident = dumpReader.Read(0); - Assert.True(ident.IsIdentMagicValid.Check()); - Assert.True(ident.IsClassValid.Check()); - Assert.True(ident.IsDataValid.Check()); - - LayoutManager layoutManager = new(); - layoutManager.AddELFTypes( - isBigEndian: ident.Data == ELFData.BigEndian, - is64Bit: ident.Class == ELFClass.Class64); - Reader headerReader = new(dumpAddressSpace, layoutManager); - - ELFHeader header = headerReader.Read(0); - // Validate Signature - Assert.True(header.IsIdentMagicValid.Check()); - // Validate ELF file is a core dump - Assert.Equal(ELFHeaderType.Core, header.Type); - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - if (appRunner.Environment.ContainsKey(EnableElfDumpOnMacOS)) + // Read enough to deserialize the header. + int read; + int total = 0; + using CancellationTokenSource cancellation = new(TestTimeouts.DumpTimeout); + while (total < headerBuffer.Length && 0 != (read = await holder.Stream.ReadAsync(headerBuffer, total, headerBuffer.Length - total, cancellation.Token))) + { + total += read; + } + Assert.Equal(headerBuffer.Length, total); + + // Read header and validate + using MemoryStream headerStream = new(headerBuffer); + + StreamAddressSpace dumpAddressSpace = new(headerStream); + Reader dumpReader = new(dumpAddressSpace); + + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + MinidumpHeader header = dumpReader.Read(0); + // Validate Signature + Assert.True(header.IsSignatureValid.Check()); + } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { - ELFHeader header = dumpReader.Read(0); + ELFHeaderIdent ident = dumpReader.Read(0); + Assert.True(ident.IsIdentMagicValid.Check()); + Assert.True(ident.IsClassValid.Check()); + Assert.True(ident.IsDataValid.Check()); + + LayoutManager layoutManager = new(); + layoutManager.AddELFTypes( + isBigEndian: ident.Data == ELFData.BigEndian, + is64Bit: ident.Class == ELFClass.Class64); + Reader headerReader = new(dumpAddressSpace, layoutManager); + + ELFHeader header = headerReader.Read(0); // Validate Signature Assert.True(header.IsIdentMagicValid.Check()); // Validate ELF file is a core dump Assert.Equal(ELFHeaderType.Core, header.Type); } + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + { + if (runner.Environment.ContainsKey(EnableElfDumpOnMacOS)) + { + ELFHeader header = dumpReader.Read(0); + // Validate Signature + Assert.True(header.IsIdentMagicValid.Check()); + // Validate ELF file is a core dump + Assert.Equal(ELFHeaderType.Core, header.Type); + } + else + { + MachHeader header = dumpReader.Read(0); + // Validate Signature + Assert.True(header.IsMagicValid.Check()); + // Validate MachO file is a core dump + Assert.True(header.IsFileTypeValid.Check()); + Assert.Equal(MachHeaderFileType.Core, header.FileType); + } + } else { - MachHeader header = dumpReader.Read(0); - // Validate Signature - Assert.True(header.IsMagicValid.Check()); - // Validate MachO file is a core dump - Assert.True(header.IsFileTypeValid.Check()); - Assert.Equal(MachHeaderFileType.Core, header.FileType); + throw new NotImplementedException("Dump header check not implemented for this OS platform."); } - } - else - { - throw new NotImplementedException("Dump header check not implemented for this OS platform."); - } - await appRunner.SendCommandAsync(TestAppScenarios.AsyncWait.Commands.Continue); - }); - Assert.Equal(0, appRunner.ExitCode); + 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(EnableElfDumpOnMacOS, "1"); + } + }); } private class MinidumpHeader : TStruct diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/LogsTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/LogsTests.cs index ca2bb453865..f8102e37f70 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/LogsTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/LogsTests.cs @@ -161,7 +161,7 @@ public Task LogsDefaultLevelNoneNotSupportedViaQueryTest(DiagnosticPortConnectio _httpClientFactory, mode, TestAppScenarios.Logger.Name, - async (runner, client) => + appValidate: async (runner, client) => { ValidationProblemDetailsException exception = await Assert.ThrowsAsync( async () => @@ -194,7 +194,7 @@ public Task LogsDefaultLevelNoneNotSupportedViaBodyTest(DiagnosticPortConnection _httpClientFactory, mode, TestAppScenarios.Logger.Name, - async (runner, client) => + appValidate: async (runner, client) => { ValidationProblemDetailsException exception = await Assert.ThrowsAsync( async () => @@ -373,7 +373,7 @@ private Task ValidateLogsAsync( _httpClientFactory, mode, TestAppScenarios.Logger.Name, - (runner, client) => ValidateResponseStream( + appValidate: (runner, client) => ValidateResponseStream( runner, client.CaptureLogsAsync(runner.ProcessId, TestTimeouts.LogsDuration, logLevel), callback)); @@ -389,7 +389,7 @@ private Task ValidateLogsAsync( _httpClientFactory, mode, TestAppScenarios.Logger.Name, - (runner, client) => ValidateResponseStream( + appValidate: (runner, client) => ValidateResponseStream( runner, client.CaptureLogsAsync(runner.ProcessId, TestTimeouts.LogsDuration, configuration), callback)); diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/ProcessTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/ProcessTests.cs index d6270bd54ae..2312a6ac9a3 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/ProcessTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/ProcessTests.cs @@ -43,43 +43,33 @@ public ProcessTests(ITestOutputHelper outputHelper, ServiceProviderFixture servi #if NET5_0_OR_GREATER [InlineData(DiagnosticPortConnectionMode.Listen)] #endif - public async Task SingleProcessIdentificationTest(DiagnosticPortConnectionMode mode) + public Task SingleProcessIdentificationTest(DiagnosticPortConnectionMode mode) { - DiagnosticPortHelper.Generate( - mode, - out DiagnosticPortConnectionMode appConnectionMode, - out string diagnosticPortPath); - - await using MonitorRunner toolRunner = new(_outputHelper); - toolRunner.ConnectionMode = mode; - toolRunner.DiagnosticPortPath = diagnosticPortPath; - toolRunner.DisableAuthentication = true; - await toolRunner.StartAsync(); - - using HttpClient httpClient = await toolRunner.CreateHttpClientDefaultAddressAsync(_httpClientFactory); - ApiClient apiClient = new(_outputHelper, httpClient); - - AppRunner appRunner = new(_outputHelper); - appRunner.ConnectionMode = appConnectionMode; - appRunner.DiagnosticPortPath = diagnosticPortPath; - appRunner.ScenarioName = TestAppScenarios.AsyncWait.Name; - string expectedEnvVarValue = Guid.NewGuid().ToString("D"); - appRunner.Environment[ExpectedEnvVarName] = expectedEnvVarValue; - await appRunner.ExecuteAsync(async () => - { - await VerifyProcessAsync(apiClient, await apiClient.GetProcessesAsync(), appRunner.ProcessId, expectedEnvVarValue); - - await appRunner.SendCommandAsync(TestAppScenarios.AsyncWait.Commands.Continue); - }); - Assert.Equal(0, appRunner.ExitCode); + return ScenarioRunner.SingleTarget( + _outputHelper, + _httpClientFactory, + mode, + TestAppScenarios.AsyncWait.Name, + appValidate: async (runner, client) => + { + await VerifyProcessAsync(client, await client.GetProcessesAsync(), runner.ProcessId, expectedEnvVarValue); - // Verify app is no longer reported - IEnumerable identifiers = await apiClient.GetProcessesAsync(); - Assert.NotNull(identifiers); - ProcessIdentifier identifier = identifiers.FirstOrDefault(p => p.Pid == appRunner.ProcessId); - Assert.Null(identifier); + await runner.SendCommandAsync(TestAppScenarios.AsyncWait.Commands.Continue); + }, + postAppValidate: async (client, processId) => + { + // Verify app is no longer reported + IEnumerable identifiers = await client.GetProcessesAsync(); + Assert.NotNull(identifiers); + ProcessIdentifier identifier = identifiers.FirstOrDefault(p => p.Pid == processId); + Assert.Null(identifier); + }, + configureApp: runner => + { + runner.Environment[ExpectedEnvVarName] = expectedEnvVarValue; + }); } /// diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Runners/ScenarioRunner.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Runners/ScenarioRunner.cs index 005b823ebb7..fc5fd235817 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Runners/ScenarioRunner.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Runners/ScenarioRunner.cs @@ -1,4 +1,8 @@ -using Microsoft.Diagnostics.Monitoring.UnitTests.HttpApi; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Diagnostics.Monitoring.UnitTests.HttpApi; using Microsoft.Diagnostics.Monitoring.UnitTests.Options; using System; using System.Net.Http; @@ -15,7 +19,9 @@ public static async Task SingleTarget( IHttpClientFactory httpClientFactory, DiagnosticPortConnectionMode mode, string scenarioName, - Func callback) + Func appValidate, + Func postAppValidate = null, + Action configureApp = null) { DiagnosticPortHelper.Generate( mode, @@ -36,11 +42,21 @@ public static async Task SingleTarget( appRunner.DiagnosticPortPath = diagnosticPortPath; appRunner.ScenarioName = scenarioName; + if (null != configureApp) + { + configureApp(appRunner); + } + await appRunner.ExecuteAsync(async () => { - await callback(appRunner, apiClient); + await appValidate(appRunner, apiClient); }); Assert.Equal(0, appRunner.ExitCode); + + if (null != postAppValidate) + { + await postAppValidate(apiClient, appRunner.ProcessId); + } } } } From d4999f15c5cf80bfb98872599b0587a6e641938a Mon Sep 17 00:00:00 2001 From: Patrick Fenelon Date: Thu, 17 Jun 2021 20:45:31 -0700 Subject: [PATCH 079/185] Convert strings to Resource Strings (#362) Convert all strings that should be localizable into resource strings --- .../Controllers/DiagController.cs | 2 +- .../Controllers/MetricsController.cs | 2 +- .../CorsConfiguration.cs | 7 +- .../DiagProcessFilter.cs | 13 +- .../DiagnosticServices.cs | 19 +- .../LoggingExtensions.cs | 14 +- .../MetricsOptions.cs | 34 +- .../MetricsStore.cs | 3 +- ...osoft.Diagnostics.Monitoring.WebApi.csproj | 22 + .../OptionsDisplayStrings.Designer.cs | 324 ++++++++++ .../OptionsDisplayStrings.resx | 236 +++++++ .../ProcessFilterOptions.cs | 38 +- .../StorageOptions.cs | 10 +- .../Strings.Designer.cs | 225 +++++++ .../Strings.resx | 208 +++++++ .../Validation/IntegerOrHexStringAttribute.cs | 8 +- ...oring.ConfigurationSchema.UnitTests.csproj | 1 + ...agnostics.Monitoring.Tool.UnitTests.csproj | 1 + .../Options/EgressOptions.cs | 15 +- ...ft.Diagnostics.Monitoring.UnitTests.csproj | 5 +- .../Auth/ApiAuthenticationOptions.cs | 10 +- .../Auth/ApiKeyAuthenticationHandler.cs | 14 +- ...piKeyAuthenticationPostConfigureOptions.cs | 29 +- .../dotnet-monitor/ConfigurationJsonWriter.cs | 4 +- .../dotnet-monitor/DiagnosticPortOptions.cs | 21 +- .../DiagnosticPortValidateOptions.cs | 2 +- .../AzureBlob/AzureBlobEgressProvider.cs | 7 +- .../AzureBlobEgressProviderOptions.cs | 7 +- .../dotnet-monitor/Egress/EgressService.cs | 5 +- .../FileSystem/FileSystemEgressProvider.cs | 5 +- .../FilteredEndpointInfoSource.cs | 3 +- .../GenerateApiKeyCommandHandler.cs | 17 +- src/Tools/dotnet-monitor/LoggingExtensions.cs | 58 +- src/Tools/dotnet-monitor/Program.cs | 61 +- src/Tools/dotnet-monitor/Startup.cs | 2 +- src/Tools/dotnet-monitor/Strings.Designer.cs | 576 ++++++++++++++++++ src/Tools/dotnet-monitor/Strings.resx | 429 +++++++++++++ src/Tools/dotnet-monitor/Throttling.cs | 3 - .../dotnet-monitor/dotnet-monitor.csproj | 12 + 39 files changed, 2306 insertions(+), 146 deletions(-) create mode 100644 src/Microsoft.Diagnostics.Monitoring.WebApi/OptionsDisplayStrings.Designer.cs create mode 100644 src/Microsoft.Diagnostics.Monitoring.WebApi/OptionsDisplayStrings.resx create mode 100644 src/Microsoft.Diagnostics.Monitoring.WebApi/Strings.Designer.cs create mode 100644 src/Microsoft.Diagnostics.Monitoring.WebApi/Strings.resx create mode 100644 src/Tools/dotnet-monitor/Strings.Designer.cs create mode 100644 src/Tools/dotnet-monitor/Strings.resx diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.cs index 4683fcf78ca..e3772c5a291 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.cs @@ -131,7 +131,7 @@ public Task>> GetProcessEnvironment( } catch (ServerErrorException) { - throw new InvalidOperationException("Unable to get process environment."); + throw new InvalidOperationException(Strings.ErrorMessage_CanNotGetEnvironment); } }, processKey); diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/MetricsController.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/MetricsController.cs index 558c015fb60..52a077f02c5 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/MetricsController.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/MetricsController.cs @@ -46,7 +46,7 @@ public ActionResult GetMetrics() { if (!_metricsOptions.Enabled.GetValueOrDefault(MetricsOptionsDefaults.Enabled)) { - throw new InvalidOperationException("Metrics was not enabled"); + throw new InvalidOperationException(Strings.ErrorMessage_MetricsDisabled); } KeyValueLogScope scope = new KeyValueLogScope(); diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/CorsConfiguration.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/CorsConfiguration.cs index 75c7df2371f..e7fe9b47d6b 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/CorsConfiguration.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/CorsConfiguration.cs @@ -2,10 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.ComponentModel; using System.ComponentModel.DataAnnotations; #if UNITTEST +using Microsoft.Diagnostics.Monitoring.WebApi; + namespace Microsoft.Diagnostics.Monitoring.UnitTests.Options #else namespace Microsoft.Diagnostics.Monitoring.WebApi @@ -13,7 +14,9 @@ namespace Microsoft.Diagnostics.Monitoring.WebApi { public class CorsConfiguration { - [Display(Description = "List of allowed CORS origins, separated by semicolons.")] + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_CorsConfiguration_AllowedOrigins))] [Required] public string AllowedOrigins { get; set; } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/DiagProcessFilter.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/DiagProcessFilter.cs index 70f3be886dd..2a5ad85be7c 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/DiagProcessFilter.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/DiagProcessFilter.cs @@ -77,7 +77,13 @@ private static DiagProcessFilterEntry TransformDescriptor(ProcessFilterDescripto Value = processFilterDescriptor.Value }; default: - throw new ArgumentException($"Invalid {nameof(processFilterDescriptor)}"); + throw new ArgumentException( + string.Format( + CultureInfo.InvariantCulture, + Strings.ErrorMessage_UnexpectedType, + nameof(ProcessFilterDescriptor), + processFilterDescriptor.Key), + nameof(processFilterDescriptor)); } } } @@ -103,9 +109,8 @@ public bool MatchFilter(IProcessInfo processInfo) case DiagProcessFilterCriteria.ProcessName: return Compare(processInfo.ProcessName); default: - Debug.Fail("Unexpected filter criteria"); + Debug.Fail($"Unexpected {nameof(DiagProcessFilterCriteria)}: {this.Criteria}"); break; - } return false; @@ -121,7 +126,7 @@ private bool Compare(string value) { return ContainsCompare(value); } - Debug.Fail("Unexpected match type"); + Debug.Fail($"Unexpected {nameof(DiagProcessFilterMatchType)}: {MatchType}"); return false; } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/DiagnosticServices.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/DiagnosticServices.cs index c21c023e84b..0e0950fdb2c 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/DiagnosticServices.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/DiagnosticServices.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; +using System.Globalization; using System.IO; using System.Linq; using System.Runtime.InteropServices; @@ -70,7 +71,7 @@ public async Task> GetProcessesAsync(DiagProcessFilter } catch (UnauthorizedAccessException) { - throw new InvalidOperationException("Unable to enumerate processes."); + throw new InvalidOperationException(Strings.ErrorMessage_ProcessEnumeratuinFailed); } if (processFilterConfig != null) @@ -116,7 +117,13 @@ private static DumpType MapDumpType(Models.DumpType dumpType) case Models.DumpType.Mini: return DumpType.Normal; default: - throw new ArgumentException("Unexpected dumpType", nameof(dumpType)); + throw new ArgumentException( + string.Format( + CultureInfo.InvariantCulture, + Strings.ErrorMessage_UnexpectedType, + nameof(DumpType), + dumpType), + nameof(dumpType)); } } @@ -140,18 +147,18 @@ private async Task GetProcessAsync(DiagProcessFilter processFilter //Short circuit when we are missing default process config if (!processFilterConfig.Filters.Any()) { - throw new InvalidOperationException("No default process configuration has been set."); + throw new InvalidOperationException(Strings.ErrorMessage_NoDefaultProcessConfig); } IEnumerable matchingProcesses = await GetProcessesAsync(processFilterConfig, token); switch (matchingProcesses.Count()) { case 0: - throw new ArgumentException("Unable to discover a target process."); + throw new ArgumentException(Strings.ErrorMessage_NoTargetProcess); case 1: return matchingProcesses.First(); default: - throw new ArgumentException("Unable to select a single target process because multiple target processes have been discovered."); + throw new ArgumentException(Strings.ErrorMessage_MultipleTargetProcesses); } } @@ -180,7 +187,7 @@ private sealed class ProcessInfo : IProcessInfo { // String returned for a process field when its value could not be retrieved. This is the same // value that is returned by the runtime when it could not determine the value for each of those fields. - private const string ProcessFieldUnknownValue = "unknown"; + private static readonly string ProcessFieldUnknownValue = "unknown"; public ProcessInfo( IEndpointInfo endpointInfo, diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/LoggingExtensions.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/LoggingExtensions.cs index 1d3c5fcda8c..f583c437ea8 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/LoggingExtensions.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/LoggingExtensions.cs @@ -13,37 +13,37 @@ internal static class LoggingExtensions LoggerMessage.Define( eventId: new EventId(1, "RequestFailed"), logLevel: LogLevel.Error, - formatString: "Request failed."); + formatString: Strings.LogFormatString_RequestFailed); private static readonly Action _requestCanceled = LoggerMessage.Define( eventId: new EventId(2, "RequestCanceled"), logLevel: LogLevel.Information, - formatString: "Request canceled."); + formatString: Strings.LogFormatString_RequestCanceled); private static readonly Action _resolvedTargetProcess = LoggerMessage.Define( eventId: new EventId(3, "ResolvedTargetProcess"), logLevel: LogLevel.Debug, - formatString: "Resolved target process."); + formatString: Strings.LogFormatString_ResolvedTargetProcess); private static readonly Action _egressedArtifact = LoggerMessage.Define( eventId: new EventId(4, "EgressedArtifact"), logLevel: LogLevel.Information, - formatString: "Egressed artifact to {location}"); + formatString: Strings.LogFormatString_EgressedArtifact); private static readonly Action _writtenToHttpStream = LoggerMessage.Define( eventId: new EventId(5, "WrittenToHttpStream"), logLevel: LogLevel.Information, - formatString: "Written to HTTP stream."); + formatString: Strings.LogFormatString_WrittenToHttpStream); private static readonly Action _throttledEndpoint = LoggerMessage.Define( - eventId: new EventId(6, "ThrottledEndpoint"), + eventId: new EventId(6, "ThrottledEndpoint"), logLevel: LogLevel.Warning, - formatString: "Request limit for endpoint reached. Limit: {limit}, oustanding requests: {requests}"); + formatString: Strings.LogFormatString_ThrottledEndpoint); public static void RequestFailed(this ILogger logger, Exception ex) { diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/MetricsOptions.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/MetricsOptions.cs index 13305d815b9..d87bf6465f6 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/MetricsOptions.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/MetricsOptions.cs @@ -7,6 +7,8 @@ using System.ComponentModel.DataAnnotations; #if UNITTEST +using Microsoft.Diagnostics.Monitoring.WebApi; + namespace Microsoft.Diagnostics.Monitoring.UnitTests.Options #else namespace Microsoft.Diagnostics.Monitoring.WebApi @@ -20,36 +22,52 @@ namespace Microsoft.Diagnostics.Monitoring.WebApi /// public class MetricsOptions { - [Display(Description = "Enable or disable metrics collection.")] + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_MetricsOptions_Enabled))] [DefaultValue(MetricsOptionsDefaults.Enabled)] public bool? Enabled { get; set; } - [Display(Description = "Endpoints that expose prometheus metrics. Defaults to http://localhost:52325.")] + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_MetricsOptions_Endpoints))] public string Endpoints { get; set; } + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_MetricsOptions_UpdateIntervalSeconds))] [DefaultValue(MetricsOptionsDefaults.UpdateIntervalSeconds)] - [Display(Description = "How often metrics are collected.")] public int? UpdateIntervalSeconds { get; set; } + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_MetricsOptions_MetricCount))] [DefaultValue(MetricsOptionsDefaults.MetricCount)] - [Display(Description = "Amount of data points to store per metric.")] public int? MetricCount { get; set; } + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_MetricsOptions_IncludeDefaultProviders))] [DefaultValue(MetricsOptionsDefaults.IncludeDefaultProviders)] - [Display(Description = "Include default providers: System.Runtime, Microsoft.AspNetCore.Hosting, and Grpc.AspNetCore.Server.")] public bool? IncludeDefaultProviders { get; set; } - [Display(Description = "Providers for custom metrics.")] + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_MetricsOptions_Providers))] public List Providers { get; set; } = new List(0); } public class MetricProvider { - [Display(Description = "The name of the custom metrics provider.")] + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_MetricProvider_ProviderName))] [Required] public string ProviderName { get; set; } - [Display(Description = "Name of custom metrics counters.")] + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_MetricProvider_CounterNames))] public List CounterNames { get; set; } = new List(0); } } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/MetricsStore.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/MetricsStore.cs index 02cde46c324..32df5695bc0 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/MetricsStore.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/MetricsStore.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using Microsoft.Diagnostics.Monitoring.EventPipe; +using Microsoft.Diagnostics.Monitoring.WebApi; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -63,7 +64,7 @@ public MetricsStore(int maxMetricCount) { if (maxMetricCount < 1) { - throw new ArgumentException("Invalid metric count"); + throw new ArgumentException(Strings.ErrorMessage_InvalidMetricCount); } _maxMetricCount = maxMetricCount; } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Microsoft.Diagnostics.Monitoring.WebApi.csproj b/src/Microsoft.Diagnostics.Monitoring.WebApi/Microsoft.Diagnostics.Monitoring.WebApi.csproj index d6f89afb2b1..5c39085284d 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Microsoft.Diagnostics.Monitoring.WebApi.csproj +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Microsoft.Diagnostics.Monitoring.WebApi.csproj @@ -43,4 +43,26 @@ + + + + True + True + OptionsDisplayStrings.resx + + + True + True + Strings.resx + + + PublicResXFileCodeGenerator + OptionsDisplayStrings.Designer.cs + Microsoft.Diagnostics.Monitoring.WebApi + + + ResXFileCodeGenerator + Strings.Designer.cs + + \ No newline at end of file diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/OptionsDisplayStrings.Designer.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/OptionsDisplayStrings.Designer.cs new file mode 100644 index 00000000000..eac7b198187 --- /dev/null +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/OptionsDisplayStrings.Designer.cs @@ -0,0 +1,324 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Microsoft.Diagnostics.Monitoring.WebApi { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class OptionsDisplayStrings { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal OptionsDisplayStrings() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.Diagnostics.Monitoring.WebApi.OptionsDisplayStrings", typeof(OptionsDisplayStrings).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to API key in hashed form. Each byte should be two hexadecimal-based digits.. + /// + public static string DisplayAttributeDescription_ApiAuthenticationOptions_ApiKeyHash { + get { + return ResourceManager.GetString("DisplayAttributeDescription_ApiAuthenticationOptions_ApiKeyHash", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Hash algorithm used to compute ApiKeyHash, typically 'SHA256'. 'SHA1' and 'MD5' are not allowed.. + /// + public static string DisplayAttributeDescription_ApiAuthenticationOptions_ApiKeyHashType { + get { + return ResourceManager.GetString("DisplayAttributeDescription_ApiAuthenticationOptions_ApiKeyHashType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to List of allowed CORS origins, separated by semicolons.. + /// + public static string DisplayAttributeDescription_CorsConfiguration_AllowedOrigins { + get { + return ResourceManager.GetString("DisplayAttributeDescription_CorsConfiguration_AllowedOrigins", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Launches in mode where dotnet-monitor will connect to a separate running dotnet process.. + /// + public static string DisplayAttributeDescription_DiagnosticPortConnectionMode_Connect { + get { + return ResourceManager.GetString("DisplayAttributeDescription_DiagnosticPortConnectionMode_Connect", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Launches in mode where dotnet-monitor will listen for connections from a separate running dotnet process. This configuration options requires environment variables be set on the target process.. + /// + public static string DisplayAttributeDescription_DiagnosticPortConnectionMode_Listen { + get { + return ResourceManager.GetString("DisplayAttributeDescription_DiagnosticPortConnectionMode_Listen", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to In 'Connect' mode, dotnet-monitor connects to the application for diagnostics. In 'Listen' mode, the application connects to dotnet-monitor via EndpointName.. + /// + public static string DisplayAttributeDescription_DiagnosticPortOptions_ConnectionMode { + get { + return ResourceManager.GetString("DisplayAttributeDescription_DiagnosticPortOptions_ConnectionMode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to In 'Listen' mode, specifies the name of the named pipe or unix domain socket to use for connecting to the diagnostic server.. + /// + public static string DisplayAttributeDescription_DiagnosticPortOptions_EndpointName { + get { + return ResourceManager.GetString("DisplayAttributeDescription_DiagnosticPortOptions_EndpointName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to In 'Listen' mode, the maximum amount of connections to accept.. + /// + public static string DisplayAttributeDescription_DiagnosticPortOptions_MaxConnections { + get { + return ResourceManager.GetString("DisplayAttributeDescription_DiagnosticPortOptions_MaxConnections", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Additional properties, such as secrets, that can be referenced by the provider definitions.. + /// + public static string DisplayAttributeDescription_EgressOptions_Properties { + get { + return ResourceManager.GetString("DisplayAttributeDescription_EgressOptions_Properties", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Named providers for egress. The names can be referenced when requesting artifacts, such as dumps or traces.. + /// + public static string DisplayAttributeDescription_EgressOptions_Providers { + get { + return ResourceManager.GetString("DisplayAttributeDescription_EgressOptions_Providers", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The type of provider. Currently this supports 'fileSystem' and 'azureBlobStorage'.. + /// + public static string DisplayAttributeDescription_EgressProvider_EgressType { + get { + return ResourceManager.GetString("DisplayAttributeDescription_EgressProvider_EgressType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Name of custom metrics counters.. + /// + public static string DisplayAttributeDescription_MetricProvider_CounterNames { + get { + return ResourceManager.GetString("DisplayAttributeDescription_MetricProvider_CounterNames", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The name of the custom metrics provider.. + /// + public static string DisplayAttributeDescription_MetricProvider_ProviderName { + get { + return ResourceManager.GetString("DisplayAttributeDescription_MetricProvider_ProviderName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enable or disable metrics collection.. + /// + public static string DisplayAttributeDescription_MetricsOptions_Enabled { + get { + return ResourceManager.GetString("DisplayAttributeDescription_MetricsOptions_Enabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Endpoints that expose prometheus metrics. Defaults to http://localhost:52325.. + /// + public static string DisplayAttributeDescription_MetricsOptions_Endpoints { + get { + return ResourceManager.GetString("DisplayAttributeDescription_MetricsOptions_Endpoints", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Include default providers: System.Runtime, Microsoft.AspNetCore.Hosting, and Grpc.AspNetCore.Server.. + /// + public static string DisplayAttributeDescription_MetricsOptions_IncludeDefaultProviders { + get { + return ResourceManager.GetString("DisplayAttributeDescription_MetricsOptions_IncludeDefaultProviders", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Amount of data points to store per metric.. + /// + public static string DisplayAttributeDescription_MetricsOptions_MetricCount { + get { + return ResourceManager.GetString("DisplayAttributeDescription_MetricsOptions_MetricCount", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Providers for custom metrics.. + /// + public static string DisplayAttributeDescription_MetricsOptions_Providers { + get { + return ResourceManager.GetString("DisplayAttributeDescription_MetricsOptions_Providers", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to How often metrics are collected.. + /// + public static string DisplayAttributeDescription_MetricsOptions_UpdateIntervalSeconds { + get { + return ResourceManager.GetString("DisplayAttributeDescription_MetricsOptions_UpdateIntervalSeconds", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The criteria used to compare against the target process.. + /// + public static string DisplayAttributeDescription_ProcessFilterDescriptor_Key { + get { + return ResourceManager.GetString("DisplayAttributeDescription_ProcessFilterDescriptor_Key", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Type of match to use against the process criteria.. + /// + public static string DisplayAttributeDescription_ProcessFilterDescriptor_MatchType { + get { + return ResourceManager.GetString("DisplayAttributeDescription_ProcessFilterDescriptor_MatchType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The value of the criteria used to compare against the target process.. + /// + public static string DisplayAttributeDescription_ProcessFilterDescriptor_Value { + get { + return ResourceManager.GetString("DisplayAttributeDescription_ProcessFilterDescriptor_Value", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Performs a match based on the contents of the command passed to launch the process on the system; this typically includes the executable path and arguments to the process.. + /// + public static string DisplayAttributeDescription_ProcessFilterKey_CommandLine { + get { + return ResourceManager.GetString("DisplayAttributeDescription_ProcessFilterKey_CommandLine", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Performs a match based on the numerical ID of a process on the system.. + /// + public static string DisplayAttributeDescription_ProcessFilterKey_ProcessId { + get { + return ResourceManager.GetString("DisplayAttributeDescription_ProcessFilterKey_ProcessId", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Performs a match based on the name of a process on the system.. + /// + public static string DisplayAttributeDescription_ProcessFilterKey_ProcessName { + get { + return ResourceManager.GetString("DisplayAttributeDescription_ProcessFilterKey_ProcessName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Process filters used to determine which process to use if one is not explicitly specified. All filters must match.. + /// + public static string DisplayAttributeDescription_ProcessFilterOptions_Filters { + get { + return ResourceManager.GetString("DisplayAttributeDescription_ProcessFilterOptions_Filters", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Performs a case-insensitive substring search.. + /// + public static string DisplayAttributeDescription_ProcessFilterType_Contains { + get { + return ResourceManager.GetString("DisplayAttributeDescription_ProcessFilterType_Contains", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Performs a case-insensitive string comparison.. + /// + public static string DisplayAttributeDescription_ProcessFilterType_Exact { + get { + return ResourceManager.GetString("DisplayAttributeDescription_ProcessFilterType_Exact", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The location for temporary dump files. Defaults to the temp folder.. + /// + public static string DisplayAttributeDescription_StorageOptions_DumpTempFolder { + get { + return ResourceManager.GetString("DisplayAttributeDescription_StorageOptions_DumpTempFolder", resourceCulture); + } + } + } +} diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/OptionsDisplayStrings.resx b/src/Microsoft.Diagnostics.Monitoring.WebApi/OptionsDisplayStrings.resx new file mode 100644 index 00000000000..5fe0b2fac17 --- /dev/null +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/OptionsDisplayStrings.resx @@ -0,0 +1,236 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + API key in hashed form. Each byte should be two hexadecimal-based digits. + The description provided for the ApiKeyHash parameter on ApiAuthenticationOptions. + + + Hash algorithm used to compute ApiKeyHash, typically 'SHA256'. 'SHA1' and 'MD5' are not allowed. + The description provided for the ApiKeyHashType parameter on ApiAuthenticationOptions. + + + List of allowed CORS origins, separated by semicolons. + The description provided for the AllowedOrigins parameter on CorsConfiguration. + + + Launches in mode where dotnet-monitor will connect to a separate running dotnet process. + The description provided for enum DiagnosticPortConnectionMode's Connect value. + + + Launches in mode where dotnet-monitor will listen for connections from a separate running dotnet process. This configuration options requires environment variables be set on the target process. + The description provided for enum DiagnosticPortConnectionMode's Listen value. + + + In 'Connect' mode, dotnet-monitor connects to the application for diagnostics. In 'Listen' mode, the application connects to dotnet-monitor via EndpointName. + The description provided for the ConnectionMode parameter on DiagnosticPortOptions. + + + In 'Listen' mode, specifies the name of the named pipe or unix domain socket to use for connecting to the diagnostic server. + The description provided for the EndpointName parameter on DiagnosticPortOptions. + + + In 'Listen' mode, the maximum amount of connections to accept. + The description provided for the MaxConnections parameter on DiagnosticPortOptions. + + + Additional properties, such as secrets, that can be referenced by the provider definitions. + The description provided for the Properties parameter on EgressOptions. + + + Named providers for egress. The names can be referenced when requesting artifacts, such as dumps or traces. + The description provided for the Providers parameter on EgressOptions. + + + The type of provider. Currently this supports 'fileSystem' and 'azureBlobStorage'. + The description provided for the EgressType parameter on EgressProvider. + + + Name of custom metrics counters. + The description provided for the CounterNames parameter on MetricProvider. + + + The name of the custom metrics provider. + The description provided for the ProviderName parameter on MetricProvider. + + + Enable or disable metrics collection. + The description provided for the Enabled parameter on MetricsOptions. + + + Endpoints that expose prometheus metrics. Defaults to http://localhost:52325. + The description provided for the Endpoints parameter on MetricsOptions. + + + Include default providers: System.Runtime, Microsoft.AspNetCore.Hosting, and Grpc.AspNetCore.Server. + The description provided for the IncludeDefaultProviders parameter on MetricsOptions. + + + Amount of data points to store per metric. + The description provided for the MetricCount parameter on MetricsOptions. + + + Providers for custom metrics. + The description provided for the Providers parameter on MetricsOptions. + + + How often metrics are collected. + The description provided for the UpdateIntervalSeconds parameter on MetricsOptions. + + + The criteria used to compare against the target process. + The description provided for the Key parameter on ProcessFilterDescriptor. + + + Type of match to use against the process criteria. + The description provided for the MatchType parameter on ProcessFilterDescriptor. + + + The value of the criteria used to compare against the target process. + The description provided for the Value parameter on ProcessFilterDescriptor. + + + Performs a match based on the contents of the command passed to launch the process on the system; this typically includes the executable path and arguments to the process. + The description provided for enum ProcessFilterKey's CommandLine value. + + + Performs a match based on the numerical ID of a process on the system. + The description provided for enum ProcessFilterKey's ProcessId value. + + + Performs a match based on the name of a process on the system. + The description provided for enum ProcessFilterKey's ProcessName value. + + + Process filters used to determine which process to use if one is not explicitly specified. All filters must match. + The description provided for the Filters parameter on ProcessFilterOptions. + + + Performs a case-insensitive substring search. + The description provided for enum ProcessFilterType's Contains value. + + + Performs a case-insensitive string comparison. + The description provided for enum ProcessFilterType's Exact value. + + + The location for temporary dump files. Defaults to the temp folder. + The description provided for the DumpTempFolder parameter on StorageOptions. + + \ No newline at end of file diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/ProcessFilterOptions.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/ProcessFilterOptions.cs index 248e15f4d7e..fa1be9391cc 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/ProcessFilterOptions.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/ProcessFilterOptions.cs @@ -2,15 +2,14 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; using System.Collections.Generic; using System.ComponentModel; using System.ComponentModel.DataAnnotations; -using System.Linq; using System.Text.Json.Serialization; -using System.Threading.Tasks; #if UNITTEST +using Microsoft.Diagnostics.Monitoring.WebApi; + namespace Microsoft.Diagnostics.Monitoring.UnitTests.Options #else namespace Microsoft.Diagnostics.Monitoring.WebApi @@ -19,38 +18,59 @@ namespace Microsoft.Diagnostics.Monitoring.WebApi [JsonConverter(typeof(JsonStringEnumConverter))] public enum ProcessFilterKey { + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_ProcessFilterKey_ProcessId))] ProcessId, + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_ProcessFilterKey_ProcessName))] ProcessName, + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_ProcessFilterKey_CommandLine))] CommandLine, } [JsonConverter(typeof(JsonStringEnumConverter))] public enum ProcessFilterType { - [Display(Description = "Performs a case-insensitive string comparison.")] + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_ProcessFilterType_Exact))] Exact, - [Display(Description = "Performs a case-insensitive substring search.")] + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_ProcessFilterType_Contains))] Contains, } public sealed class ProcessFilterOptions { - [Display(Description = "Process filters used to determine which process to use if one is not explicitly specified. All filters must match.")] + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_ProcessFilterOptions_Filters))] public List Filters { get; set; } = new List(0); } public sealed class ProcessFilterDescriptor { - [Display(Description = "The criteria used to compare against the target process.")] + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_ProcessFilterDescriptor_Key))] [Required] public ProcessFilterKey Key { get;set; } - [Display(Description = "The value of the criteria used to compare against the target process.")] + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_ProcessFilterDescriptor_Value))] [Required] public string Value { get; set; } - [Display(Description = "Type of match to use against the process criteria.")] + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_ProcessFilterDescriptor_MatchType))] [DefaultValue(ProcessFilterType.Exact)] public ProcessFilterType MatchType { get; set; } = ProcessFilterType.Exact; } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/StorageOptions.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/StorageOptions.cs index 574cb5b7fc1..dd31db177ae 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/StorageOptions.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/StorageOptions.cs @@ -2,13 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System; -using System.Collections.Generic; using System.ComponentModel.DataAnnotations; -using System.Linq; -using System.Threading.Tasks; #if UNITTEST +using Microsoft.Diagnostics.Monitoring.WebApi; + namespace Microsoft.Diagnostics.Monitoring.UnitTests.Options #else namespace Microsoft.Diagnostics.Monitoring.WebApi @@ -16,7 +14,9 @@ namespace Microsoft.Diagnostics.Monitoring.WebApi { internal class StorageOptions { - [Display(Description = "The location for temporary dump files. Defaults to the temp folder.")] + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_StorageOptions_DumpTempFolder))] public string DumpTempFolder {get; set; } } } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Strings.Designer.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Strings.Designer.cs new file mode 100644 index 00000000000..d3a73e00c0b --- /dev/null +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Strings.Designer.cs @@ -0,0 +1,225 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Microsoft.Diagnostics.Monitoring.WebApi { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Strings { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Strings() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.Diagnostics.Monitoring.WebApi.Strings", typeof(Strings).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Unable to get process environment.. + /// + internal static string ErrorMessage_CanNotGetEnvironment { + get { + return ResourceManager.GetString("ErrorMessage_CanNotGetEnvironment", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid metric count.. + /// + internal static string ErrorMessage_InvalidMetricCount { + get { + return ResourceManager.GetString("ErrorMessage_InvalidMetricCount", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Metrics was not enabled.. + /// + internal static string ErrorMessage_MetricsDisabled { + get { + return ResourceManager.GetString("ErrorMessage_MetricsDisabled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to select a single target process because multiple target processes have been discovered.. + /// + internal static string ErrorMessage_MultipleTargetProcesses { + get { + return ResourceManager.GetString("ErrorMessage_MultipleTargetProcesses", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No default process configuration has been set.. + /// + internal static string ErrorMessage_NoDefaultProcessConfig { + get { + return ResourceManager.GetString("ErrorMessage_NoDefaultProcessConfig", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to discover a target process.. + /// + internal static string ErrorMessage_NoTargetProcess { + get { + return ResourceManager.GetString("ErrorMessage_NoTargetProcess", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to enumerate processes.. + /// + internal static string ErrorMessage_ProcessEnumeratuinFailed { + get { + return ResourceManager.GetString("ErrorMessage_ProcessEnumeratuinFailed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unexpected {0}: {1}. + /// + internal static string ErrorMessage_UnexpectedType { + get { + return ResourceManager.GetString("ErrorMessage_UnexpectedType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Value cannot be null, empty, or whitespace.. + /// + internal static string ErrorMessage_ValueEmptyNullWhitespace { + get { + return ResourceManager.GetString("ErrorMessage_ValueEmptyNullWhitespace", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The value '{0}' is not a valid hexadecimal number.. + /// + internal static string ErrorMessage_ValueNotHex { + get { + return ResourceManager.GetString("ErrorMessage_ValueNotHex", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The value '{0}' is not a valid integer.. + /// + internal static string ErrorMessage_ValueNotInt { + get { + return ResourceManager.GetString("ErrorMessage_ValueNotInt", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Value must be of type string.. + /// + internal static string ErrorMessage_ValueNotString { + get { + return ResourceManager.GetString("ErrorMessage_ValueNotString", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Egressed artifact to {location}. + /// + internal static string LogFormatString_EgressedArtifact { + get { + return ResourceManager.GetString("LogFormatString_EgressedArtifact", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Request canceled.. + /// + internal static string LogFormatString_RequestCanceled { + get { + return ResourceManager.GetString("LogFormatString_RequestCanceled", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Request failed.. + /// + internal static string LogFormatString_RequestFailed { + get { + return ResourceManager.GetString("LogFormatString_RequestFailed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Resolved target process.. + /// + internal static string LogFormatString_ResolvedTargetProcess { + get { + return ResourceManager.GetString("LogFormatString_ResolvedTargetProcess", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Request limit for endpoint reached. Limit: {limit}, oustanding requests: {requests}. + /// + internal static string LogFormatString_ThrottledEndpoint { + get { + return ResourceManager.GetString("LogFormatString_ThrottledEndpoint", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Written to HTTP stream.. + /// + internal static string LogFormatString_WrittenToHttpStream { + get { + return ResourceManager.GetString("LogFormatString_WrittenToHttpStream", resourceCulture); + } + } + } +} diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Strings.resx b/src/Microsoft.Diagnostics.Monitoring.WebApi/Strings.resx new file mode 100644 index 00000000000..e2e73a1afd1 --- /dev/null +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Strings.resx @@ -0,0 +1,208 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Unable to get process environment. + Gets a string similar to "Unable to get process environment.". + + + Invalid metric count. + Gets a string similar to "Invalid metric count.". + + + Metrics was not enabled. + Gets a string similar to "Metrics was not enabled.". + + + Unable to select a single target process because multiple target processes have been discovered. + Gets a string similar to "Unable to select a single target process because multiple target processes have been discovered.". + + + No default process configuration has been set. + Gets a string similar to "No default process configuration has been set.". + + + Unable to discover a target process. + Gets a string similar to "Unable to discover a target process.". + + + Unable to enumerate processes. + Gets a string similar to "Unable to enumerate processes.". + + + Unexpected {0}: {1} + Gets the format string for unexpected type provided. +2 Format Parameters: +0. typeName: Name of the type that has the unexpected value +1. value: The value that was unexpected + + + Value cannot be null, empty, or whitespace. + Gets a string similar to "Value cannot be null, empty, or whitespace.". + + + The value '{0}' is not a valid hexadecimal number. + Gets the format string for the error message when a value could not be parsed as hex. +1 Format Parameter: +1. value: The value that could not be parsed + + + The value '{0}' is not a valid integer. + Gets the format string for the error message when a value could not be parsed into an integer. +1 Format Parameter: +1. value: The value that could not be parsed + + + Value must be of type string. + Gets a string similar to "Value must be of type string.". + + + Egressed artifact to {location} + Gets the format string that is printed in the 4:EgressedArtifact event. +1 Format Parameter: +1. location: The location that the artifact was egressed to + + + Request canceled. + Gets the format string that is printed in the 2:RequestCanceled event. +0 Format Parameters + + + Request failed. + Gets the format string that is printed in the 1:RequestFailed event. +0 Format Parameters + + + Resolved target process. + Gets the format string that is printed in the 3:ResolvedTargetProcess event. +0 Format Parameters + + + Request limit for endpoint reached. Limit: {limit}, oustanding requests: {requests} + Gets the format string that is printed in the 6:ThrottledEndpoint event. +2 Format Parameters: +1. limit: The numerical limit that was reached +2. requests: The number of outstanding requests + + + Written to HTTP stream. + Gets the format string that is printed in the 5:WrittenToHttpStream event. +0 Format Parameters + + \ No newline at end of file diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Validation/IntegerOrHexStringAttribute.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Validation/IntegerOrHexStringAttribute.cs index 891f409504a..9c8413572a6 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Validation/IntegerOrHexStringAttribute.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Validation/IntegerOrHexStringAttribute.cs @@ -14,7 +14,7 @@ protected override ValidationResult IsValid(object value, ValidationContext vali { if (!(value is string stringValue)) { - return new ValidationResult("Value must be of type string."); + return new ValidationResult(Strings.ErrorMessage_ValueNotString); } else if (!TryParse(stringValue, out _, out string error)) { @@ -30,7 +30,7 @@ public static bool TryParse(string value, out long result, out string error) if (string.IsNullOrWhiteSpace(value)) { - error = "Value cannot be null, empty, or whitespace."; + error = Strings.ErrorMessage_ValueEmptyNullWhitespace; return false; } else if (value.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) @@ -39,7 +39,7 @@ public static bool TryParse(string value, out long result, out string error) // It parses the actual value, not the "0x" syntax prefix. if (!long.TryParse(value.Substring(2), NumberStyles.AllowHexSpecifier, CultureInfo.InvariantCulture, out result)) { - error = FormattableString.Invariant($"The value '{value}' is not a valid hexadecimal number."); + error = string.Format(CultureInfo.InvariantCulture, Strings.ErrorMessage_ValueNotHex, value); return false; } } @@ -47,7 +47,7 @@ public static bool TryParse(string value, out long result, out string error) { if (!long.TryParse(value, NumberStyles.AllowLeadingSign, CultureInfo.InvariantCulture, out result)) { - error = FormattableString.Invariant($"The value '{value}' is not a valid integer."); + error = string.Format(CultureInfo.InvariantCulture, Strings.ErrorMessage_ValueNotInt, value); return false; } } diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.ConfigurationSchema.UnitTests/Microsoft.Diagnostics.Monitoring.ConfigurationSchema.UnitTests.csproj b/src/Tests/Microsoft.Diagnostics.Monitoring.ConfigurationSchema.UnitTests/Microsoft.Diagnostics.Monitoring.ConfigurationSchema.UnitTests.csproj index 92efee5663f..9d8af698f3c 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.ConfigurationSchema.UnitTests/Microsoft.Diagnostics.Monitoring.ConfigurationSchema.UnitTests.csproj +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.ConfigurationSchema.UnitTests/Microsoft.Diagnostics.Monitoring.ConfigurationSchema.UnitTests.csproj @@ -16,4 +16,5 @@ + diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj index 98981fa8535..4c549cb6a52 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj @@ -29,6 +29,7 @@ + false diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Options/EgressOptions.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Options/EgressOptions.cs index bb847c7e629..37a6780d059 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Options/EgressOptions.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Options/EgressOptions.cs @@ -2,29 +2,34 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using Microsoft.Diagnostics.Monitoring.WebApi; using System; using System.Collections.Generic; -using System.ComponentModel; using System.ComponentModel.DataAnnotations; -using System.Runtime.Serialization; using System.Text.Json.Serialization; namespace Microsoft.Diagnostics.Monitoring.UnitTests.Options { internal class EgressOptions { - [Display(Description = "Named providers for egress. The names can be referenced when requesting artifacts, such as dumps or traces.")] + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_EgressOptions_Providers))] public Dictionary Providers { get; set; } = new(StringComparer.OrdinalIgnoreCase); - [Display(Description = "Additional properties, such as secrets, that can be referenced by the provider definitions.")] + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_EgressOptions_Properties))] public Dictionary Properties { get; set; } = new(StringComparer.OrdinalIgnoreCase); } internal class EgressProvider { - [Display(Description = "The type of provider. Currently this supports 'fileSystem' and 'azureBlobStorage'.")] + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_EgressProvider_EgressType))] //TODO This should honor DataMember, but only seems to work with JsonProperty [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)] public string EgressType { get; set; } diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Microsoft.Diagnostics.Monitoring.UnitTests.csproj b/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Microsoft.Diagnostics.Monitoring.UnitTests.csproj index 4f865643f4b..211687c010c 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Microsoft.Diagnostics.Monitoring.UnitTests.csproj +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/Microsoft.Diagnostics.Monitoring.UnitTests.csproj @@ -1,14 +1,15 @@  - net6.0 + netcoreapp3.1;net6.0 $(DefineConstants);UNITTEST - + + diff --git a/src/Tools/dotnet-monitor/Auth/ApiAuthenticationOptions.cs b/src/Tools/dotnet-monitor/Auth/ApiAuthenticationOptions.cs index 1125025d95c..08920fb9e3f 100644 --- a/src/Tools/dotnet-monitor/Auth/ApiAuthenticationOptions.cs +++ b/src/Tools/dotnet-monitor/Auth/ApiAuthenticationOptions.cs @@ -2,7 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using System.ComponentModel; +using Microsoft.Diagnostics.Monitoring.WebApi; using System.ComponentModel.DataAnnotations; #if UNITTEST @@ -13,13 +13,17 @@ namespace Microsoft.Diagnostics.Tools.Monitor { internal sealed class ApiAuthenticationOptions { - [Display(Description = "API key in hashed form. Each byte should be two hexadecimal-based digits.")] + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_ApiAuthenticationOptions_ApiKeyHash))] [RegularExpression("[0-9a-fA-F]+")] [MinLength(64)] [Required] public string ApiKeyHash { get; set; } - [Display(Description = "Hash algorithm used to compute ApiKeyHash, typically 'SHA256'. 'SHA1' and 'MD5' are not allowed.")] + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_ApiAuthenticationOptions_ApiKeyHashType))] [Required] public string ApiKeyHashType { get; set; } } diff --git a/src/Tools/dotnet-monitor/Auth/ApiKeyAuthenticationHandler.cs b/src/Tools/dotnet-monitor/Auth/ApiKeyAuthenticationHandler.cs index c33094bb8f6..1c70122a28b 100644 --- a/src/Tools/dotnet-monitor/Auth/ApiKeyAuthenticationHandler.cs +++ b/src/Tools/dotnet-monitor/Auth/ApiKeyAuthenticationHandler.cs @@ -46,7 +46,7 @@ protected override Task HandleAuthenticateAsync() { Logger.ApiKeyValidationFailures(options.ValidationErrors); - return Task.FromResult(AuthenticateResult.Fail("API key authentication not configured.")); + return Task.FromResult(AuthenticateResult.Fail(Strings.ErrorMessage_ApiKeyNotConfigured)); } //We are expecting a header such as Authorization: @@ -59,7 +59,7 @@ protected override Task HandleAuthenticateAsync() if (!AuthenticationHeaderValue.TryParse(values.First(), out AuthenticationHeaderValue authHeader)) { - return Task.FromResult(AuthenticateResult.Fail("Invalid authentication header.")); + return Task.FromResult(AuthenticateResult.Fail(Strings.ErrorMessage_InvalidAuthHeader)); } if (!string.Equals(authHeader.Scheme, Scheme.Name, StringComparison.OrdinalIgnoreCase)) @@ -69,12 +69,12 @@ protected override Task HandleAuthenticateAsync() if (authHeader.Parameter == null) { - return Task.FromResult(AuthenticateResult.Fail("Invalid API key format.")); + return Task.FromResult(AuthenticateResult.Fail(Strings.ErrorMessage_InvalidApiKeyFormat)); } if (authHeader.Parameter.Length > ApiKeyBase64MaxLength) { - return Task.FromResult(AuthenticateResult.Fail("Invalid API key format.")); + return Task.FromResult(AuthenticateResult.Fail(Strings.ErrorMessage_InvalidApiKeyFormat)); } // Calculate the max length of the base64 encoded value, @@ -84,7 +84,7 @@ protected override Task HandleAuthenticateAsync() if (byteLen < ApiKeyByteMinLength) { - return Task.FromResult(AuthenticateResult.Fail("Invalid API key format.")); + return Task.FromResult(AuthenticateResult.Fail(Strings.ErrorMessage_InvalidApiKeyFormat)); } // The user is passing a base 64-encoded version of the secret @@ -93,7 +93,7 @@ protected override Task HandleAuthenticateAsync() Span span = new Span(buffer); if (!Convert.TryFromBase64String(authHeader.Parameter, span, out int bytesWritten) || bytesWritten < ApiKeyByteMinLength || bytesWritten > ApiKeyByteMaxLength) { - return Task.FromResult(AuthenticateResult.Fail("Invalid API key format.")); + return Task.FromResult(AuthenticateResult.Fail(Strings.ErrorMessage_InvalidApiKeyFormat)); } Debug.Assert(null != options.HashAlgorithm); @@ -112,7 +112,7 @@ protected override Task HandleAuthenticateAsync() } else { - return Task.FromResult(AuthenticateResult.Fail("Invalid API key.")); + return Task.FromResult(AuthenticateResult.Fail(Strings.ErrorMessage_InvalidApiKey)); } } } diff --git a/src/Tools/dotnet-monitor/Auth/ApiKeyAuthenticationPostConfigureOptions.cs b/src/Tools/dotnet-monitor/Auth/ApiKeyAuthenticationPostConfigureOptions.cs index 2d693635e84..682804e28fe 100644 --- a/src/Tools/dotnet-monitor/Auth/ApiKeyAuthenticationPostConfigureOptions.cs +++ b/src/Tools/dotnet-monitor/Auth/ApiKeyAuthenticationPostConfigureOptions.cs @@ -43,14 +43,26 @@ public void PostConfigure(string name, ApiKeyAuthenticationOptions options) { if (!HashAlgorithmChecker.IsAllowedAlgorithm(sourceOptions.ApiKeyHashType)) { - errors.Add(new ValidationResult($"The {nameof(ApiAuthenticationOptions.ApiKeyHashType)} field value '{sourceOptions.ApiKeyHashType}' is not allowed.", new string[] { nameof(ApiAuthenticationOptions.ApiKeyHashType) })); + errors.Add( + new ValidationResult( + string.Format( + Strings.ErrorMessage_FieldNotAllowed, + nameof(ApiAuthenticationOptions.ApiKeyHashType), + sourceOptions.ApiKeyHashType), + new string[] { nameof(ApiAuthenticationOptions.ApiKeyHashType) })); } else { using HashAlgorithm algorithm = HashAlgorithm.Create(sourceOptions.ApiKeyHashType); if (null == algorithm) { - errors.Add(new ValidationResult($"The {nameof(ApiAuthenticationOptions.ApiKeyHashType)} field value '{sourceOptions.ApiKeyHashType}' is not supported.", new string[] { nameof(ApiAuthenticationOptions.ApiKeyHashType) })); + errors.Add( + new ValidationResult( + string.Format( + Strings.ErrorMessage_FieldNotAllowed, + nameof(ApiAuthenticationOptions.ApiKeyHashType), + sourceOptions.ApiKeyHashType), + new string[] { nameof(ApiAuthenticationOptions.ApiKeyHashType) })); } } } @@ -66,6 +78,12 @@ public void PostConfigure(string name, ApiKeyAuthenticationOptions options) { if (!byte.TryParse(sourceOptions.ApiKeyHash.AsSpan(i, 2), NumberStyles.HexNumber, provider: NumberFormatInfo.InvariantInfo, result: out byte resultByte)) { + errors.Add( + new ValidationResult( + string.Format( + Strings.ErrorMessage_FieldNotHex, + nameof(ApiAuthenticationOptions.ApiKeyHash)), + new string[] { nameof(ApiAuthenticationOptions.ApiKeyHash) })); errors.Add(new ValidationResult($"The {nameof(ApiAuthenticationOptions.ApiKeyHash)} field could not be decoded as hex string.", new string[] { nameof(ApiAuthenticationOptions.ApiKeyHash) })); break; } @@ -74,7 +92,12 @@ public void PostConfigure(string name, ApiKeyAuthenticationOptions options) } else { - errors.Add(new ValidationResult($"The {nameof(ApiAuthenticationOptions.ApiKeyHash)} field value length must be an even number.", new string[] { nameof(ApiAuthenticationOptions.ApiKeyHash) })); + errors.Add( + new ValidationResult( + string.Format( + Strings.ErrorMessage_FieldOddLengh, + nameof(ApiAuthenticationOptions.ApiKeyHash)), + new string[] { nameof(ApiAuthenticationOptions.ApiKeyHash) })); } } diff --git a/src/Tools/dotnet-monitor/ConfigurationJsonWriter.cs b/src/Tools/dotnet-monitor/ConfigurationJsonWriter.cs index b2a603da637..d59d211e456 100644 --- a/src/Tools/dotnet-monitor/ConfigurationJsonWriter.cs +++ b/src/Tools/dotnet-monitor/ConfigurationJsonWriter.cs @@ -166,7 +166,7 @@ private IConfigurationSection ProcessChildSection(IConfiguration parentSection, if (!section.Exists()) { _writer.WritePropertyName(key); - _writer.WriteStringValue(":NOT PRESENT:"); + _writer.WriteStringValue(Strings.Placeholder_NotPresent); return null; } @@ -197,7 +197,7 @@ private void ProcessSection(IConfigurationSection section, bool includeChildSect { if (redact) { - _writer.WriteStringValue(":REDACTED:"); + _writer.WriteStringValue(Strings.Placeholder_Redacted); } else { diff --git a/src/Tools/dotnet-monitor/DiagnosticPortOptions.cs b/src/Tools/dotnet-monitor/DiagnosticPortOptions.cs index ebfb545ab8a..0ed00b14987 100644 --- a/src/Tools/dotnet-monitor/DiagnosticPortOptions.cs +++ b/src/Tools/dotnet-monitor/DiagnosticPortOptions.cs @@ -2,9 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using Microsoft.Diagnostics.Monitoring.WebApi; using System.ComponentModel; using System.ComponentModel.DataAnnotations; -using System.Runtime.Serialization; using System.Text.Json.Serialization; #if UNITTEST @@ -15,21 +15,34 @@ namespace Microsoft.Diagnostics.Tools.Monitor { public class DiagnosticPortOptions { - [Display(Description = @"In 'Connect' mode, dotnet-monitor connects to the application for diagnostics. In 'Listen' mode, the application connects to dotnet-monitor via " + nameof(EndpointName) + ".")] + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_DiagnosticPortOptions_ConnectionMode))] [DefaultValue(DiagnosticPortOptionsDefaults.ConnectionMode)] public DiagnosticPortConnectionMode? ConnectionMode { get; set; } - [Display(Description = @"In 'Listen' mode, specifies the name of the named pipe or unix domain socket to use for connecting to the diagnostic server.")] + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_DiagnosticPortOptions_EndpointName))] public string EndpointName { get; set; } - [Display(Description = @"In 'Listen' mode, the maximum amount of connections to accept.")] + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_DiagnosticPortOptions_MaxConnections))] public int? MaxConnections { get; set; } } [JsonConverter(typeof(JsonStringEnumConverter))] public enum DiagnosticPortConnectionMode { + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_DiagnosticPortConnectionMode_Connect))] Connect, + + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_DiagnosticPortConnectionMode_Listen))] Listen } } diff --git a/src/Tools/dotnet-monitor/DiagnosticPortValidateOptions.cs b/src/Tools/dotnet-monitor/DiagnosticPortValidateOptions.cs index 9d436756316..3b702070959 100644 --- a/src/Tools/dotnet-monitor/DiagnosticPortValidateOptions.cs +++ b/src/Tools/dotnet-monitor/DiagnosticPortValidateOptions.cs @@ -14,7 +14,7 @@ public ValidateOptionsResult Validate(string name, DiagnosticPortOptions options if (options.ConnectionMode == DiagnosticPortConnectionMode.Listen && string.IsNullOrEmpty(options.EndpointName)) { - return ValidateOptionsResult.Fail("In 'Listen' mode, the diagnostic port endpoint name must be specified."); + return ValidateOptionsResult.Fail(Strings.ErrorMessage_DiagnosticPortMissingInListenMode); } return ValidateOptionsResult.Success; diff --git a/src/Tools/dotnet-monitor/Egress/AzureBlob/AzureBlobEgressProvider.cs b/src/Tools/dotnet-monitor/Egress/AzureBlob/AzureBlobEgressProvider.cs index f6865a3bb5f..ff1087bf48d 100644 --- a/src/Tools/dotnet-monitor/Egress/AzureBlob/AzureBlobEgressProvider.cs +++ b/src/Tools/dotnet-monitor/Egress/AzureBlob/AzureBlobEgressProvider.cs @@ -9,6 +9,7 @@ using Azure.Storage.Blobs.Specialized; using Microsoft.Extensions.Logging; using System; +using System.Globalization; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -158,7 +159,7 @@ private async Task GetBlobContainerClientAsync(Cancellation } else { - throw CreateException("SharedAccessSignature or AccountKey must be specified."); + throw CreateException(Strings.ErrorMessage_EgressMissingSasOrKey); } BlobContainerClient containerClient = serviceClient.GetBlobContainerClient(Options.ContainerName); @@ -211,11 +212,11 @@ private static string WrapMessage(string innerMessage) { if (!string.IsNullOrEmpty(innerMessage)) { - return $"Azure blob egress failed: {innerMessage}"; + return string.Format(CultureInfo.CurrentCulture, Strings.ErrorMessage_EgressAzureFailedDetailed, innerMessage); } else { - return "Azure blob egress failed."; + return Strings.ErrorMessage_EgressAzureFailedGeneric; } } } diff --git a/src/Tools/dotnet-monitor/Egress/AzureBlob/AzureBlobEgressProviderOptions.cs b/src/Tools/dotnet-monitor/Egress/AzureBlob/AzureBlobEgressProviderOptions.cs index 53f1f26aa7f..f99c19b3da2 100644 --- a/src/Tools/dotnet-monitor/Egress/AzureBlob/AzureBlobEgressProviderOptions.cs +++ b/src/Tools/dotnet-monitor/Egress/AzureBlob/AzureBlobEgressProviderOptions.cs @@ -56,7 +56,12 @@ IEnumerable IValidatableObject.Validate(ValidationContext vali // One of the authentication keys/tokens is required if (string.IsNullOrEmpty(AccountKey) && string.IsNullOrEmpty(SharedAccessSignature)) { - results.Add(new ValidationResult($"The {nameof(AccountKey)} field or the {nameof(SharedAccessSignature)} field is required.")); + results.Add( + new ValidationResult( + string.Format( + Strings.ErrorMessage_TwoFieldsMissing, + nameof(AccountKey), + nameof(SharedAccessSignature)))); } return results; diff --git a/src/Tools/dotnet-monitor/Egress/EgressService.cs b/src/Tools/dotnet-monitor/Egress/EgressService.cs index 62180075bc0..9cd2596e5b4 100644 --- a/src/Tools/dotnet-monitor/Egress/EgressService.cs +++ b/src/Tools/dotnet-monitor/Egress/EgressService.cs @@ -7,6 +7,7 @@ using Microsoft.Diagnostics.Tools.Monitor.Egress.Configuration; using Microsoft.Extensions.Options; using System; +using System.Globalization; using System.IO; using System.Threading; using System.Threading.Tasks; @@ -31,7 +32,7 @@ public Task EgressAsync(string providerName, Func EgressAsync(string providerName, Func action, string fileName, string contentType, IEndpointInfo source, CancellationToken token) @@ -40,7 +41,7 @@ public Task EgressAsync(string providerName, Func portOptions) _source = new ServerEndpointInfoSource(_portOptions.EndpointName); break; default: - throw new InvalidOperationException($"Unhandled connection mode: {connectionMode}"); + throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Strings.ErrorMessage_UnhandledConnectionMode, connectionMode)); } // Filter out the current process based on the connection mode. diff --git a/src/Tools/dotnet-monitor/GenerateApiKeyCommandHandler.cs b/src/Tools/dotnet-monitor/GenerateApiKeyCommandHandler.cs index 9a7ee883ddd..d3a00f97566 100644 --- a/src/Tools/dotnet-monitor/GenerateApiKeyCommandHandler.cs +++ b/src/Tools/dotnet-monitor/GenerateApiKeyCommandHandler.cs @@ -5,6 +5,7 @@ using System; using System.CommandLine; using System.CommandLine.IO; +using System.Globalization; using System.Threading; using System.Threading.Tasks; @@ -21,13 +22,25 @@ public Task GenerateApiKey(CancellationToken token, int keyLength, string h { if (!HashAlgorithmChecker.IsAllowedAlgorithm(hashAlgorithm)) { - console.Error.WriteLine(FormattableString.CurrentCulture($"The {nameof(hashAlgorithm)} parameter value '{hashAlgorithm}' is not allowed.")); + console.Error.WriteLine( + string.Format( + CultureInfo.CurrentCulture, + Strings.ErrorMessage_ParameterNotAllowed, + nameof(hashAlgorithm), + hashAlgorithm)); return Task.FromResult(1); } if (keyLength < ApiKeyAuthenticationHandler.ApiKeyByteMinLength || keyLength > ApiKeyAuthenticationHandler.ApiKeyByteMaxLength) { - console.Error.WriteLine(FormattableString.CurrentCulture($"The {nameof(keyLength)} parameter value '{keyLength}' is not allowed. Must be between {ApiKeyAuthenticationHandler.ApiKeyByteMinLength} and {ApiKeyAuthenticationHandler.ApiKeyByteMaxLength} bytes.")); + console.Error.WriteLine( + string.Format( + CultureInfo.CurrentCulture, + Strings.ErrorMessage_ParameterNotAllowedByteRange, + nameof(hashAlgorithm), + hashAlgorithm, + ApiKeyAuthenticationHandler.ApiKeyByteMinLength, + ApiKeyAuthenticationHandler.ApiKeyByteMaxLength)); return Task.FromResult(1); } diff --git a/src/Tools/dotnet-monitor/LoggingExtensions.cs b/src/Tools/dotnet-monitor/LoggingExtensions.cs index 7f95bbff921..07db455a067 100644 --- a/src/Tools/dotnet-monitor/LoggingExtensions.cs +++ b/src/Tools/dotnet-monitor/LoggingExtensions.cs @@ -17,139 +17,139 @@ internal static class LoggingExtensions LoggerMessage.Define( eventId: new EventId(1, "EgressProviderAdded"), logLevel: LogLevel.Debug, - formatString: "Provider '{providerName}': Added."); + formatString: Strings.LogFormatString_EgressProviderAdded); private static readonly Action _egressProviderInvalidOptions = LoggerMessage.Define( eventId: new EventId(2, "EgressProviderInvalidOptions"), logLevel: LogLevel.Error, - formatString: "Provider '{providerName}': Invalid options."); + formatString: Strings.LogFormatString_EgressProviderInvalidOptions); private static readonly Action _egressProviderInvalidType = LoggerMessage.Define( eventId: new EventId(3, "EgressProviderInvalidType"), logLevel: LogLevel.Error, - formatString: "Provider '{providerName}': Type '{providerType}' is not supported."); + formatString: Strings.LogFormatString_EgressProviderInvalidType); private static readonly Action _egressProviderValidatingOptions = LoggerMessage.Define( eventId: new EventId(4, "EgressProviderValidatingOptions"), logLevel: LogLevel.Debug, - formatString: "Provider '{providerName}': Validating options."); + formatString: Strings.LogFormatString_EgressProviderValidatingOptions); private static readonly Action _egressCopyActionStreamToEgressStream = LoggerMessage.Define( eventId: new EventId(5, "EgressCopyActionStreamToEgressStream"), logLevel: LogLevel.Debug, - formatString: "Copying action stream to egress stream with buffer size {bufferSize}"); + formatString: Strings.LogFormatString_EgressCopyActionStreamToEgressStream); private static readonly Action _egressProviderOptionsValidationWarning = LoggerMessage.Define( eventId: new EventId(6, "EgressProviderOptionsValidationWarning"), logLevel: LogLevel.Warning, - formatString: "Provider '{providerName}': {validationWarning}"); + formatString: Strings.LogFormatString_EgressProviderOptionsValidationWarning); private static readonly Action _egressProviderOptionValue = LoggerMessage.Define( eventId: new EventId(7, "EgressProviderOptionValue"), logLevel: LogLevel.Debug, - formatString: "Provider {providerType}: Provider option {optionName} = {optionValue}"); + formatString: Strings.LogFormatString_EgressProviderOptionValue); private static readonly Action _egressStreamOptionValue = LoggerMessage.Define( eventId: new EventId(8, "EgressStreamOptionValue"), logLevel: LogLevel.Debug, - formatString: "Provider {providerType}: Stream option {optionName} = {optionValue}"); + formatString: Strings.LogFormatString_EgressStreamOptionValue); private static readonly Action _egressProviderFileName = LoggerMessage.Define( eventId: new EventId(9, "EgressProviderFileName"), logLevel: LogLevel.Debug, - formatString: "Provider {providerType}: File name = {fileName}"); + formatString: Strings.LogFormatString_EgressProviderFileName); private static readonly Action _egressProviderUnableToFindPropertyKey = LoggerMessage.Define( eventId: new EventId(10, "EgressProvideUnableToFindPropertyKey"), logLevel: LogLevel.Warning, - formatString: "Provider {providerType}: Unable to find '{keyName}' key in egress properties"); + formatString: Strings.LogFormatString_EgressProvideUnableToFindPropertyKey); private static readonly Action _egressProviderInvokeStreamAction = LoggerMessage.Define( eventId: new EventId(11, "EgressProviderInvokeStreamAction"), logLevel: LogLevel.Debug, - formatString: "Provider {providerType}: Invoking stream action."); + formatString: Strings.LogFormatString_EgressProviderInvokeStreamAction); private static readonly Action _egressProviderSavedStream = LoggerMessage.Define( eventId: new EventId(12, "EgressProviderSavedStream"), logLevel: LogLevel.Debug, - formatString: "Provider {providerType}: Saved stream to {path}"); + formatString: Strings.LogFormatString_EgressProviderSavedStream); private static readonly Action _noAuthentication = LoggerMessage.Define( eventId: new EventId(13, "NoAuthentication"), logLevel: LogLevel.Warning, - formatString: "WARNING: Authentication has been disabled. This can pose a security risk and is not intended for production environments."); + formatString: Strings.LogFormatString_NoAuthentication); private static readonly Action _insecureAuthenticationConfiguration = LoggerMessage.Define( eventId: new EventId(14, "InsecureAutheticationConfiguration"), logLevel: LogLevel.Warning, - formatString: "WARNING: Authentication is enabled over insecure http transport. This can pose a security risk and is not intended for production environments."); + formatString: Strings.LogFormatString_InsecureAutheticationConfiguration); private static readonly Action _unableToListenToAddress = LoggerMessage.Define( eventId: new EventId(15, "UnableToListenToAddress"), logLevel: LogLevel.Error, - formatString: "Unable to listen to {url}. Dotnet-monitor functionality will be limited."); + formatString: Strings.LogFormatString_UnableToListenToAddress); private static readonly Action _boundDefaultAddress = LoggerMessage.Define( eventId: new EventId(16, "BoundDefaultAddress"), logLevel: LogLevel.Debug, - formatString: "Bound default address: {address}"); + formatString: Strings.LogFormatString_BoundDefaultAddress); private static readonly Action _boundMetricsAddress = LoggerMessage.Define( eventId: new EventId(17, "BoundMetricsAddress"), logLevel: LogLevel.Debug, - formatString: "Bound metrics address: {address}"); + formatString: Strings.LogFormatString_BoundMetricsAddress); private static readonly Action _optionsValidationFalure = LoggerMessage.Define( eventId: new EventId(18, "OptionsValidationFailure"), logLevel: LogLevel.Critical, - formatString: "{failure}"); + formatString: Strings.LogFormatString_OptionsValidationFailure); private static readonly Action _runningElevated = LoggerMessage.Define( eventId: new EventId(19, "RunningElevated"), logLevel: LogLevel.Warning, - formatString: "The process was launched elevated and will have access to all processes on the system. Do not run elevated unless you need to monitor processes launched by another user (e.g., IIS worker processes)"); + formatString: Strings.LogFormatString_RunningElevated); private static readonly Action _disabledNegotiateWhileElevated = LoggerMessage.Define( eventId: new EventId(20, "DisabledNegotiateWhileElevated"), logLevel: LogLevel.Warning, - formatString: "Negotiate, Kerberos, and NTLM authentication are not enabled when running with elevated permissions."); + formatString: Strings.LogFormatString_DisabledNegotiateWhileElevated); - private static readonly Action _apiKeyValidationFailure = - LoggerMessage.Define( + private static readonly Action _apiKeyValidationFailure = + LoggerMessage.Define( eventId: new EventId(21, "ApiKeyValidationFailure"), logLevel: LogLevel.Warning, - formatString: nameof(ConfigurationKeys.ApiAuthentication) + " settings are invalid: {validationFailure}"); + formatString: Strings.LogFormatString_ApiKeyValidationFailure); - private static readonly Action _apiKeyAuthenticationOptionsChanged = - LoggerMessage.Define( + private static readonly Action _apiKeyAuthenticationOptionsChanged = + LoggerMessage.Define( eventId: new EventId(22, "ApiKeyAuthenticationOptionsChanged"), logLevel: LogLevel.Information, - formatString: nameof(ConfigurationKeys.ApiAuthentication) + " settings have changed."); + formatString: Strings.LogFormatString_ApiKeyAuthenticationOptionsChanged); private static readonly Action _logTempKey = LoggerMessage.Define( eventId: new EventId(23, "LogTempApiKey"), logLevel: LogLevel.Warning, - formatString: "Generated one-time-use ApiKey for dotnet-monitor; use the following header for authorization:{NewLine}{AuthHeaderName}: {AuthScheme} {MonitorApiKey}"); + formatString: Strings.LogFormatString_LogTempApiKey); public static void EgressProviderAdded(this ILogger logger, string providerName) { @@ -271,13 +271,13 @@ public static void ApiKeyValidationFailures(this ILogger logger, IEnumerable new Command( name: "generatekey", - description: "Generate api key and hash for authentication") + description: Strings.HelpDescription_CommandGenerateKey) { CommandHandler.Create(new GenerateApiKeyCommandHandler().GenerateApiKey), HashAlgorithm(), KeyLength() }; private static Command CollectCommand() => - new Command( - name: "collect", - description: "Monitor logs and metrics in a .NET application send the results to a chosen destination.") - { + new Command( + name: "collect", + description: Strings.HelpDescription_CommandCollect) + { // Handler - CommandHandler.Create(Delegate.CreateDelegate(typeof(Func>), - new DiagnosticsMonitorCommandHandler(), nameof(DiagnosticsMonitorCommandHandler.Start))), + CommandHandler.Create( + Delegate.CreateDelegate( + typeof(Func>), + new DiagnosticsMonitorCommandHandler(), + nameof(DiagnosticsMonitorCommandHandler.Start))), SharedOptions() - }; + }; private static Command ConfigCommand() => - new Command( - name: "config", - description: "Configuration related commands for dotnet-monitor.") - { + new Command( + name: "config", + description: Strings.HelpDescription_CommandConfig) + { new Command( - name: "show", - description: "Shows configuration, as if dotnet-monitor collect was executed with these parameters.") + name: "show", + description: Strings.HelpDescription_CommandShow) { - // Handler - CommandHandler.Create(Delegate.CreateDelegate(typeof(Func>), - new DiagnosticsMonitorCommandHandler(), nameof(DiagnosticsMonitorCommandHandler.ShowConfig))), - SharedOptions(), ConfigLevel() + // Handler + CommandHandler.Create( + Delegate.CreateDelegate( + typeof(Func>), + new DiagnosticsMonitorCommandHandler(), + nameof(DiagnosticsMonitorCommandHandler.ShowConfig))), + SharedOptions(), + ConfigLevel() } }; @@ -62,7 +69,7 @@ private static Command ConfigCommand() => private static Option Urls() => new Option( aliases: new[] { "-u", "--urls" }, - description: "Bindings for the REST api.") + description: Strings.HelpDescription_OptionUrls) { Argument = new Argument(name: "urls", getDefaultValue: () => new[] { "https://localhost:52323" }) }; @@ -70,7 +77,7 @@ private static Option Urls() => private static Option MetricUrls() => new Option( aliases: new[] { "--metricUrls" }, - description: "Bindings for metrics") + description: Strings.HelpDescription_OptionMetricsUrls) { Argument = new Argument(name: "metricUrls", getDefaultValue: () => new[] { GetDefaultMetricsEndpoint() }) }; @@ -78,7 +85,7 @@ private static Option MetricUrls() => private static Option ProvideMetrics() => new Option( aliases: new[] { "-m", "--metrics" }, - description: "Enable publishing of metrics") + description: Strings.HelpDescription_OptionMetrics) { Argument = new Argument(name: "metrics", getDefaultValue: () => true) }; @@ -86,7 +93,7 @@ private static Option ProvideMetrics() => private static Option DiagnosticPort() => new Option( alias: "--diagnostic-port", - description: "The fully qualified path and filename of the diagnostic port to which runtime instances can connect.") + description: Strings.HelpDescription_OptionDiagnosticPort) { Argument = new Argument(name: "diagnosticPort") }; @@ -94,7 +101,7 @@ private static Option DiagnosticPort() => private static Option NoAuth() => new Option( alias: "--no-auth", - description: "Turn off authentication." + description: Strings.HelpDescription_OptionNoAuth ) { Argument = new Argument(name: "noAuth", getDefaultValue: () => false) @@ -103,7 +110,7 @@ private static Option NoAuth() => private static Option TempApiKey() => new Option( alias: "--temp-apikey", - description: "Generates a new MonitorApiKey for each launch of the process." + description: Strings.HelpDescription_OptionTempApiKey ) { Argument = new Argument(name: "tempApiKey", getDefaultValue: () => false) @@ -112,7 +119,7 @@ private static Option TempApiKey() => private static Option HashAlgorithm() => new Option( aliases: new[] { "-h", "--hash-algorithm" }, - description: "The string representing the hash algorithm used to compute ApiKeyHash store in configuration") + description: Strings.HelpDescription_HashAlgorithm) { Argument = new Argument(name: "hashAlgorithm", getDefaultValue: () => GeneratedApiKey.DefaultHashAlgorithm) }; @@ -120,7 +127,7 @@ private static Option HashAlgorithm() => private static Option KeyLength() => new Option( aliases: new[] { "-l", "--key-length" }, - description: "The length of the MonitorApiKey in bytes. ") + description: Strings.HelpDescription_KeyLength) { Argument = new Argument(name: "keyLength", getDefaultValue: () => GeneratedApiKey.DefaultKeyLength) }; @@ -128,7 +135,7 @@ private static Option KeyLength() => private static Option ConfigLevel() => new Option( alias: "--level", - description: "Configuration level. Unredacted configuration can show sensitive information.") + description: Strings.HelpDescription_OptionLevel) { Argument = new Argument(name: "level", getDefaultValue: () => ConfigDisplayLevel.Redacted) }; diff --git a/src/Tools/dotnet-monitor/Startup.cs b/src/Tools/dotnet-monitor/Startup.cs index 19378655b9c..a2264d5677d 100644 --- a/src/Tools/dotnet-monitor/Startup.cs +++ b/src/Tools/dotnet-monitor/Startup.cs @@ -118,7 +118,7 @@ public void Configure( if (!listenResults.AnyAddresses) { // This is logged by GenericWebHostServer.StartAsync - throw new MonitoringException("Unable to bind any urls."); + throw new MonitoringException(Strings.ErrorMessage_UnableToBindUrls); } lifetime.ApplicationStarted.Register(() => LogBoundAddresses(app.ServerFeatures, listenResults, logger)); diff --git a/src/Tools/dotnet-monitor/Strings.Designer.cs b/src/Tools/dotnet-monitor/Strings.Designer.cs new file mode 100644 index 00000000000..386de6c1355 --- /dev/null +++ b/src/Tools/dotnet-monitor/Strings.Designer.cs @@ -0,0 +1,576 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Microsoft.Diagnostics.Tools.Monitor { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Strings { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Strings() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.Diagnostics.Tools.Monitor.Strings", typeof(Strings).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to API key authentication not configured.. + /// + internal static string ErrorMessage_ApiKeyNotConfigured { + get { + return ResourceManager.GetString("ErrorMessage_ApiKeyNotConfigured", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to In 'Listen' mode, the diagnostic port endpoint name must be specified.. + /// + internal static string ErrorMessage_DiagnosticPortMissingInListenMode { + get { + return ResourceManager.GetString("ErrorMessage_DiagnosticPortMissingInListenMode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Azure blob egress failed: {0}. + /// + internal static string ErrorMessage_EgressAzureFailedDetailed { + get { + return ResourceManager.GetString("ErrorMessage_EgressAzureFailedDetailed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Azure blob egress failed.. + /// + internal static string ErrorMessage_EgressAzureFailedGeneric { + get { + return ResourceManager.GetString("ErrorMessage_EgressAzureFailedGeneric", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to File system egress failed" {0}. + /// + internal static string ErrorMessage_EgressFileFailedDetailed { + get { + return ResourceManager.GetString("ErrorMessage_EgressFileFailedDetailed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to File system egress failed.. + /// + internal static string ErrorMessage_EgressFileFailedGeneric { + get { + return ResourceManager.GetString("ErrorMessage_EgressFileFailedGeneric", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to SharedAccessSignature or AccountKey must be specified.. + /// + internal static string ErrorMessage_EgressMissingSasOrKey { + get { + return ResourceManager.GetString("ErrorMessage_EgressMissingSasOrKey", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Egress provider '{0}' does not exist.. + /// + internal static string ErrorMessage_EgressProviderDoesNotExist { + get { + return ResourceManager.GetString("ErrorMessage_EgressProviderDoesNotExist", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The {0} field value '{1}' is not allowed.. + /// + internal static string ErrorMessage_FieldNotAllowed { + get { + return ResourceManager.GetString("ErrorMessage_FieldNotAllowed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The {0} field could not be decoded as hex string.. + /// + internal static string ErrorMessage_FieldNotHex { + get { + return ResourceManager.GetString("ErrorMessage_FieldNotHex", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The {0} field value length must be an even number.. + /// + internal static string ErrorMessage_FieldOddLengh { + get { + return ResourceManager.GetString("ErrorMessage_FieldOddLengh", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid API key.. + /// + internal static string ErrorMessage_InvalidApiKey { + get { + return ResourceManager.GetString("ErrorMessage_InvalidApiKey", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid API key format.. + /// + internal static string ErrorMessage_InvalidApiKeyFormat { + get { + return ResourceManager.GetString("ErrorMessage_InvalidApiKeyFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid authentication header.. + /// + internal static string ErrorMessage_InvalidAuthHeader { + get { + return ResourceManager.GetString("ErrorMessage_InvalidAuthHeader", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The {0} parameter value '{1}' is not allowed.. + /// + internal static string ErrorMessage_ParameterNotAllowed { + get { + return ResourceManager.GetString("ErrorMessage_ParameterNotAllowed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The {0} parameter value '{1}' is not allowed. Must be between {2} and {3} bytes long.. + /// + internal static string ErrorMessage_ParameterNotAllowedByteRange { + get { + return ResourceManager.GetString("ErrorMessage_ParameterNotAllowedByteRange", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The {0} field or the {1} field is required.. + /// + internal static string ErrorMessage_TwoFieldsMissing { + get { + return ResourceManager.GetString("ErrorMessage_TwoFieldsMissing", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to bind any urls.. + /// + internal static string ErrorMessage_UnableToBindUrls { + get { + return ResourceManager.GetString("ErrorMessage_UnableToBindUrls", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unhandled connection mode: {0}. + /// + internal static string ErrorMessage_UnhandledConnectionMode { + get { + return ResourceManager.GetString("ErrorMessage_UnhandledConnectionMode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Monitor logs and metrics in a .NET application send the results to a chosen destination.. + /// + internal static string HelpDescription_CommandCollect { + get { + return ResourceManager.GetString("HelpDescription_CommandCollect", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Configuration related commands for dotnet-monitor.. + /// + internal static string HelpDescription_CommandConfig { + get { + return ResourceManager.GetString("HelpDescription_CommandConfig", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Generate api key and hash for authentication.. + /// + internal static string HelpDescription_CommandGenerateKey { + get { + return ResourceManager.GetString("HelpDescription_CommandGenerateKey", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Shows configuration, as if dotnet-monitor collect was executed with these parameters.. + /// + internal static string HelpDescription_CommandShow { + get { + return ResourceManager.GetString("HelpDescription_CommandShow", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The string representing the hash algorithm used to compute ApiKeyHash store in configuration, typically SHA256.. + /// + internal static string HelpDescription_HashAlgorithm { + get { + return ResourceManager.GetString("HelpDescription_HashAlgorithm", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The length of the MonitorApiKey in bytes.. + /// + internal static string HelpDescription_KeyLength { + get { + return ResourceManager.GetString("HelpDescription_KeyLength", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The fully qualified path and filename of the diagnostic port to which runtime instances can connect.. + /// + internal static string HelpDescription_OptionDiagnosticPort { + get { + return ResourceManager.GetString("HelpDescription_OptionDiagnosticPort", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Configuration level. Unredacted configuration can show sensitive information.. + /// + internal static string HelpDescription_OptionLevel { + get { + return ResourceManager.GetString("HelpDescription_OptionLevel", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Enable publishing of metrics. + /// + internal static string HelpDescription_OptionMetrics { + get { + return ResourceManager.GetString("HelpDescription_OptionMetrics", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Bindings for metrics api.. + /// + internal static string HelpDescription_OptionMetricsUrls { + get { + return ResourceManager.GetString("HelpDescription_OptionMetricsUrls", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Turn off authentication.. + /// + internal static string HelpDescription_OptionNoAuth { + get { + return ResourceManager.GetString("HelpDescription_OptionNoAuth", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Generates a new MonitorApiKey for each launch of the process.. + /// + internal static string HelpDescription_OptionTempApiKey { + get { + return ResourceManager.GetString("HelpDescription_OptionTempApiKey", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Bindings for the REST api.. + /// + internal static string HelpDescription_OptionUrls { + get { + return ResourceManager.GetString("HelpDescription_OptionUrls", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {apiAuthenticationConfigKey} settings have changed.. + /// + internal static string LogFormatString_ApiKeyAuthenticationOptionsChanged { + get { + return ResourceManager.GetString("LogFormatString_ApiKeyAuthenticationOptionsChanged", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {apiAuthenticationConfigKey} settings are invalid: {validationFailure}. + /// + internal static string LogFormatString_ApiKeyValidationFailure { + get { + return ResourceManager.GetString("LogFormatString_ApiKeyValidationFailure", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Bound default address: {address}. + /// + internal static string LogFormatString_BoundDefaultAddress { + get { + return ResourceManager.GetString("LogFormatString_BoundDefaultAddress", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Bound metrics address: {address}. + /// + internal static string LogFormatString_BoundMetricsAddress { + get { + return ResourceManager.GetString("LogFormatString_BoundMetricsAddress", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Negotiate, Kerberos, and NTLM authentication are not enabled when running with elevated permissions.. + /// + internal static string LogFormatString_DisabledNegotiateWhileElevated { + get { + return ResourceManager.GetString("LogFormatString_DisabledNegotiateWhileElevated", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Copying action stream to egress stream with buffer size {bufferSize}. + /// + internal static string LogFormatString_EgressCopyActionStreamToEgressStream { + get { + return ResourceManager.GetString("LogFormatString_EgressCopyActionStreamToEgressStream", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Provider '{providerName}': Added.. + /// + internal static string LogFormatString_EgressProviderAdded { + get { + return ResourceManager.GetString("LogFormatString_EgressProviderAdded", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Provider {providerType}: File name = {fileName}. + /// + internal static string LogFormatString_EgressProviderFileName { + get { + return ResourceManager.GetString("LogFormatString_EgressProviderFileName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Provider '{providerName}': Invalid options.. + /// + internal static string LogFormatString_EgressProviderInvalidOptions { + get { + return ResourceManager.GetString("LogFormatString_EgressProviderInvalidOptions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Provider '{providerName}': Type '{providerType}' is not supported.. + /// + internal static string LogFormatString_EgressProviderInvalidType { + get { + return ResourceManager.GetString("LogFormatString_EgressProviderInvalidType", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Provider {providerType}: Invoking stream action.. + /// + internal static string LogFormatString_EgressProviderInvokeStreamAction { + get { + return ResourceManager.GetString("LogFormatString_EgressProviderInvokeStreamAction", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Provider '{providerName}': {validationWarning}. + /// + internal static string LogFormatString_EgressProviderOptionsValidationWarning { + get { + return ResourceManager.GetString("LogFormatString_EgressProviderOptionsValidationWarning", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Provider {providerType}: Provider option {optionName} = {optionValue}. + /// + internal static string LogFormatString_EgressProviderOptionValue { + get { + return ResourceManager.GetString("LogFormatString_EgressProviderOptionValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Provider {providerType}: Saved stream to {path}. + /// + internal static string LogFormatString_EgressProviderSavedStream { + get { + return ResourceManager.GetString("LogFormatString_EgressProviderSavedStream", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Provider '{providerName}': Validating options.. + /// + internal static string LogFormatString_EgressProviderValidatingOptions { + get { + return ResourceManager.GetString("LogFormatString_EgressProviderValidatingOptions", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Provider {providerType}: Unable to find '{keyName}' key in egress properties. + /// + internal static string LogFormatString_EgressProvideUnableToFindPropertyKey { + get { + return ResourceManager.GetString("LogFormatString_EgressProvideUnableToFindPropertyKey", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Provider {providerType}: Stream option {optionName} = {optionValue}. + /// + internal static string LogFormatString_EgressStreamOptionValue { + get { + return ResourceManager.GetString("LogFormatString_EgressStreamOptionValue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to WARNING: Authentication is enabled over insecure http transport. This can pose a security risk and is not intended for production environments.. + /// + internal static string LogFormatString_InsecureAutheticationConfiguration { + get { + return ResourceManager.GetString("LogFormatString_InsecureAutheticationConfiguration", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Generated one-time-use ApiKey for dotnet-monitor; use the following header for authorization:{NewLine}{AuthHeaderName}: {AuthScheme} {MonitorApiKey}. + /// + internal static string LogFormatString_LogTempApiKey { + get { + return ResourceManager.GetString("LogFormatString_LogTempApiKey", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to WARNING: Authentication has been disabled. This can pose a security risk and is not intended for production environments.. + /// + internal static string LogFormatString_NoAuthentication { + get { + return ResourceManager.GetString("LogFormatString_NoAuthentication", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to {failure}. + /// + internal static string LogFormatString_OptionsValidationFailure { + get { + return ResourceManager.GetString("LogFormatString_OptionsValidationFailure", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The process was launched elevated and will have access to all processes on the system. Do not run elevated unless you need to monitor processes launched by another user (e.g., IIS worker processes). + /// + internal static string LogFormatString_RunningElevated { + get { + return ResourceManager.GetString("LogFormatString_RunningElevated", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to listen to {url}. Dotnet-monitor functionality will be limited.. + /// + internal static string LogFormatString_UnableToListenToAddress { + get { + return ResourceManager.GetString("LogFormatString_UnableToListenToAddress", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to :NOT PRESENT:. + /// + internal static string Placeholder_NotPresent { + get { + return ResourceManager.GetString("Placeholder_NotPresent", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to :REDACTED:. + /// + internal static string Placeholder_Redacted { + get { + return ResourceManager.GetString("Placeholder_Redacted", resourceCulture); + } + } + } +} diff --git a/src/Tools/dotnet-monitor/Strings.resx b/src/Tools/dotnet-monitor/Strings.resx new file mode 100644 index 00000000000..6448e190ef2 --- /dev/null +++ b/src/Tools/dotnet-monitor/Strings.resx @@ -0,0 +1,429 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + API key authentication not configured. + Gets a string similar to "API key authentication not configured.". + + + In 'Listen' mode, the diagnostic port endpoint name must be specified. + Gets a string similar to "In 'Listen' mode, the diagnostic port endpoint name must be specified.". + + + Azure blob egress failed: {0} + Gets the format string for egress failure to Azure blob (with an inner message). +1 Format Parameter: +0. innerMessage: The detailed inner message with additional error context. + + + Azure blob egress failed. + Gets a string similar to "Azure blob egress failed.". + + + File system egress failed" {0} + Gets the format string for egress failure to File (with an inner message). +1 Format Parameter: +0. innerMessage: The detailed inner message with additional error context. + + + File system egress failed. + Gets a string similar to "File system egress failed.". + + + SharedAccessSignature or AccountKey must be specified. + Gets a string similar to "SharedAccessSignature or AccountKey must be specified.". + + + Egress provider '{0}' does not exist. + Gets the format string for egress provider failure due to missing provider. +1 Format Parameter: +0. providerName: The name of the provider that could not be found. + + + The {0} field value '{1}' is not allowed. + Gets the format string for rejecting a field value. +2 Format Parameters: +0. fieldName: The name of the field that failed validation +1. fieldValue: The value in the field that was rejected + + + The {0} field could not be decoded as hex string. + Gets the format string for rejecting a field because it is not hex. +1 Format Parameter: +0. fieldName: The name of the field that failed validation + + + The {0} field value length must be an even number. + Gets the format string for rejecting a field because it must have an even numbered length. +1 Format Parameter: +0. fieldName: The name of the field that failed validation + + + Invalid API key. + Gets a string similar to "Invalid API key.". + + + Invalid API key format. + Gets a string similar to "Invalid API key format.". + + + Invalid authentication header. + Gets a string similar to "Invalid authentication header.". + + + The {0} parameter value '{1}' is not allowed. + Gets the format string for rejecting a parameter value. +2 Format Parameters: +0. parameterName: The name of the parameter that failed validation +1. parameterValue: The value in the parameter that was rejected + + + The {0} parameter value '{1}' is not allowed. Must be between {2} and {3} bytes long. + Gets the format string for rejecting a parameter value with additional text specifying the required range in bytes. +4 Format Parameters: +0. parameterName: The name of the parameter that failed validation +1. parameterValue: The value in the parameter that was rejected +2. minBytes: The minimum number of bytes acceptable +3. maxBytes: The maximum number of bytes acceptable + + + The {0} field or the {1} field is required. + Gets the format string for rejecting validation due to 2 missing fields where at least one is required. +2 Format Parameters: +0. fieldNameOne: The name of the first field that is missing +1. fieldNameTwo: The name of the second field that is missing + + + Unable to bind any urls. + Gets a string similar to "Unable to bind any urls.". + + + Unhandled connection mode: {0} + Gets the format string for egress provider failure due to missing provider. +1 Format Parameter: +0. connectionMode: The provided DiagnosticPortConnectionMode that could not be parsed. + + + Monitor logs and metrics in a .NET application send the results to a chosen destination. + Gets the string to display in help that explains what the 'collect' command does. + + + Configuration related commands for dotnet-monitor. + Gets the string to display in help that explains what the 'config' command does. + + + Generate api key and hash for authentication. + Gets the string to display in help that explains what the 'generatekey' command does. + + + Shows configuration, as if dotnet-monitor collect was executed with these parameters. + Gets the string to display in help that explains what the 'show' command does. + + + The string representing the hash algorithm used to compute ApiKeyHash store in configuration, typically SHA256. + Gets the string to display in help that explains what the '--hash-algorithm' option does. + + + The length of the MonitorApiKey in bytes. + Gets the string to display in help that explains what the '--key-length' option does. + + + The fully qualified path and filename of the diagnostic port to which runtime instances can connect. + Gets the string to display in help that explains what the '--diagnostic-port' option does. + + + Configuration level. Unredacted configuration can show sensitive information. + Gets the string to display in help that explains what the '--level' option does. + + + Enable publishing of metrics + Gets the string to display in help that explains what the '--metricls' option does. + + + Bindings for metrics api. + Gets the string to display in help that explains what the '--metricUrls' option does. + + + Turn off authentication. + Gets the string to display in help that explains what the '--no-auth' option does. + + + Generates a new MonitorApiKey for each launch of the process. + Gets the string to display in help that explains what the '--temp-apikey' option does. + + + Bindings for the REST api. + Gets the string to display in help that explains what the '--urls' option does. + + + {apiAuthenticationConfigKey} settings have changed. + Gets the format string that is printed in the 22:ApiKeyAuthenticationOptionsChanged event. +1 Format Parameter: +1. apiAuthenticationConfigKey: The string key of ApiAuthentication object in configuration. + + + {apiAuthenticationConfigKey} settings are invalid: {validationFailure} + Gets the format string that is printed in the 21:ApiKeyValidationFailure event. +2 Format Parameters: +1. apiAuthenticationConfigKey: The string key of ApiAuthentication object in configuration. +2. validationFailure: The error message of why the provided ApiAuthentication object is invalid. + + + Bound default address: {address} + Gets the format string that is printed in the 16:BoundDefaultAddress event. +1 Format Parameter: +1. address: The address the REST api was bound to + + + Bound metrics address: {address} + Gets the format string that is printed in the 17:BoundMetricsAddress event. +1 Format Parameter: +1. address: The address the metrics api was bound to + + + Negotiate, Kerberos, and NTLM authentication are not enabled when running with elevated permissions. + Gets the format string that is printed in the 20:DisabledNegotiateWhileElevated event. +0 Format Parameters + + + Copying action stream to egress stream with buffer size {bufferSize} + Gets the format string that is printed in the 5:EgressCopyActionStreamToEgressStream event. +1 Format Parameter: +1. bufferSize: Size of the buffer + + + Provider '{providerName}': Added. + Gets the format string that is printed in the 1:EgressProviderAdded event. +1 Format Parameter: +1. providerName: Name of the provider that was added + + + Provider {providerType}: File name = {fileName} + Gets the format string that is printed in the 9:EgressProviderFileName event. +2 Format Parameters: +1. providerType: Type of the provider +2. fileName: Name of the file being egressed + + + Provider '{providerName}': Invalid options. + Gets the format string that is printed in the 2:EgressProviderInvalidOptions event. +1 Format Parameter: +1. providerName: Name of the provider that was not valid + + + Provider '{providerName}': Type '{providerType}' is not supported. + Gets the format string that is printed in the 3:EgressProviderInvalidType event. +2 Format Parameters: +1. providerName: Name of the provider that was not valid +2. providerType: Type of the provider that is not a valid type + + + Provider {providerType}: Invoking stream action. + Gets the format string that is printed in the 11:EgressProviderInvokeStreamAction event. +1 Format Parameter: +1. providerType: Type of the provider that was invoked + + + Provider '{providerName}': {validationWarning} + Gets the format string that is printed in the 6:EgressProviderOptionsValidationWarning event. +2 Format Parameters: +1. providerName: Name of the provider with a warning +2. validationWarning: The warning message + + + Provider {providerType}: Provider option {optionName} = {optionValue} + Gets the format string that is printed in the 7:EgressProviderOptionValue event. +3 Format Parameters: +1. providerType: Type of the provider +2. optionName: Name of the provider option on this provider +3. optionValue: Value of the option specified by OptionName + + + Provider {providerType}: Saved stream to {path} + Gets the format string that is printed in the 12:EgressProviderSavedStream event. +2 Format Parameters: +1. providerType: Type of the provider +2. path: path where provider saved the stream + + + Provider '{providerName}': Validating options. + Gets the format string that is printed in the 4:EgressProviderValidatingOptions event. +1 Format Parameter: +1. providerName: Name of the provider that is being validated + + + Provider {providerType}: Unable to find '{keyName}' key in egress properties + Gets the format string that is printed in the 10:EgressProvideUnableToFindPropertyKey event. +2 Format Parameters: +1. providerType: Type of the provider +2. keyName: Name of the property that could not be found + + + Provider {providerType}: Stream option {optionName} = {optionValue} + Gets the format string that is printed in the 8:EgressStreamOptionValue event. +3 Format Parameters: +1. providerType: Type of the provider +2. optionName: Name of the stream option on this provider +3. optionValue: Value of the option specified by OptionName + + + WARNING: Authentication is enabled over insecure http transport. This can pose a security risk and is not intended for production environments. + Gets the format string that is printed in the 14:InsecureAutheticationConfiguration event. +0 Format Parameters + + + Generated one-time-use ApiKey for dotnet-monitor; use the following header for authorization:{NewLine}{AuthHeaderName}: {AuthScheme} {MonitorApiKey} + Gets the format string that is printed in the 23:LogTempApiKey event. +4 Format Parameters: +1. NewLine: A newline string from the current environment, Environment.NewLine +2. AuthHeaderName: The string name of the Authorization header, "Authorization" +3. AuthScheme: The scheme used in the http Authorization header +4. MonitorApiKey: The parameter to the scheme used in the http Authorization header, this should be the MonitorApiKey's value + + + WARNING: Authentication has been disabled. This can pose a security risk and is not intended for production environments. + Gets the format string that is printed in the 13:NoAuthentication event. +0 Format Parameters + + + {failure} + Gets the format string that is printed in the 18:OptionsValidationFailure event. +1 Format Parameter: +1. failure: The failure message from validation + + + The process was launched elevated and will have access to all processes on the system. Do not run elevated unless you need to monitor processes launched by another user (e.g., IIS worker processes) + Gets the format string that is printed in the 19:RunningElevated event. +0 Format Parameters + + + Unable to listen to {url}. Dotnet-monitor functionality will be limited. + Gets the format string that is printed in the 15:UnableToListenToAddress event. +1 Format Parameter: +1. url: The URL that could not have a listener attached to it + + + :NOT PRESENT: + Gets a string similar to ":NOT PRESENT:". + + + :REDACTED: + Gets a string similar to ":REDACTED:". + + \ No newline at end of file diff --git a/src/Tools/dotnet-monitor/Throttling.cs b/src/Tools/dotnet-monitor/Throttling.cs index 08c7cc4ff68..ea90ae27288 100644 --- a/src/Tools/dotnet-monitor/Throttling.cs +++ b/src/Tools/dotnet-monitor/Throttling.cs @@ -5,10 +5,7 @@ using Microsoft.AspNetCore.Http; using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Extensions.Logging; -using System; using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; using System.Net; using System.Threading; using System.Threading.Tasks; diff --git a/src/Tools/dotnet-monitor/dotnet-monitor.csproj b/src/Tools/dotnet-monitor/dotnet-monitor.csproj index d7555136994..9e43c325595 100644 --- a/src/Tools/dotnet-monitor/dotnet-monitor.csproj +++ b/src/Tools/dotnet-monitor/dotnet-monitor.csproj @@ -57,4 +57,16 @@ + + + True + True + Strings.resx + + + ResXFileCodeGenerator + Strings.Designer.cs + + + From 00d9ad1a72f22c759f655bb980928b6d5629766c Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 18 Jun 2021 12:31:31 +0000 Subject: [PATCH 080/185] Update dependencies from https://github.com/dotnet/diagnostics build 20210617.1 (#459) [main] Update dependencies from dotnet/diagnostics --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 1e94ab09151..1342fc8c454 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics - 605d5481c4aa09c801a55785d523811696e3fe2e + 24d52ed63bea25654857b81771342948c9ce7491 - + https://github.com/dotnet/diagnostics - 605d5481c4aa09c801a55785d523811696e3fe2e + 24d52ed63bea25654857b81771342948c9ce7491 diff --git a/eng/Versions.props b/eng/Versions.props index 09ec642e0e4..2e84fecd45c 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-preview.7.21316.11 - 5.0.0-preview.21316.1 - 5.0.0-preview.21316.1 + 5.0.0-preview.21317.1 + 5.0.0-preview.21317.1 6.0.0-preview.7.21317.1 From 7ccb8b8df4a7993506c5a73405c9b6b37f555290 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 18 Jun 2021 12:31:49 +0000 Subject: [PATCH 081/185] Update dependencies from https://github.com/dotnet/arcade build 20210617.1 (#460) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- global.json | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 1342fc8c454..24d86ed16ff 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -14,13 +14,13 @@ - + https://github.com/dotnet/arcade - d8967a1e57275aa682c7639ef95b4d148722ba4e + 5619c32997ab2d6a5ddf6d2e488c572b882f891b - + https://github.com/dotnet/arcade - d8967a1e57275aa682c7639ef95b4d148722ba4e + 5619c32997ab2d6a5ddf6d2e488c572b882f891b https://github.com/dotnet/symstore diff --git a/eng/Versions.props b/eng/Versions.props index 2e84fecd45c..840a553a1ed 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -27,7 +27,7 @@ --> - 6.0.0-beta.21316.3 + 6.0.0-beta.21317.1 6.0.0-preview.7.21316.11 diff --git a/global.json b/global.json index 14005765f1d..da6f401c93f 100644 --- a/global.json +++ b/global.json @@ -16,6 +16,6 @@ }, "msbuild-sdks": { "Microsoft.Build.NoTargets": "2.0.1", - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21316.3" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21317.1" } } From 860be40198609b9942c30cb643c82909649736c9 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 18 Jun 2021 12:41:47 +0000 Subject: [PATCH 082/185] Update dependencies from https://github.com/dotnet/runtime build 20210618.2 (#461) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 24d86ed16ff..1173f5a59e9 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 4fc4748c196de4bae8da1e146638f484e7e4b99c - + https://github.com/dotnet/runtime - 96a4671bc52e70024da409f5f48b0abaa30cb901 + 140120290aaaffb40e90e8ece982b4f0170c6700 diff --git a/eng/Versions.props b/eng/Versions.props index 840a553a1ed..c03dde918b0 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21317.1 5.0.0-preview.21317.1 - 6.0.0-preview.7.21317.1 + 6.0.0-preview.7.21318.2 1.0.215101 From 3fc13d4c127b5bfddb519b52b759f286809cf315 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 18 Jun 2021 12:46:58 +0000 Subject: [PATCH 083/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210618.1 (#462) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 1173f5a59e9..18320d84082 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - 4fc4748c196de4bae8da1e146638f484e7e4b99c + 746b9f82fb5c026ce3ce1aed9b2883078ca9ebe6 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index c03dde918b0..63180c4eb9e 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21317.1 - 6.0.0-preview.7.21316.11 + 6.0.0-preview.7.21318.1 5.0.0-preview.21317.1 5.0.0-preview.21317.1 From deb715ec958935b9ee82ff52f06a6273ddfe894b Mon Sep 17 00:00:00 2001 From: Justin Anderson Date: Fri, 18 Jun 2021 13:26:55 -0700 Subject: [PATCH 084/185] Copy endpoint info, runtime info, commmand parsing, and tests from dotnet/diagnostics (#451) --- eng/Versions.props | 1 + .../CommandLineHelper.cs | 69 ++++ .../EndpointInfo/ClientEndpointInfoSource.cs | 54 +++ .../EndpointInfo/EndpointInfo.cs | 99 ++++++ .../EndpointInfo/IEndpointInfoSource.cs | 36 ++ .../EndpointInfo/ServerEndpointInfoSource.cs | 272 +++++++++++++++ .../OptionsDisplayStrings.Designer.cs | 18 - .../OptionsDisplayStrings.resx | 8 - .../SchemaGenerationTests.cs | 1 + .../OpenApiGeneratorTests.cs | 1 + .../CommonTestTimeouts.cs | 26 ++ .../DiagnosticPortHelper.cs | 2 +- ...t.Diagnostics.Monitoring.TestCommon.csproj | 6 + .../Runners/AppRunner.cs | 28 +- .../Runners/AppRunnerExtensions.cs | 28 +- .../Runners/ConsoleLogEvent.cs | 2 +- .../{ => Runners}/DotNetRunner.cs | 3 +- .../{ => Runners}/LoggingRunnerAdapter.cs | 3 +- .../DumpTests.cs | 1 + .../ProcessTests.cs | 3 +- .../Runners/MonitorRunnerExtensions.cs | 2 +- .../Runners/ScenarioRunner.cs | 3 +- .../TestTimeouts.cs | 15 - .../CommandLineHelperTests.cs | 43 +++ .../EndpointInfoSourceTests.cs | 309 ++++++++++++++++++ ...ft.Diagnostics.Monitoring.UnitTests.csproj | 6 +- .../DiagnosticPortConnectionMode.cs | 19 ++ .../dotnet-monitor/DiagnosticPortOptions.cs | 15 - .../DiagnosticPortOptionsDefaults.cs | 4 - .../DiagnosticsMonitorCommandHandler.cs | 5 +- .../Egress/AzureBlobEgressFactory.cs | 1 - .../Egress/ConfiguredEgressProvider.cs | 1 - .../dotnet-monitor/Egress/EgressService.cs | 1 - .../Egress/FileSystemEgressFactory.cs | 1 - .../FilteredEndpointInfoSource.cs | 2 +- ...FilteredEndpointInfoSourceHostedService.cs | 2 +- src/Tools/dotnet-monitor/Program.cs | 1 - src/Tools/dotnet-monitor/RuntimeInfo.cs | 46 +++ 38 files changed, 1033 insertions(+), 104 deletions(-) create mode 100644 src/Microsoft.Diagnostics.Monitoring.WebApi/CommandLineHelper.cs create mode 100644 src/Microsoft.Diagnostics.Monitoring.WebApi/EndpointInfo/ClientEndpointInfoSource.cs create mode 100644 src/Microsoft.Diagnostics.Monitoring.WebApi/EndpointInfo/EndpointInfo.cs create mode 100644 src/Microsoft.Diagnostics.Monitoring.WebApi/EndpointInfo/IEndpointInfoSource.cs create mode 100644 src/Microsoft.Diagnostics.Monitoring.WebApi/EndpointInfo/ServerEndpointInfoSource.cs create mode 100644 src/Tests/Microsoft.Diagnostics.Monitoring.TestCommon/CommonTestTimeouts.cs rename src/Tests/{Microsoft.Diagnostics.Monitoring.Tool.UnitTests => Microsoft.Diagnostics.Monitoring.TestCommon}/DiagnosticPortHelper.cs (96%) rename src/Tests/{Microsoft.Diagnostics.Monitoring.Tool.UnitTests => Microsoft.Diagnostics.Monitoring.TestCommon}/Runners/AppRunner.cs (90%) rename src/Tests/{Microsoft.Diagnostics.Monitoring.Tool.UnitTests => Microsoft.Diagnostics.Monitoring.TestCommon}/Runners/AppRunnerExtensions.cs (79%) rename src/Tests/{Microsoft.Diagnostics.Monitoring.Tool.UnitTests => Microsoft.Diagnostics.Monitoring.TestCommon}/Runners/ConsoleLogEvent.cs (93%) rename src/Tests/Microsoft.Diagnostics.Monitoring.TestCommon/{ => Runners}/DotNetRunner.cs (98%) rename src/Tests/Microsoft.Diagnostics.Monitoring.TestCommon/{ => Runners}/LoggingRunnerAdapter.cs (98%) create mode 100644 src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/CommandLineHelperTests.cs create mode 100644 src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/EndpointInfoSourceTests.cs create mode 100644 src/Tools/dotnet-monitor/DiagnosticPortConnectionMode.cs create mode 100644 src/Tools/dotnet-monitor/RuntimeInfo.cs diff --git a/eng/Versions.props b/eng/Versions.props index 63180c4eb9e..ce8d838db70 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -64,6 +64,7 @@ 10.3.11 5.6.3 + 2.4.1 - 6.0.0-beta.21317.1 + 6.0.0-beta.21318.2 6.0.0-preview.7.21318.1 diff --git a/eng/common/generate-locproject.ps1 b/eng/common/generate-locproject.ps1 index de348a2e225..25e97ac0077 100644 --- a/eng/common/generate-locproject.ps1 +++ b/eng/common/generate-locproject.ps1 @@ -25,8 +25,15 @@ Push-Location "$SourcesDirectory" # push location for Resolve-Path -Relative to # Template files $jsonFiles = @() -$jsonFiles += Get-ChildItem -Recurse -Path "$SourcesDirectory" | Where-Object { $_.FullName -Match "\.template\.config\\localize\\en\..+\.json" } # .NET templating pattern -$jsonFiles += Get-ChildItem -Recurse -Path "$SourcesDirectory" | Where-Object { $_.FullName -Match "en\\strings\.json" } # current winforms pattern +$jsonTemplateFiles = Get-ChildItem -Recurse -Path "$SourcesDirectory" | Where-Object { $_.FullName -Match "\.template\.config\\localize\\.+\.en\.json" } # .NET templating pattern +$jsonTemplateFiles | ForEach-Object { + $null = $_.Name -Match "(.+)\.[\w-]+\.json" # matches '[filename].[langcode].json + + $destinationFile = "$($_.Directory.FullName)\$($Matches.1).json" + $jsonFiles += Copy-Item "$($_.FullName)" -Destination $destinationFile -PassThru +} + +$jsonWinformsTemplateFiles = Get-ChildItem -Recurse -Path "$SourcesDirectory" | Where-Object { $_.FullName -Match "en\\strings\.json" } # current winforms pattern $xlfFiles = @() @@ -44,7 +51,7 @@ $langXlfFiles | ForEach-Object { $xlfFiles += Copy-Item "$($_.FullName)" -Destination $destinationFile -PassThru } -$locFiles = $jsonFiles + $xlfFiles +$locFiles = $jsonFiles + $jsonWinformsTemplateFiles + $xlfFiles $locJson = @{ Projects = @( diff --git a/global.json b/global.json index da6f401c93f..b2c0b306593 100644 --- a/global.json +++ b/global.json @@ -16,6 +16,6 @@ }, "msbuild-sdks": { "Microsoft.Build.NoTargets": "2.0.1", - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21317.1" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21318.2" } } From a5fece4af5f1b0d3e0a8df3bde3570bc61b9b99a Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 19 Jun 2021 12:39:23 +0000 Subject: [PATCH 086/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210619.1 (#467) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 50822fe4ba7..3fa995abacb 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - 746b9f82fb5c026ce3ce1aed9b2883078ca9ebe6 + c5800e2a83d73e696088c455c7d2cb0b7ac9018a https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 1e8eb10ce82..6147a02aca9 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21318.2 - 6.0.0-preview.7.21318.1 + 6.0.0-preview.7.21319.1 5.0.0-preview.21317.1 5.0.0-preview.21317.1 From 18903a5b20b5b38d6f91869e516440f7e7973a7a Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 19 Jun 2021 12:44:18 +0000 Subject: [PATCH 087/185] Update dependencies from https://github.com/dotnet/runtime build 20210618.21 (#466) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 3fa995abacb..191c7464f5f 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore c5800e2a83d73e696088c455c7d2cb0b7ac9018a - + https://github.com/dotnet/runtime - 140120290aaaffb40e90e8ece982b4f0170c6700 + ca3c11d64516217134430d04354ac770b07c91ef diff --git a/eng/Versions.props b/eng/Versions.props index 6147a02aca9..75fe02be998 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21317.1 5.0.0-preview.21317.1 - 6.0.0-preview.7.21318.2 + 6.0.0-preview.7.21318.21 1.0.215101 From 0a993c6e703d9a5d17dc00280765b3f1ebdeee43 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sun, 20 Jun 2021 12:31:53 +0000 Subject: [PATCH 088/185] Update dependencies from https://github.com/dotnet/arcade build 20210619.2 (#469) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- global.json | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 191c7464f5f..a364fd54b92 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -14,13 +14,13 @@ - + https://github.com/dotnet/arcade - 4a2adbaf2da67d8951fbc19d4c257a6fd51741c2 + a3377cccde8639089f99107e2ba5df2c8cbe6394 - + https://github.com/dotnet/arcade - 4a2adbaf2da67d8951fbc19d4c257a6fd51741c2 + a3377cccde8639089f99107e2ba5df2c8cbe6394 https://github.com/dotnet/symstore diff --git a/eng/Versions.props b/eng/Versions.props index 75fe02be998..3d4747c538f 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -27,7 +27,7 @@ --> - 6.0.0-beta.21318.2 + 6.0.0-beta.21319.2 6.0.0-preview.7.21319.1 diff --git a/global.json b/global.json index b2c0b306593..add90405031 100644 --- a/global.json +++ b/global.json @@ -16,6 +16,6 @@ }, "msbuild-sdks": { "Microsoft.Build.NoTargets": "2.0.1", - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21318.2" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21319.2" } } From 1b46cdc0cb62577e8bec2355f0dc3fd4a7381b41 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sun, 20 Jun 2021 12:43:11 +0000 Subject: [PATCH 089/185] Update dependencies from https://github.com/dotnet/runtime build 20210619.2 (#470) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index a364fd54b92..d9cb83b35bf 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore c5800e2a83d73e696088c455c7d2cb0b7ac9018a - + https://github.com/dotnet/runtime - ca3c11d64516217134430d04354ac770b07c91ef + 24950a310bde0d816060f920090b4e9666c15fed diff --git a/eng/Versions.props b/eng/Versions.props index 3d4747c538f..9d56c57b31f 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21317.1 5.0.0-preview.21317.1 - 6.0.0-preview.7.21318.21 + 6.0.0-preview.7.21319.2 1.0.215101 From b25c02421fc3634d8b455ce9e8b51dd59b98878f Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sun, 20 Jun 2021 12:43:19 +0000 Subject: [PATCH 090/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210619.2 (#471) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index d9cb83b35bf..a328d2c8354 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - c5800e2a83d73e696088c455c7d2cb0b7ac9018a + a9a6831a1a0aa2fc21c276e1f28b86a2b1cdbb28 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 9d56c57b31f..ae89fad1883 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21319.2 - 6.0.0-preview.7.21319.1 + 6.0.0-preview.7.21319.2 5.0.0-preview.21317.1 5.0.0-preview.21317.1 From 222ecc2590cb49750a93dcc73b2ee173b5e3cc50 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 21 Jun 2021 12:29:30 +0000 Subject: [PATCH 091/185] Update dependencies from https://github.com/dotnet/diagnostics build 20210618.1 (#472) [main] Update dependencies from dotnet/diagnostics --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index a328d2c8354..43fba3fc09e 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics - 24d52ed63bea25654857b81771342948c9ce7491 + 7b253a5dbde5f2574ada392ceb4e9d6d19083ad9 - + https://github.com/dotnet/diagnostics - 24d52ed63bea25654857b81771342948c9ce7491 + 7b253a5dbde5f2574ada392ceb4e9d6d19083ad9 diff --git a/eng/Versions.props b/eng/Versions.props index ae89fad1883..c5a493d97fd 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-preview.7.21319.2 - 5.0.0-preview.21317.1 - 5.0.0-preview.21317.1 + 5.0.0-preview.21318.1 + 5.0.0-preview.21318.1 6.0.0-preview.7.21319.2 From 289c562906f555429cc84fed15db0ce392283928 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 21 Jun 2021 12:42:26 +0000 Subject: [PATCH 092/185] Update dependencies from https://github.com/dotnet/runtime build 20210621.2 (#473) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 43fba3fc09e..6d56c31fdb7 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore a9a6831a1a0aa2fc21c276e1f28b86a2b1cdbb28 - + https://github.com/dotnet/runtime - 24950a310bde0d816060f920090b4e9666c15fed + f891033db5b8ebf651176a3dcc3bec74a217f85e diff --git a/eng/Versions.props b/eng/Versions.props index c5a493d97fd..398d8b8d3bb 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21318.1 5.0.0-preview.21318.1 - 6.0.0-preview.7.21319.2 + 6.0.0-preview.7.21321.2 1.0.215101 From 44cd022e7720d7c0372a90e518ec1f1c904a8fcb Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 22 Jun 2021 16:14:40 +0000 Subject: [PATCH 093/185] Update dependencies from https://github.com/dotnet/diagnostics build 20210621.1 (#476) [main] Update dependencies from dotnet/diagnostics --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 6d56c31fdb7..a8c3f64838c 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics - 7b253a5dbde5f2574ada392ceb4e9d6d19083ad9 + 3451a6dfa5ee3d1e8d0e2c3af7d4ced7f2af0129 - + https://github.com/dotnet/diagnostics - 7b253a5dbde5f2574ada392ceb4e9d6d19083ad9 + 3451a6dfa5ee3d1e8d0e2c3af7d4ced7f2af0129 diff --git a/eng/Versions.props b/eng/Versions.props index 398d8b8d3bb..284d8d38b02 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-preview.7.21319.2 - 5.0.0-preview.21318.1 - 5.0.0-preview.21318.1 + 5.0.0-preview.21321.1 + 5.0.0-preview.21321.1 6.0.0-preview.7.21321.2 From 2311bda4bdfe8e58021c765049cb98d3b3d247bb Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 22 Jun 2021 16:32:31 +0000 Subject: [PATCH 094/185] Update dependencies from https://github.com/dotnet/runtime build 20210621.15 (#478) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index a8c3f64838c..c326e514f08 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore a9a6831a1a0aa2fc21c276e1f28b86a2b1cdbb28 - + https://github.com/dotnet/runtime - f891033db5b8ebf651176a3dcc3bec74a217f85e + 2a43c07bb82113a029090730d8ca001a68b22c05 diff --git a/eng/Versions.props b/eng/Versions.props index 284d8d38b02..fca8f253ffc 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21321.1 5.0.0-preview.21321.1 - 6.0.0-preview.7.21321.2 + 6.0.0-preview.7.21321.15 1.0.215101 From 05bee47639e6151fabfd5aba11ec9b28d4c6ccb9 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 22 Jun 2021 16:32:39 +0000 Subject: [PATCH 095/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210621.7 (#479) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index c326e514f08..80911361f09 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - a9a6831a1a0aa2fc21c276e1f28b86a2b1cdbb28 + ab87c90db386a5c442e1299b8dbc24a2d37a3754 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index fca8f253ffc..30a2e3f1b87 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21319.2 - 6.0.0-preview.7.21319.2 + 6.0.0-preview.7.21321.7 5.0.0-preview.21321.1 5.0.0-preview.21321.1 From c456e5fe6b1aabe25739a85652f7333a30517f68 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 22 Jun 2021 16:35:20 +0000 Subject: [PATCH 096/185] Update dependencies from https://github.com/dotnet/arcade build 20210621.1 (#477) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- global.json | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 80911361f09..4db493380b8 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -14,13 +14,13 @@ - + https://github.com/dotnet/arcade - a3377cccde8639089f99107e2ba5df2c8cbe6394 + 36b148348ee8312f6369c0c56b0d0fe07deec603 - + https://github.com/dotnet/arcade - a3377cccde8639089f99107e2ba5df2c8cbe6394 + 36b148348ee8312f6369c0c56b0d0fe07deec603 https://github.com/dotnet/symstore diff --git a/eng/Versions.props b/eng/Versions.props index 30a2e3f1b87..9244988a223 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -27,7 +27,7 @@ --> - 6.0.0-beta.21319.2 + 6.0.0-beta.21321.1 6.0.0-preview.7.21321.7 diff --git a/global.json b/global.json index add90405031..3b8d2ef6f57 100644 --- a/global.json +++ b/global.json @@ -16,6 +16,6 @@ }, "msbuild-sdks": { "Microsoft.Build.NoTargets": "2.0.1", - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21319.2" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21321.1" } } From 6a0183af9add2cdcf26cd807ad4da07fb67500ef Mon Sep 17 00:00:00 2001 From: kkeirstead <85592574+kkeirstead@users.noreply.github.com> Date: Tue, 22 Jun 2021 11:53:10 -0700 Subject: [PATCH 097/185] Add Support For Json Text Sequence When Acquiring Logs (#468) --- documentation/openapi.json | 10 ++ .../ContentTypes.cs | 1 + .../Controllers/DiagController.cs | 32 ++++- .../LogFormat.cs | 5 +- .../StreamingLogger.cs | 19 ++- .../HttpApi/ApiClient.cs | 40 ++++-- .../HttpApi/ApiClientExtensions.cs | 17 +-- .../HttpApi/ContentTypes.cs | 1 + .../LogsTests.cs | 131 ++++++++++++------ 9 files changed, 182 insertions(+), 74 deletions(-) diff --git a/documentation/openapi.json b/documentation/openapi.json index 3a1acd0bec9..db646230587 100644 --- a/documentation/openapi.json +++ b/documentation/openapi.json @@ -580,6 +580,11 @@ "type": "string" } }, + "application/json-seq": { + "schema": { + "type": "string" + } + }, "text/event-stream": { "schema": { "type": "string" @@ -684,6 +689,11 @@ "type": "string" } }, + "application/json-seq": { + "schema": { + "type": "string" + } + }, "text/event-stream": { "schema": { "type": "string" diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/ContentTypes.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/ContentTypes.cs index 00fdcad7d60..066e52b25f8 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/ContentTypes.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/ContentTypes.cs @@ -7,6 +7,7 @@ namespace Microsoft.Diagnostics.Monitoring.WebApi internal static class ContentTypes { public const string ApplicationJson = "application/json"; + public const string ApplicationJsonSequence = "application/json-seq"; public const string ApplicationNdJson = "application/x-ndjson"; public const string ApplicationOctetStream = "application/octet-stream"; public const string ApplicationProblemJson = "application/problem+json"; diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.cs index e3772c5a291..f403e6c1e7e 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.cs @@ -42,6 +42,7 @@ public class DiagController : ControllerBase private const Models.TraceProfile DefaultTraceProfiles = Models.TraceProfile.Cpu | Models.TraceProfile.Http | Models.TraceProfile.Metrics; private static readonly MediaTypeHeaderValue NdJsonHeader = new MediaTypeHeaderValue(ContentTypes.ApplicationNdJson); + private static readonly MediaTypeHeaderValue JsonSequenceHeader = new MediaTypeHeaderValue(ContentTypes.ApplicationJsonSequence); private static readonly MediaTypeHeaderValue EventStreamHeader = new MediaTypeHeaderValue(ContentTypes.TextEventStream); private readonly ILogger _logger; @@ -360,7 +361,7 @@ public Task CaptureTraceCustom( /// The level of the logs to capture. /// The egress provider to which the logs are saved. [HttpGet("logs/{processKey?}", Name = nameof(CaptureLogs))] - [ProducesWithProblemDetails(ContentTypes.ApplicationNdJson, ContentTypes.TextEventStream)] + [ProducesWithProblemDetails(ContentTypes.ApplicationNdJson, ContentTypes.ApplicationJsonSequence, ContentTypes.TextEventStream)] [ProducesResponseType(typeof(void), StatusCodes.Status429TooManyRequests)] [ProducesResponseType(typeof(string), StatusCodes.Status200OK)] [RequestLimit(MaxConcurrency = 3)] @@ -405,7 +406,7 @@ public Task CaptureLogs( /// The duration of the logs session (in seconds). /// The egress provider to which the logs are saved. [HttpPost("logs/{processKey?}", Name = nameof(CaptureLogsCustom))] - [ProducesWithProblemDetails(ContentTypes.ApplicationNdJson, ContentTypes.TextEventStream)] + [ProducesWithProblemDetails(ContentTypes.ApplicationNdJson, ContentTypes.ApplicationJsonSequence, ContentTypes.TextEventStream)] [ProducesResponseType(typeof(void), StatusCodes.Status429TooManyRequests)] [ProducesResponseType(typeof(string), StatusCodes.Status200OK)] [RequestLimit(MaxConcurrency = 3)] @@ -483,7 +484,20 @@ private ActionResult StartLogs( } string fileName = FormattableString.Invariant($"{GetFileNameTimeStampUtcNow()}_{processInfo.EndpointInfo.ProcessId}.txt"); - string contentType = format == LogFormat.EventStream ? ContentTypes.TextEventStream : ContentTypes.ApplicationNdJson; + string contentType = ContentTypes.TextEventStream; + + if (format == LogFormat.EventStream) + { + contentType = ContentTypes.TextEventStream; + } + else if (format == LogFormat.NDJson) + { + contentType = ContentTypes.ApplicationNdJson; + } + else if (format == LogFormat.JsonSequence) + { + contentType = ContentTypes.ApplicationJsonSequence; + } Func action = async (outputStream, token) => { @@ -532,7 +546,11 @@ private static LogFormat ComputeLogFormat(IList acceptedHe } if (acceptedHeaders.Contains(NdJsonHeader)) { - return LogFormat.Json; + return LogFormat.NDJson; + } + if (acceptedHeaders.Contains(JsonSequenceHeader)) + { + return LogFormat.JsonSequence; } if (acceptedHeaders.Any(h => EventStreamHeader.IsSubsetOf(h))) { @@ -540,7 +558,11 @@ private static LogFormat ComputeLogFormat(IList acceptedHe } if (acceptedHeaders.Any(h => NdJsonHeader.IsSubsetOf(h))) { - return LogFormat.Json; + return LogFormat.NDJson; + } + if (acceptedHeaders.Any(h => JsonSequenceHeader.IsSubsetOf(h))) + { + return LogFormat.JsonSequence; } return LogFormat.None; } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/LogFormat.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/LogFormat.cs index 285ed532e38..cacbcbb47c3 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/LogFormat.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/LogFormat.cs @@ -12,7 +12,8 @@ namespace Microsoft.Diagnostics.Monitoring.WebApi public enum LogFormat { None = 0, - Json = 1, - EventStream = 2 + NDJson = 1, + EventStream = 2, + JsonSequence = 3 } } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/StreamingLogger.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/StreamingLogger.cs index 935812f17d7..96050029c59 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/StreamingLogger.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/StreamingLogger.cs @@ -46,6 +46,8 @@ public sealed class StreamingLogger : ILogger private readonly LogFormat _logFormat; private readonly LogLevel? _logLevel; + public const byte JsonSequenceRecordSeparator = 0x1E; + public StreamingLogger(string category, Stream outputStream, LogFormat format, LogLevel? logLevel) { _outputStream = outputStream; @@ -67,27 +69,36 @@ public IDisposable BeginScope(TState state) public void Log(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) { - if (_logFormat == LogFormat.Json) + if (_logFormat == LogFormat.NDJson) { LogJson(logLevel, eventId, state, exception, formatter); } + else if (_logFormat == LogFormat.JsonSequence) + { + LogJson(logLevel, eventId, state, exception, formatter, LogFormat.JsonSequence); + } else { LogEventStream(logLevel, eventId, state, exception, formatter); } } - private void LogJson(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter) + private void LogJson(LogLevel logLevel, EventId eventId, TState state, Exception exception, Func formatter, LogFormat jsonFormat = LogFormat.NDJson) { Stream outputStream = _outputStream; + if (jsonFormat == LogFormat.JsonSequence) + { + outputStream.WriteByte(JsonSequenceRecordSeparator); + } + //CONSIDER Should we cache up the loggers and writers? using (var jsonWriter = new Utf8JsonWriter(outputStream, new JsonWriterOptions { Indented = false })) { // Matches the format of JsonConsoleFormatter jsonWriter.WriteStartObject(); - jsonWriter.WriteString("Timestamp", (state is IStateWithTimestamp stateWithTimestamp) ? FormatTimestamp(stateWithTimestamp): string.Empty); + jsonWriter.WriteString("Timestamp", (state is IStateWithTimestamp stateWithTimestamp) ? FormatTimestamp(stateWithTimestamp) : string.Empty); jsonWriter.WriteString("LogLevel", logLevel.ToString()); jsonWriter.WriteNumber("EventId", eventId.Id); // EventId.Name is optional; use empty string if it is null as this @@ -132,7 +143,9 @@ private void LogJson(LogLevel logLevel, EventId eventId, TState state, E jsonWriter.Flush(); } + // JSON Sequence and NDJson both use newline as the end character outputStream.WriteByte((byte)'\n'); + outputStream.Flush(); } diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClient.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClient.cs index 6a73351f49e..2677a95fc22 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClient.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClient.cs @@ -4,6 +4,7 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.Diagnostics.Monitoring.UnitTests.Models; +using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Extensions.Logging; using Microsoft.Net.Http.Headers; using System; @@ -199,45 +200,46 @@ await SendAndLogAsync( /// /// GET /logs/{pid}?level={logLevel}&durationSeconds={duration} /// - public Task CaptureLogsAsync(int pid, TimeSpan duration, LogLevel? logLevel, CancellationToken token) + public Task CaptureLogsAsync(int pid, TimeSpan duration, LogLevel? logLevel, LogFormat logFormat, CancellationToken token) { - return CaptureLogsAsync(pid.ToString(CultureInfo.InvariantCulture), duration, logLevel, token); + return CaptureLogsAsync(pid.ToString(CultureInfo.InvariantCulture), duration, logLevel, logFormat, token); } /// /// GET /logs/{uid}?level={logLevel}&durationSeconds={duration} /// - public Task CaptureLogsAsync(Guid uid, TimeSpan duration, LogLevel? logLevel, CancellationToken token) + public Task CaptureLogsAsync(Guid uid, TimeSpan duration, LogLevel? logLevel, LogFormat logFormat, CancellationToken token) { - return CaptureLogsAsync(uid.ToString("D"), duration, logLevel, token); + return CaptureLogsAsync(uid.ToString("D"), duration, logLevel, logFormat, token); } - private Task CaptureLogsAsync(string processKey, TimeSpan duration, LogLevel? logLevel, CancellationToken token) + private Task CaptureLogsAsync(string processKey, TimeSpan duration, LogLevel? logLevel, LogFormat logFormat, CancellationToken token) { return CaptureLogsAsync( HttpMethod.Get, CreateLogsUriString(processKey, duration, logLevel), content: null, + logFormat, token); } /// /// POST /logs/{pid}?durationSeconds={duration} /// - public Task CaptureLogsAsync(int pid, TimeSpan duration, LogsConfiguration configuration, CancellationToken token) + public Task CaptureLogsAsync(int pid, TimeSpan duration, LogsConfiguration configuration, LogFormat logFormat, CancellationToken token) { - return CaptureLogsAsync(pid.ToString(CultureInfo.InvariantCulture), duration, configuration, token); + return CaptureLogsAsync(pid.ToString(CultureInfo.InvariantCulture), duration, configuration, logFormat, token); } /// /// POST /logs/{uid}?durationSeconds={duration} /// - public Task CaptureLogsAsync(Guid uid, TimeSpan duration, LogsConfiguration configuration, CancellationToken token) + public Task CaptureLogsAsync(Guid uid, TimeSpan duration, LogsConfiguration configuration, LogFormat logFormat, CancellationToken token) { - return CaptureLogsAsync(uid.ToString("D"), duration, configuration, token); + return CaptureLogsAsync(uid.ToString("D"), duration, configuration, logFormat, token); } - private Task CaptureLogsAsync(string processKey, TimeSpan duration, LogsConfiguration configuration, CancellationToken token) + private Task CaptureLogsAsync(string processKey, TimeSpan duration, LogsConfiguration configuration, LogFormat logFormat, CancellationToken token) { JsonSerializerOptions options = new(); options.Converters.Add(new JsonStringEnumConverter()); @@ -247,13 +249,25 @@ private Task CaptureLogsAsync(string processKey, TimeSpan HttpMethod.Post, CreateLogsUriString(processKey, duration, logLevel: null), new StringContent(json, Encoding.UTF8, ContentTypes.ApplicationJson), + logFormat, token); } - private async Task CaptureLogsAsync(HttpMethod method, string uri, HttpContent content, CancellationToken token) + private async Task CaptureLogsAsync(HttpMethod method, string uri, HttpContent content, LogFormat logFormat, CancellationToken token) { + string contentType = ""; + + if (logFormat == LogFormat.JsonSequence) + { + contentType = ContentTypes.ApplicationJsonSequence; + } + else if (logFormat == LogFormat.NDJson) + { + contentType = ContentTypes.ApplicationNDJson; + } + using HttpRequestMessage request = new(method, uri); - request.Headers.Add(HeaderNames.Accept, ContentTypes.ApplicationNDJson); + request.Headers.Add(HeaderNames.Accept, contentType); request.Content = content; using DisposableBox responseBox = new( @@ -265,7 +279,7 @@ await SendAndLogAsync( switch (responseBox.Value.StatusCode) { case HttpStatusCode.OK: - ValidateContentType(responseBox.Value, ContentTypes.ApplicationNDJson); + ValidateContentType(responseBox.Value, contentType); return await ResponseStreamHolder.CreateAsync(responseBox).ConfigureAwait(false); case HttpStatusCode.BadRequest: ValidateContentType(responseBox.Value, ContentTypes.ApplicationProblemJson); diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClientExtensions.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClientExtensions.cs index 6b5af127eea..4d9d83fc763 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClientExtensions.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClientExtensions.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using Microsoft.Diagnostics.Monitoring.UnitTests.Models; +using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; @@ -135,35 +136,35 @@ public static async Task CaptureDumpAsync(this ApiClient c /// /// GET /logs/{pid}?level={logLevel}&durationSeconds={duration} /// - public static Task CaptureLogsAsync(this ApiClient client, int pid, TimeSpan duration, LogLevel? logLevel) + public static Task CaptureLogsAsync(this ApiClient client, int pid, TimeSpan duration, LogLevel? logLevel, LogFormat logFormat) { - return client.CaptureLogsAsync(pid, duration, logLevel, TestTimeouts.HttpApi); + return client.CaptureLogsAsync(pid, duration, logLevel, TestTimeouts.HttpApi, logFormat); } /// /// GET /logs/{pid}?level={logLevel}&durationSeconds={duration} /// - public static async Task CaptureLogsAsync(this ApiClient client, int pid, TimeSpan duration, LogLevel? logLevel, TimeSpan timeout) + public static async Task CaptureLogsAsync(this ApiClient client, int pid, TimeSpan duration, LogLevel? logLevel, TimeSpan timeout, LogFormat logFormat) { using CancellationTokenSource timeoutSource = new(timeout); - return await client.CaptureLogsAsync(pid, duration, logLevel, timeoutSource.Token); + return await client.CaptureLogsAsync(pid, duration, logLevel, logFormat, timeoutSource.Token); } /// /// POST /logs/{pid}?durationSeconds={duration} /// - public static Task CaptureLogsAsync(this ApiClient client, int pid, TimeSpan duration, LogsConfiguration configuration) + public static Task CaptureLogsAsync(this ApiClient client, int pid, TimeSpan duration, LogsConfiguration configuration, LogFormat logFormat) { - return client.CaptureLogsAsync(pid, duration, configuration, TestTimeouts.HttpApi); + return client.CaptureLogsAsync(pid, duration, configuration, TestTimeouts.HttpApi, logFormat); } /// /// POST /logs/{pid}?durationSeconds={duration} /// - public static async Task CaptureLogsAsync(this ApiClient client, int pid, TimeSpan duration, LogsConfiguration configuration, TimeSpan timeout) + public static async Task CaptureLogsAsync(this ApiClient client, int pid, TimeSpan duration, LogsConfiguration configuration, TimeSpan timeout, LogFormat logFormat) { using CancellationTokenSource timeoutSource = new(timeout); - return await client.CaptureLogsAsync(pid, duration, configuration, timeoutSource.Token); + return await client.CaptureLogsAsync(pid, duration, configuration, logFormat, timeoutSource.Token); } /// diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ContentTypes.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ContentTypes.cs index fa9e95a837f..8ec1fd9d075 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ContentTypes.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ContentTypes.cs @@ -7,6 +7,7 @@ namespace Microsoft.Diagnostics.Monitoring.UnitTests.HttpApi internal static class ContentTypes { public const string ApplicationJson = "application/json"; + public const string ApplicationJsonSequence = "application/json-seq"; public const string ApplicationNDJson = "application/x-ndjson"; public const string ApplicationOctetStream = "application/octet-stream"; public const string ApplicationProblemJson = "application/problem+json"; diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/LogsTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/LogsTests.cs index f8102e37f70..542d254b6b4 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/LogsTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/LogsTests.cs @@ -9,6 +9,7 @@ using Microsoft.Diagnostics.Monitoring.UnitTests.Models; using Microsoft.Diagnostics.Monitoring.UnitTests.Options; using Microsoft.Diagnostics.Monitoring.UnitTests.Runners; +using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using System; @@ -31,6 +32,8 @@ public class LogsTests private readonly IHttpClientFactory _httpClientFactory; private readonly ITestOutputHelper _outputHelper; + const char JsonSequenceRecordSeparator = '\u001E'; + public LogsTests(ITestOutputHelper outputHelper, ServiceProviderFixture serviceProviderFixture) { _httpClientFactory = serviceProviderFixture.ServiceProvider.GetService(); @@ -41,11 +44,14 @@ public LogsTests(ITestOutputHelper outputHelper, ServiceProviderFixture serviceP /// Tests that all log events are collected if log level set to Trace. /// [Theory] - [InlineData(DiagnosticPortConnectionMode.Connect)] + [InlineData(DiagnosticPortConnectionMode.Connect, LogFormat.JsonSequence)] + [InlineData(DiagnosticPortConnectionMode.Connect, LogFormat.NDJson)] + #if NET5_0_OR_GREATER - [InlineData(DiagnosticPortConnectionMode.Listen)] + [InlineData(DiagnosticPortConnectionMode.Listen, LogFormat.JsonSequence)] + [InlineData(DiagnosticPortConnectionMode.Listen, LogFormat.NDJson)] #endif - public Task LogsAllCategoriesTest(DiagnosticPortConnectionMode mode) + public Task LogsAllCategoriesTest(DiagnosticPortConnectionMode mode, LogFormat logFormat) { return ValidateLogsAsync( mode, @@ -76,18 +82,21 @@ public Task LogsAllCategoriesTest(DiagnosticPortConnectionMode mode) ValidateEntry(Category3ErrorEntry, await reader.ReadAsync()); ValidateEntry(Category3CriticalEntry, await reader.ReadAsync()); Assert.False(await reader.WaitToReadAsync()); - }); + }, + logFormat); } /// /// Tests that log events with level at or above the specified level are collected. /// [Theory] - [InlineData(DiagnosticPortConnectionMode.Connect)] + [InlineData(DiagnosticPortConnectionMode.Connect, LogFormat.JsonSequence)] + [InlineData(DiagnosticPortConnectionMode.Connect, LogFormat.NDJson)] #if NET5_0_OR_GREATER - [InlineData(DiagnosticPortConnectionMode.Listen)] + [InlineData(DiagnosticPortConnectionMode.Listen, LogFormat.JsonSequence)] + [InlineData(DiagnosticPortConnectionMode.Listen, LogFormat.NDJson)] #endif - public Task LogsDefaultLevelTest(DiagnosticPortConnectionMode mode) + public Task LogsDefaultLevelTest(DiagnosticPortConnectionMode mode, LogFormat logFormat) { return ValidateLogsAsync( mode, @@ -104,7 +113,8 @@ public Task LogsDefaultLevelTest(DiagnosticPortConnectionMode mode) ValidateEntry(Category3ErrorEntry, await reader.ReadAsync()); ValidateEntry(Category3CriticalEntry, await reader.ReadAsync()); Assert.False(await reader.WaitToReadAsync()); - }); + }, + logFormat); } /// @@ -112,11 +122,13 @@ public Task LogsDefaultLevelTest(DiagnosticPortConnectionMode mode) /// at the log level specified in the request body. /// [Theory] - [InlineData(DiagnosticPortConnectionMode.Connect)] + [InlineData(DiagnosticPortConnectionMode.Connect, LogFormat.JsonSequence)] + [InlineData(DiagnosticPortConnectionMode.Connect, LogFormat.NDJson)] #if NET5_0_OR_GREATER - [InlineData(DiagnosticPortConnectionMode.Listen)] + [InlineData(DiagnosticPortConnectionMode.Listen, LogFormat.JsonSequence)] + [InlineData(DiagnosticPortConnectionMode.Listen, LogFormat.NDJson)] #endif - public Task LogsDefaultLevelFallbackTest(DiagnosticPortConnectionMode mode) + public Task LogsDefaultLevelFallbackTest(DiagnosticPortConnectionMode mode, LogFormat logFormat) { return ValidateLogsAsync( mode, @@ -143,18 +155,21 @@ public Task LogsDefaultLevelFallbackTest(DiagnosticPortConnectionMode mode) ValidateEntry(Category3ErrorEntry, await reader.ReadAsync()); ValidateEntry(Category3CriticalEntry, await reader.ReadAsync()); Assert.False(await reader.WaitToReadAsync()); - }); + }, + logFormat); } /// /// Test that LogLevel.None is not supported as the level query parameter. /// [Theory] - [InlineData(DiagnosticPortConnectionMode.Connect)] + [InlineData(DiagnosticPortConnectionMode.Connect, LogFormat.JsonSequence)] + [InlineData(DiagnosticPortConnectionMode.Connect, LogFormat.NDJson)] #if NET5_0_OR_GREATER - [InlineData(DiagnosticPortConnectionMode.Listen)] + [InlineData(DiagnosticPortConnectionMode.Listen, LogFormat.JsonSequence)] + [InlineData(DiagnosticPortConnectionMode.Listen, LogFormat.NDJson)] #endif - public Task LogsDefaultLevelNoneNotSupportedViaQueryTest(DiagnosticPortConnectionMode mode) + public Task LogsDefaultLevelNoneNotSupportedViaQueryTest(DiagnosticPortConnectionMode mode, LogFormat logFormat) { return ScenarioRunner.SingleTarget( _outputHelper, @@ -169,7 +184,8 @@ public Task LogsDefaultLevelNoneNotSupportedViaQueryTest(DiagnosticPortConnectio using ResponseStreamHolder _ = await client.CaptureLogsAsync( runner.ProcessId, TestTimeouts.LogsDuration, - LogLevel.None); + LogLevel.None, + logFormat); }); Assert.Equal(HttpStatusCode.BadRequest, exception.StatusCode); Assert.Equal(StatusCodes.Status400BadRequest, exception.Details.Status); @@ -183,11 +199,13 @@ public Task LogsDefaultLevelNoneNotSupportedViaQueryTest(DiagnosticPortConnectio /// Test that LogLevel.None is not supported as the default log level in the request body. /// [Theory] - [InlineData(DiagnosticPortConnectionMode.Connect)] + [InlineData(DiagnosticPortConnectionMode.Connect, LogFormat.JsonSequence)] + [InlineData(DiagnosticPortConnectionMode.Connect, LogFormat.NDJson)] #if NET5_0_OR_GREATER - [InlineData(DiagnosticPortConnectionMode.Listen)] + [InlineData(DiagnosticPortConnectionMode.Listen, LogFormat.JsonSequence)] + [InlineData(DiagnosticPortConnectionMode.Listen, LogFormat.NDJson)] #endif - public Task LogsDefaultLevelNoneNotSupportedViaBodyTest(DiagnosticPortConnectionMode mode) + public Task LogsDefaultLevelNoneNotSupportedViaBodyTest(DiagnosticPortConnectionMode mode, LogFormat logFormat) { return ScenarioRunner.SingleTarget( _outputHelper, @@ -202,7 +220,8 @@ public Task LogsDefaultLevelNoneNotSupportedViaBodyTest(DiagnosticPortConnection using ResponseStreamHolder _ = await client.CaptureLogsAsync( runner.ProcessId, TestTimeouts.LogsDuration, - new LogsConfiguration() { LogLevel = LogLevel.None }); + new LogsConfiguration() { LogLevel = LogLevel.None }, + logFormat); }); Assert.Equal(HttpStatusCode.BadRequest, exception.StatusCode); Assert.Equal(StatusCodes.Status400BadRequest, exception.Details.Status); @@ -216,11 +235,13 @@ public Task LogsDefaultLevelNoneNotSupportedViaBodyTest(DiagnosticPortConnection /// Test that log events are collected for the categories and levels specified by the application. /// [Theory] - [InlineData(DiagnosticPortConnectionMode.Connect)] + [InlineData(DiagnosticPortConnectionMode.Connect, LogFormat.JsonSequence)] + [InlineData(DiagnosticPortConnectionMode.Connect, LogFormat.NDJson)] #if NET5_0_OR_GREATER - [InlineData(DiagnosticPortConnectionMode.Listen)] + [InlineData(DiagnosticPortConnectionMode.Listen, LogFormat.JsonSequence)] + [InlineData(DiagnosticPortConnectionMode.Listen, LogFormat.NDJson)] #endif - public Task LogsUseAppFiltersViaQueryTest(DiagnosticPortConnectionMode mode) + public Task LogsUseAppFiltersViaQueryTest(DiagnosticPortConnectionMode mode, LogFormat logFormat) { return ValidateLogsAsync( mode, @@ -240,18 +261,21 @@ public Task LogsUseAppFiltersViaQueryTest(DiagnosticPortConnectionMode mode) ValidateEntry(Category3ErrorEntry, await reader.ReadAsync()); ValidateEntry(Category3CriticalEntry, await reader.ReadAsync()); Assert.False(await reader.WaitToReadAsync()); - }); + }, + logFormat); } /// /// Test that log events are collected for the categories and levels specified by the application. /// [Theory] - [InlineData(DiagnosticPortConnectionMode.Connect)] + [InlineData(DiagnosticPortConnectionMode.Connect, LogFormat.JsonSequence)] + [InlineData(DiagnosticPortConnectionMode.Connect, LogFormat.NDJson)] #if NET5_0_OR_GREATER - [InlineData(DiagnosticPortConnectionMode.Listen)] + [InlineData(DiagnosticPortConnectionMode.Listen, LogFormat.JsonSequence)] + [InlineData(DiagnosticPortConnectionMode.Listen, LogFormat.NDJson)] #endif - public Task LogsUseAppFiltersViaBodyTest(DiagnosticPortConnectionMode mode) + public Task LogsUseAppFiltersViaBodyTest(DiagnosticPortConnectionMode mode, LogFormat logFormat) { return ValidateLogsAsync( mode, @@ -275,7 +299,8 @@ public Task LogsUseAppFiltersViaBodyTest(DiagnosticPortConnectionMode mode) ValidateEntry(Category3ErrorEntry, await reader.ReadAsync()); ValidateEntry(Category3CriticalEntry, await reader.ReadAsync()); Assert.False(await reader.WaitToReadAsync()); - }); + }, + logFormat); } /// @@ -283,11 +308,13 @@ public Task LogsUseAppFiltersViaBodyTest(DiagnosticPortConnectionMode mode) /// and for the categories and levels specified in the filter specs. /// [Theory] - [InlineData(DiagnosticPortConnectionMode.Connect)] + [InlineData(DiagnosticPortConnectionMode.Connect, LogFormat.JsonSequence)] + [InlineData(DiagnosticPortConnectionMode.Connect, LogFormat.NDJson)] #if NET5_0_OR_GREATER - [InlineData(DiagnosticPortConnectionMode.Listen)] + [InlineData(DiagnosticPortConnectionMode.Listen, LogFormat.JsonSequence)] + [InlineData(DiagnosticPortConnectionMode.Listen, LogFormat.NDJson)] #endif - public Task LogsUseAppFiltersAndFilterSpecsTest(DiagnosticPortConnectionMode mode) + public Task LogsUseAppFiltersAndFilterSpecsTest(DiagnosticPortConnectionMode mode, LogFormat logFormat) { return ValidateLogsAsync( mode, @@ -317,18 +344,21 @@ public Task LogsUseAppFiltersAndFilterSpecsTest(DiagnosticPortConnectionMode mod ValidateEntry(Category3ErrorEntry, await reader.ReadAsync()); ValidateEntry(Category3CriticalEntry, await reader.ReadAsync()); Assert.False(await reader.WaitToReadAsync()); - }); + }, + logFormat); } /// /// Test that log events are collected for wildcard categories. /// [Theory] - [InlineData(DiagnosticPortConnectionMode.Connect)] + [InlineData(DiagnosticPortConnectionMode.Connect, LogFormat.JsonSequence)] + [InlineData(DiagnosticPortConnectionMode.Connect, LogFormat.NDJson)] #if NET5_0_OR_GREATER - [InlineData(DiagnosticPortConnectionMode.Listen)] + [InlineData(DiagnosticPortConnectionMode.Listen, LogFormat.JsonSequence)] + [InlineData(DiagnosticPortConnectionMode.Listen, LogFormat.NDJson)] #endif - public Task LogsWildcardTest(DiagnosticPortConnectionMode mode) + public Task LogsWildcardTest(DiagnosticPortConnectionMode mode, LogFormat logFormat) { return ValidateLogsAsync( mode, @@ -360,13 +390,15 @@ public Task LogsWildcardTest(DiagnosticPortConnectionMode mode) ValidateEntry(Category3ErrorEntry, await reader.ReadAsync()); ValidateEntry(Category3CriticalEntry, await reader.ReadAsync()); Assert.False(await reader.WaitToReadAsync()); - }); + }, + logFormat); } private Task ValidateLogsAsync( DiagnosticPortConnectionMode mode, LogLevel? logLevel, - Func, Task> callback) + Func, Task> callback, + LogFormat logFormat) { return ScenarioRunner.SingleTarget( _outputHelper, @@ -375,14 +407,16 @@ private Task ValidateLogsAsync( TestAppScenarios.Logger.Name, appValidate: (runner, client) => ValidateResponseStream( runner, - client.CaptureLogsAsync(runner.ProcessId, TestTimeouts.LogsDuration, logLevel), - callback)); + client.CaptureLogsAsync(runner.ProcessId, TestTimeouts.LogsDuration, logLevel, logFormat), + callback, + logFormat)); } private Task ValidateLogsAsync( DiagnosticPortConnectionMode mode, LogsConfiguration configuration, - Func, Task> callback) + Func, Task> callback, + LogFormat logFormat) { return ScenarioRunner.SingleTarget( _outputHelper, @@ -391,11 +425,12 @@ private Task ValidateLogsAsync( TestAppScenarios.Logger.Name, appValidate: (runner, client) => ValidateResponseStream( runner, - client.CaptureLogsAsync(runner.ProcessId, TestTimeouts.LogsDuration, configuration), - callback)); + client.CaptureLogsAsync(runner.ProcessId, TestTimeouts.LogsDuration, configuration, logFormat), + callback, + logFormat)); } - private async Task ValidateResponseStream(AppRunner runner, Task holderTask, Func, Task> callback) + private async Task ValidateResponseStream(AppRunner runner, Task holderTask, Func, Task> callback, LogFormat logFormat) { Assert.NotNull(runner); Assert.NotNull(holderTask); @@ -437,8 +472,18 @@ private async Task ValidateResponseStream(AppRunner runner, Task 1); + Assert.Equal(JsonSequenceRecordSeparator, line[0]); + Assert.NotEqual(JsonSequenceRecordSeparator, line[1]); + + line = line.TrimStart(JsonSequenceRecordSeparator); + } + _outputHelper.WriteLine("Log entry: {0}", line); try { From a915a232fc9964a3ec1b06dc0fe51f8327584eeb Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 23 Jun 2021 12:47:10 +0000 Subject: [PATCH 098/185] Update dependencies from https://github.com/dotnet/diagnostics build 20210622.2 (#484) [main] Update dependencies from dotnet/diagnostics --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 4db493380b8..3233358f924 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,11 +4,11 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics 3451a6dfa5ee3d1e8d0e2c3af7d4ced7f2af0129 - + https://github.com/dotnet/diagnostics 3451a6dfa5ee3d1e8d0e2c3af7d4ced7f2af0129 diff --git a/eng/Versions.props b/eng/Versions.props index 9244988a223..4aa685851ba 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-preview.7.21321.7 - 5.0.0-preview.21321.1 - 5.0.0-preview.21321.1 + 5.0.0-preview.21322.2 + 5.0.0-preview.21322.2 6.0.0-preview.7.21321.15 From 2107f9251957d90fee1fbc0ab831032a81dd8adc Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 23 Jun 2021 13:06:44 +0000 Subject: [PATCH 099/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210622.13 (#487) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 3233358f924..afd2ef5b898 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - ab87c90db386a5c442e1299b8dbc24a2d37a3754 + ffe00732d04bef43668077e6eaa1b5ce484fdafa https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 4aa685851ba..ed473045125 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21321.1 - 6.0.0-preview.7.21321.7 + 6.0.0-preview.7.21322.13 5.0.0-preview.21322.2 5.0.0-preview.21322.2 From 591c3958058aa12affc9433f9f86ac3f3346245e Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 23 Jun 2021 15:19:11 +0000 Subject: [PATCH 100/185] Update dependencies from https://github.com/dotnet/arcade build 20210621.2 (#485) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- global.json | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index afd2ef5b898..3d7593921ac 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -14,13 +14,13 @@ - + https://github.com/dotnet/arcade - 36b148348ee8312f6369c0c56b0d0fe07deec603 + 28a6403ee97077256fcdc60f599f0ad9e38e3cfa - + https://github.com/dotnet/arcade - 36b148348ee8312f6369c0c56b0d0fe07deec603 + 28a6403ee97077256fcdc60f599f0ad9e38e3cfa https://github.com/dotnet/symstore diff --git a/eng/Versions.props b/eng/Versions.props index ed473045125..e867a36548d 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -27,7 +27,7 @@ --> - 6.0.0-beta.21321.1 + 6.0.0-beta.21321.2 6.0.0-preview.7.21322.13 diff --git a/global.json b/global.json index 3b8d2ef6f57..0cda75d1ac8 100644 --- a/global.json +++ b/global.json @@ -16,6 +16,6 @@ }, "msbuild-sdks": { "Microsoft.Build.NoTargets": "2.0.1", - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21321.1" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21321.2" } } From 21734c787a02ca57673a8ed1ca493c3d298aa3dd Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 23 Jun 2021 15:28:11 +0000 Subject: [PATCH 101/185] Update dependencies from https://github.com/dotnet/runtime build 20210623.1 (#486) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 3d7593921ac..7d7a304dcea 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore ffe00732d04bef43668077e6eaa1b5ce484fdafa - + https://github.com/dotnet/runtime - 2a43c07bb82113a029090730d8ca001a68b22c05 + 97de5c5aff67892ae66fe65d1da971affe59bd76 diff --git a/eng/Versions.props b/eng/Versions.props index e867a36548d..64f08c9167e 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21322.2 5.0.0-preview.21322.2 - 6.0.0-preview.7.21321.15 + 6.0.0-preview.7.21323.1 1.0.215101 From a27b4891ececf0e892aaa1f96a106ae03063be23 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 24 Jun 2021 13:16:18 +0000 Subject: [PATCH 102/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210623.6 (#495) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 7d7a304dcea..af1e0f1c0ed 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - ffe00732d04bef43668077e6eaa1b5ce484fdafa + 7b28c2b572cf32cf3c874d637ca8337a3b459830 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 64f08c9167e..a84c05b4988 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21321.2 - 6.0.0-preview.7.21322.13 + 6.0.0-preview.7.21323.6 5.0.0-preview.21322.2 5.0.0-preview.21322.2 From a4e462d6730b6af2538596f2d4436a9180b0e658 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 24 Jun 2021 13:21:13 +0000 Subject: [PATCH 103/185] Update dependencies from https://github.com/dotnet/runtime build 20210624.1 (#494) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index af1e0f1c0ed..2eb6ec3cee8 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 7b28c2b572cf32cf3c874d637ca8337a3b459830 - + https://github.com/dotnet/runtime - 97de5c5aff67892ae66fe65d1da971affe59bd76 + 7833828914a42f8c99dfa6f18ccd47f99dc2b56e diff --git a/eng/Versions.props b/eng/Versions.props index a84c05b4988..e0073bb4829 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21322.2 5.0.0-preview.21322.2 - 6.0.0-preview.7.21323.1 + 6.0.0-preview.7.21324.1 1.0.215101 From 89255a8e579e644be3738daaa96eb0aa6e3d7fd5 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 25 Jun 2021 03:52:37 +0000 Subject: [PATCH 104/185] Update dependencies from https://github.com/dotnet/arcade build 20210623.1 (#493) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- global.json | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 2eb6ec3cee8..c80e3250a56 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -14,13 +14,13 @@ - + https://github.com/dotnet/arcade - 28a6403ee97077256fcdc60f599f0ad9e38e3cfa + 1685a12f35cfb396f9352d63736eb675673b0e20 - + https://github.com/dotnet/arcade - 28a6403ee97077256fcdc60f599f0ad9e38e3cfa + 1685a12f35cfb396f9352d63736eb675673b0e20 https://github.com/dotnet/symstore diff --git a/eng/Versions.props b/eng/Versions.props index e0073bb4829..d1d8189d715 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -27,7 +27,7 @@ --> - 6.0.0-beta.21321.2 + 6.0.0-beta.21323.1 6.0.0-preview.7.21323.6 diff --git a/global.json b/global.json index 0cda75d1ac8..53db7137a26 100644 --- a/global.json +++ b/global.json @@ -16,6 +16,6 @@ }, "msbuild-sdks": { "Microsoft.Build.NoTargets": "2.0.1", - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21321.2" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21323.1" } } From 9e18bcc0e1f4119b5635d82d6d357c735c9da22b Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 25 Jun 2021 03:57:26 +0000 Subject: [PATCH 105/185] Update dependencies from https://github.com/dotnet/diagnostics build 20210623.1 (#492) [main] Update dependencies from dotnet/diagnostics --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index c80e3250a56..056f25cd61c 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics - 3451a6dfa5ee3d1e8d0e2c3af7d4ced7f2af0129 + 296bda64b6bc156cf44f1984ceaed4baaf4e135d - + https://github.com/dotnet/diagnostics - 3451a6dfa5ee3d1e8d0e2c3af7d4ced7f2af0129 + 296bda64b6bc156cf44f1984ceaed4baaf4e135d diff --git a/eng/Versions.props b/eng/Versions.props index d1d8189d715..e22f78b0e36 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-preview.7.21323.6 - 5.0.0-preview.21322.2 - 5.0.0-preview.21322.2 + 5.0.0-preview.21323.1 + 5.0.0-preview.21323.1 6.0.0-preview.7.21324.1 From 214b1d060ace0a4a773c6976acf172c42da40170 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 25 Jun 2021 13:00:43 +0000 Subject: [PATCH 106/185] Update dependencies from https://github.com/dotnet/runtime build 20210624.24 (#499) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 056f25cd61c..fa80a7f48c6 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 7b28c2b572cf32cf3c874d637ca8337a3b459830 - + https://github.com/dotnet/runtime - 7833828914a42f8c99dfa6f18ccd47f99dc2b56e + 881e90231b93652acde39bea946c6075a71d5ddc diff --git a/eng/Versions.props b/eng/Versions.props index e22f78b0e36..dced931a696 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21323.1 5.0.0-preview.21323.1 - 6.0.0-preview.7.21324.1 + 6.0.0-preview.7.21324.24 1.0.215101 From 62c25553a41d95e913feb3d02a9023b108c750ba Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 25 Jun 2021 13:00:51 +0000 Subject: [PATCH 107/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210624.13 (#500) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index fa80a7f48c6..b68d46a7522 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - 7b28c2b572cf32cf3c874d637ca8337a3b459830 + 46ef939508a2c733104726a6c744368446883dc6 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index dced931a696..b2e00fe002e 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21323.1 - 6.0.0-preview.7.21323.6 + 6.0.0-preview.7.21324.13 5.0.0-preview.21323.1 5.0.0-preview.21323.1 From 3303b477fe3e9ef60dcc038c990cdfba278c0410 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 25 Jun 2021 19:52:02 +0000 Subject: [PATCH 108/185] Update dependencies from https://github.com/dotnet/diagnostics build 20210624.1 (#497) [main] Update dependencies from dotnet/diagnostics --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index b68d46a7522..becab30779a 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics - 296bda64b6bc156cf44f1984ceaed4baaf4e135d + f7d2b85037e557bab37db8b68e0da9b11ae41c0d - + https://github.com/dotnet/diagnostics - 296bda64b6bc156cf44f1984ceaed4baaf4e135d + f7d2b85037e557bab37db8b68e0da9b11ae41c0d diff --git a/eng/Versions.props b/eng/Versions.props index b2e00fe002e..51a0035608d 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-preview.7.21324.13 - 5.0.0-preview.21323.1 - 5.0.0-preview.21323.1 + 5.0.0-preview.21324.1 + 5.0.0-preview.21324.1 6.0.0-preview.7.21324.24 From 5a015bee1995651090300a64db317516a6412a7b Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 26 Jun 2021 12:36:10 +0000 Subject: [PATCH 109/185] Update dependencies from https://github.com/dotnet/diagnostics build 20210625.1 (#502) [main] Update dependencies from dotnet/diagnostics --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index becab30779a..4bf13f84444 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics - f7d2b85037e557bab37db8b68e0da9b11ae41c0d + 6f48c2ae749c29b687af0353e6c2a9590d7e3d22 - + https://github.com/dotnet/diagnostics - f7d2b85037e557bab37db8b68e0da9b11ae41c0d + 6f48c2ae749c29b687af0353e6c2a9590d7e3d22 diff --git a/eng/Versions.props b/eng/Versions.props index 51a0035608d..b4f6dec4390 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-preview.7.21324.13 - 5.0.0-preview.21324.1 - 5.0.0-preview.21324.1 + 5.0.0-preview.21325.1 + 5.0.0-preview.21325.1 6.0.0-preview.7.21324.24 From beb231e3b8b75880792428fdadffd4b3e752ebed Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 26 Jun 2021 12:49:19 +0000 Subject: [PATCH 110/185] Update dependencies from https://github.com/dotnet/runtime build 20210626.1 (#503) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 4bf13f84444..5930a7ba773 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 46ef939508a2c733104726a6c744368446883dc6 - + https://github.com/dotnet/runtime - 881e90231b93652acde39bea946c6075a71d5ddc + c7e37b1f4101cab534b2f0d87652154274cb30d3 diff --git a/eng/Versions.props b/eng/Versions.props index b4f6dec4390..693ccd9980d 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21325.1 5.0.0-preview.21325.1 - 6.0.0-preview.7.21324.24 + 6.0.0-preview.7.21326.1 1.0.215101 From 22fdf6cdbb2de60f2b9f29efc1988d3a84ebf201 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 26 Jun 2021 12:49:28 +0000 Subject: [PATCH 111/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210625.3 (#504) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 5930a7ba773..e4e907fd8c8 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - 46ef939508a2c733104726a6c744368446883dc6 + 2af293dc72625b865fa7fcad5aeb510df46386bd https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 693ccd9980d..4f6b15d0acd 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21323.1 - 6.0.0-preview.7.21324.13 + 6.0.0-preview.7.21325.3 5.0.0-preview.21325.1 5.0.0-preview.21325.1 From 4324bf158997cb7037ba08ca8437336471504a98 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sun, 27 Jun 2021 12:46:28 +0000 Subject: [PATCH 112/185] Update dependencies from https://github.com/dotnet/runtime build 20210626.8 (#505) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index e4e907fd8c8..b59661aa7f2 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 2af293dc72625b865fa7fcad5aeb510df46386bd - + https://github.com/dotnet/runtime - c7e37b1f4101cab534b2f0d87652154274cb30d3 + 02f70d0b903422282cd7ba8037de6b66ea0b7a2d diff --git a/eng/Versions.props b/eng/Versions.props index 4f6b15d0acd..e2428240e8a 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21325.1 5.0.0-preview.21325.1 - 6.0.0-preview.7.21326.1 + 6.0.0-preview.7.21326.8 1.0.215101 From 77c30a570573c1c6640517735c53971edf028a10 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 28 Jun 2021 12:50:30 +0000 Subject: [PATCH 113/185] Update dependencies from https://github.com/dotnet/runtime build 20210628.2 (#506) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index b59661aa7f2..a1452ce5d70 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 2af293dc72625b865fa7fcad5aeb510df46386bd - + https://github.com/dotnet/runtime - 02f70d0b903422282cd7ba8037de6b66ea0b7a2d + 91599fff26619cb8bccb7b39c39590e7cd9a4379 diff --git a/eng/Versions.props b/eng/Versions.props index e2428240e8a..05f580e48fe 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21325.1 5.0.0-preview.21325.1 - 6.0.0-preview.7.21326.8 + 6.0.0-preview.7.21328.2 1.0.215101 From 002f1287d7e032114a67116497d85489c456e3f6 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 28 Jun 2021 16:48:10 +0000 Subject: [PATCH 114/185] Update dependencies from https://github.com/dotnet/arcade build 20210624.3 (#498) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- eng/common/tools.ps1 | 11 ++++++++++- global.json | 2 +- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index a1452ce5d70..51a87ddfb56 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -14,13 +14,13 @@ - + https://github.com/dotnet/arcade - 1685a12f35cfb396f9352d63736eb675673b0e20 + a68ec1edf328e737b31a09cb49e1929c28e91d0c - + https://github.com/dotnet/arcade - 1685a12f35cfb396f9352d63736eb675673b0e20 + a68ec1edf328e737b31a09cb49e1929c28e91d0c https://github.com/dotnet/symstore diff --git a/eng/Versions.props b/eng/Versions.props index 05f580e48fe..2b627367a64 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -27,7 +27,7 @@ --> - 6.0.0-beta.21323.1 + 6.0.0-beta.21324.3 6.0.0-preview.7.21325.3 diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1 index 5619c7aaee1..7942ffaf4cb 100644 --- a/eng/common/tools.ps1 +++ b/eng/common/tools.ps1 @@ -378,7 +378,16 @@ function InitializeVisualStudioMSBuild([bool]$install, [object]$vsRequirements = } $msbuildVersionDir = if ([int]$vsMajorVersion -lt 16) { "$vsMajorVersion.0" } else { "Current" } - return $global:_MSBuildExe = Join-Path $vsInstallDir "MSBuild\$msbuildVersionDir\Bin\msbuild.exe" + + $local:BinFolder = Join-Path $vsInstallDir "MSBuild\$msbuildVersionDir\Bin" + $local:Prefer64bit = if ($vsRequirements.Prefer64bit) { $vsRequirements.Prefer64bit } else { $false } + if ($local:Prefer64bit -and (Test-Path(Join-Path $local:BinFolder "amd64"))) { + $global:_MSBuildExe = Join-Path $local:BinFolder "amd64\msbuild.exe" + } else { + $global:_MSBuildExe = Join-Path $local:BinFolder "msbuild.exe" + } + + return $global:_MSBuildExe } function InitializeVisualStudioEnvironmentVariables([string] $vsInstallDir, [string] $vsMajorVersion) { diff --git a/global.json b/global.json index 53db7137a26..77313c62ecb 100644 --- a/global.json +++ b/global.json @@ -16,6 +16,6 @@ }, "msbuild-sdks": { "Microsoft.Build.NoTargets": "2.0.1", - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21323.1" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21324.3" } } From e96321190a6b1abb03f9afbc4c1464483d9e95e2 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 29 Jun 2021 14:35:41 +0000 Subject: [PATCH 115/185] Update dependencies from https://github.com/dotnet/diagnostics build 20210628.1 (#507) [main] Update dependencies from dotnet/diagnostics --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 51a87ddfb56..1ee1b04fcec 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics - 6f48c2ae749c29b687af0353e6c2a9590d7e3d22 + dfb97e8c4561f5ef40b7853faa6f1ca9b5d8f8c9 - + https://github.com/dotnet/diagnostics - 6f48c2ae749c29b687af0353e6c2a9590d7e3d22 + dfb97e8c4561f5ef40b7853faa6f1ca9b5d8f8c9 diff --git a/eng/Versions.props b/eng/Versions.props index 2b627367a64..f88143e6f38 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-preview.7.21325.3 - 5.0.0-preview.21325.1 - 5.0.0-preview.21325.1 + 5.0.0-preview.21328.1 + 5.0.0-preview.21328.1 6.0.0-preview.7.21328.2 From fa502254a56ccd063c8db98517990ba10a179de4 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 29 Jun 2021 14:39:57 +0000 Subject: [PATCH 116/185] Update dependencies from https://github.com/dotnet/runtime build 20210629.1 (#509) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 1ee1b04fcec..42f8e48fc66 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 2af293dc72625b865fa7fcad5aeb510df46386bd - + https://github.com/dotnet/runtime - 91599fff26619cb8bccb7b39c39590e7cd9a4379 + 969840ecd1964656d5686fa861110d905cd0d6c9 diff --git a/eng/Versions.props b/eng/Versions.props index f88143e6f38..388576b8c4f 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21328.1 5.0.0-preview.21328.1 - 6.0.0-preview.7.21328.2 + 6.0.0-preview.7.21329.1 1.0.215101 From e47eda034111b21b2c3ee27b69f6230c1f4911fb Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 29 Jun 2021 14:45:09 +0000 Subject: [PATCH 117/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210628.9 (#510) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 42f8e48fc66..f4f5f0d0b05 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - 2af293dc72625b865fa7fcad5aeb510df46386bd + 348b810d286fd2258aa763d6eda667a83ff972dc https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 388576b8c4f..f1f69f8d4d0 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21324.3 - 6.0.0-preview.7.21325.3 + 6.0.0-preview.7.21328.9 5.0.0-preview.21328.1 5.0.0-preview.21328.1 From 6ca398f4108aabaaea5ff9a36176f96649cf77dd Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 30 Jun 2021 12:41:12 +0000 Subject: [PATCH 118/185] [main] Update dependencies from dotnet/arcade (#508) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- eng/common/tools.ps1 | 2 +- global.json | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index f4f5f0d0b05..1e777ddc0d6 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -14,13 +14,13 @@ - + https://github.com/dotnet/arcade - a68ec1edf328e737b31a09cb49e1929c28e91d0c + 6b9d24236d8d1906284e6cb6c28e3fe93a69b7d2 - + https://github.com/dotnet/arcade - a68ec1edf328e737b31a09cb49e1929c28e91d0c + 6b9d24236d8d1906284e6cb6c28e3fe93a69b7d2 https://github.com/dotnet/symstore diff --git a/eng/Versions.props b/eng/Versions.props index f1f69f8d4d0..19aaf26754f 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -27,7 +27,7 @@ --> - 6.0.0-beta.21324.3 + 6.0.0-beta.21329.8 6.0.0-preview.7.21328.9 diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1 index 7942ffaf4cb..4b255203249 100644 --- a/eng/common/tools.ps1 +++ b/eng/common/tools.ps1 @@ -380,7 +380,7 @@ function InitializeVisualStudioMSBuild([bool]$install, [object]$vsRequirements = $msbuildVersionDir = if ([int]$vsMajorVersion -lt 16) { "$vsMajorVersion.0" } else { "Current" } $local:BinFolder = Join-Path $vsInstallDir "MSBuild\$msbuildVersionDir\Bin" - $local:Prefer64bit = if ($vsRequirements.Prefer64bit) { $vsRequirements.Prefer64bit } else { $false } + $local:Prefer64bit = if (Get-Member -InputObject $vsRequirements -Name 'Prefer64bit') { $vsRequirements.Prefer64bit } else { $false } if ($local:Prefer64bit -and (Test-Path(Join-Path $local:BinFolder "amd64"))) { $global:_MSBuildExe = Join-Path $local:BinFolder "amd64\msbuild.exe" } else { diff --git a/global.json b/global.json index 77313c62ecb..28840b16a82 100644 --- a/global.json +++ b/global.json @@ -16,6 +16,6 @@ }, "msbuild-sdks": { "Microsoft.Build.NoTargets": "2.0.1", - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21324.3" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21329.8" } } From c9861977918d1f621848bb73e4addf6113afa5b0 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 30 Jun 2021 12:42:09 +0000 Subject: [PATCH 119/185] Update dependencies from https://github.com/dotnet/diagnostics build 20210629.1 (#512) [main] Update dependencies from dotnet/diagnostics --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 1e777ddc0d6..4f639519a41 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics - dfb97e8c4561f5ef40b7853faa6f1ca9b5d8f8c9 + a584d05969d1951a86e5d290d5654e30cd10d5aa - + https://github.com/dotnet/diagnostics - dfb97e8c4561f5ef40b7853faa6f1ca9b5d8f8c9 + a584d05969d1951a86e5d290d5654e30cd10d5aa diff --git a/eng/Versions.props b/eng/Versions.props index 19aaf26754f..059f0c36895 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-preview.7.21328.9 - 5.0.0-preview.21328.1 - 5.0.0-preview.21328.1 + 5.0.0-preview.21329.1 + 5.0.0-preview.21329.1 6.0.0-preview.7.21329.1 From 30948f8cd48490f344161e44643e9b206aed584e Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 30 Jun 2021 13:08:17 +0000 Subject: [PATCH 120/185] Update dependencies from https://github.com/dotnet/runtime build 20210630.2 (#513) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 4f639519a41..cc806d4d80d 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 348b810d286fd2258aa763d6eda667a83ff972dc - + https://github.com/dotnet/runtime - 969840ecd1964656d5686fa861110d905cd0d6c9 + ff88d1d3a022021a54fbe05949a27db29c690f0c diff --git a/eng/Versions.props b/eng/Versions.props index 059f0c36895..29618522890 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21329.1 5.0.0-preview.21329.1 - 6.0.0-preview.7.21329.1 + 6.0.0-preview.7.21330.2 1.0.215101 From a8b0a04a1a929ccd0edb22569fbd8cf49e4e8c2e Mon Sep 17 00:00:00 2001 From: kkeirstead <85592574+kkeirstead@users.noreply.github.com> Date: Wed, 30 Jun 2021 07:49:37 -0700 Subject: [PATCH 121/185] Use queries instead of path segments (#496) --- documentation/README.md | 4 +- documentation/api/README.md | 4 +- documentation/api/dump.md | 26 +- documentation/api/gcdump.md | 26 +- documentation/api/logs-custom.md | 26 +- documentation/api/logs-get.md | 26 +- documentation/api/pidvsuid.md | 4 +- .../api/{processes-env.md => process-env.md} | 20 +- .../api/{processes-get.md => process-get.md} | 20 +- documentation/api/processes.md | 4 +- documentation/api/trace-custom.md | 26 +- documentation/api/trace-get.md | 26 +- documentation/configuration.md | 24 +- documentation/egress.md | 2 +- documentation/openapi.json | 417 ++++++++++-------- documentation/setup.md | 4 +- .../Controllers/DiagController.cs | 142 ++++-- .../DiagProcessFilter.cs | 23 +- .../Models/ProcessIdentifier.cs | 3 + .../ProcessKey.cs | 21 +- .../Program.cs | 3 - .../HttpApi/ApiClient.cs | 119 +++-- .../HttpApi/ApiClientExtensions.cs | 52 ++- .../ProcessTests.cs | 76 +++- 24 files changed, 621 insertions(+), 477 deletions(-) rename documentation/api/{processes-env.md => process-env.md} (92%) rename documentation/api/{processes-get.md => process-get.md} (90%) diff --git a/documentation/README.md b/documentation/README.md index 05e30c901e0..52ec14e7b06 100644 --- a/documentation/README.md +++ b/documentation/README.md @@ -2,7 +2,7 @@ `dotnet monitor` is a tool that makes it easier to get access to diagnostics information in a dotnet process. -When running a dotnet application differences in diverse local and production environments can make collecting diagnostics artifacts (e.g., logs, traces, process dumps) challenging. `dotnet monitor` aims to simplify the process by exposing a consistent HTTP API regardless of where your application is run. +When running a dotnet application, differences in diverse local and production environments can make collecting diagnostics artifacts (e.g., logs, traces, process dumps) challenging. `dotnet monitor` aims to simplify the process by exposing a consistent HTTP API regardless of where your application is run. ## Table of contents @@ -29,4 +29,4 @@ When running a dotnet application differences in diverse local and production en - [Troubleshooting](./troubleshooting.md) - [Clone, build, and test the repo](./building.md) - [Official Build Instructions](./official-build-instructions.md) -- [Release Process](./release-process.md) \ No newline at end of file +- [Release Process](./release-process.md) diff --git a/documentation/api/README.md b/documentation/api/README.md index 561dd7e49b4..35962807221 100644 --- a/documentation/api/README.md +++ b/documentation/api/README.md @@ -7,10 +7,10 @@ The following are the root routes on the HTTP API surface. | Route | Description | |---|---| | [`/processes`](processes.md) | Gets detailed information about discoverable processes. | -| [`/dump`](dump.md) | Captures a managed dumps processes without using a debugger. | +| [`/dump`](dump.md) | Captures managed dumps of processes without using a debugger. | | [`/gcdump`](gcdump.md) | Captures GC dumps of processes. | | [`/trace`](trace.md) | Captures traces of processes without using a profiler. | | [`/metrics`](metrics.md) | Captures metrics of a process. | | [`/logs`](logs.md) | Captures logs of processes. | -The `dotnet monitor` tool is able to detect .NET Core 3.1 and .NET 5+ applications. When connecting to a .NET Core 3.1 application, some information may not be available and is called out in the documentation. \ No newline at end of file +The `dotnet monitor` tool is able to detect .NET Core 3.1 and .NET 5+ applications. When connecting to a .NET Core 3.1 application, some information may not be available and is called out in the documentation. diff --git a/documentation/api/dump.md b/documentation/api/dump.md index 0b062b1de2a..836cfb554f6 100644 --- a/documentation/api/dump.md +++ b/documentation/api/dump.md @@ -7,25 +7,7 @@ Captures a managed dump of a specified process without using a debugger. ## HTTP Route ```http -GET /dump/{pid}?type={type}&egressProvider={egressProvider} HTTP/1.1 -``` - -or - -```http -GET /dump/{uid}?type={type}&egressProvider={egressProvider} HTTP/1.1 -``` - -or - -```http -GET /dump/{name}?type={type}&egressProvider={egressProvider} HTTP/1.1 -``` - -or - -```http -GET /dump?type={type}&egressProvider={egressProvider} HTTP/1.1 +GET /dump?pid={pid}&uid={uid}&name={name}&type={type}&egressProvider={egressProvider} HTTP/1.1 ``` > **NOTE:** Process information (IDs, names, environment, etc) may change between invocations of these APIs. Processes may start or stop between API invocations, causing this information to change. @@ -70,7 +52,7 @@ Allowed schemes: ### Sample Request ```http -GET /dump/21632?type=Full HTTP/1.1 +GET /dump?pid=21632&type=Full HTTP/1.1 Host: localhost:52323 Authorization: MonitorApiKey fffffffffffffffffffffffffffffffffffffffffff= ``` @@ -78,7 +60,7 @@ Authorization: MonitorApiKey fffffffffffffffffffffffffffffffffffffffffff= or ```http -GET /dump/cd4da319-fa9e-4987-ac4e-e57b2aac248b?type=Full HTTP/1.1 +GET /dump?uid=cd4da319-fa9e-4987-ac4e-e57b2aac248b&type=Full HTTP/1.1 Host: localhost:52323 Authorization: MonitorApiKey fffffffffffffffffffffffffffffffffffffffffff= ``` @@ -111,4 +93,4 @@ See [Process ID `pid` vs Unique ID `uid`](pidvsuid.md) for clarification on when ### View the collected dump file -Dump files collected from this route can be analyzed using tools such as [dotnet-dump](https://docs.microsoft.com/dotnet/core/diagnostics/dotnet-dump) or Visual Studio. \ No newline at end of file +Dump files collected from this route can be analyzed using tools such as [dotnet-dump](https://docs.microsoft.com/dotnet/core/diagnostics/dotnet-dump) or Visual Studio. diff --git a/documentation/api/gcdump.md b/documentation/api/gcdump.md index 35f51b853ab..db66747a4f7 100644 --- a/documentation/api/gcdump.md +++ b/documentation/api/gcdump.md @@ -11,25 +11,7 @@ Captures a GC dump of a specified process. These dumps are useful for several sc ## HTTP Route ```http -GET /gcdump/{pid}&egressProvider={egressProvider} HTTP/1.1 -``` - -or - -```http -GET /gcdump/{uid}&egressProvider={egressProvider} HTTP/1.1 -``` - -or - -```http -GET /gcdump/{name}&egressProvider={egressProvider} HTTP/1.1 -``` - -or - -```http -GET /gcdump&egressProvider={egressProvider} HTTP/1.1 +GET /gcdump?pid={pid}&uid={uid}&name={name}&egressProvider={egressProvider} HTTP/1.1 ``` > **NOTE:** Process information (IDs, names, environment, etc) may change between invocations of these APIs. Processes may start or stop between API invocations, causing this information to change. @@ -73,7 +55,7 @@ Allowed schemes: ### Sample Request ```http -GET /gcdump/21632 HTTP/1.1 +GET /gcdump?pid=21632 HTTP/1.1 Host: localhost:52323 Authorization: MonitorApiKey fffffffffffffffffffffffffffffffffffffffffff= ``` @@ -81,7 +63,7 @@ Authorization: MonitorApiKey fffffffffffffffffffffffffffffffffffffffffff= or ```http -GET /gcdump/cd4da319-fa9e-4987-ac4e-e57b2aac248b HTTP/1.1 +GET /gcdump?uid=cd4da319-fa9e-4987-ac4e-e57b2aac248b HTTP/1.1 Host: localhost:52323 Authorization: MonitorApiKey fffffffffffffffffffffffffffffffffffffffffff= ``` @@ -116,4 +98,4 @@ On Windows, `.gcdump` files can be viewed in [PerfView](https://github.com/micro You can collect multiple `.gcdump`s and open them simultaneously in Visual Studio to get a comparison experience. -Reports can be generated from `.gcdump` files using the [dotnet-gcdump](https://docs.microsoft.com/dotnet/core/diagnostics/dotnet-gcdump) tool. \ No newline at end of file +Reports can be generated from `.gcdump` files using the [dotnet-gcdump](https://docs.microsoft.com/dotnet/core/diagnostics/dotnet-gcdump) tool. diff --git a/documentation/api/logs-custom.md b/documentation/api/logs-custom.md index 7aa6eaecd2b..3e220843585 100644 --- a/documentation/api/logs-custom.md +++ b/documentation/api/logs-custom.md @@ -7,25 +7,7 @@ Captures log statements that are logged to the [ILogger<> infrastructure](https: ## HTTP Route ```http -POST /logs/{pid}?durationSeconds={durationSeconds}&egressProvider={egressProvider} HTTP/1.1 -``` - -or - -```http -POST /logs/{uid}?durationSeconds={durationSeconds}&egressProvider={egressProvider} HTTP/1.1 -``` - -or - -```http -POST /logs/{name}?durationSeconds={durationSeconds}&egressProvider={egressProvider} HTTP/1.1 -``` - -or - -```http -POST /logs?durationSeconds={durationSeconds}&egressProvider={egressProvider} HTTP/1.1 +POST /logs?pid={pid}&uid={uid}&name={name}&durationSeconds={durationSeconds}&egressProvider={egressProvider} HTTP/1.1 ``` > **NOTE:** Process information (IDs, names, environment, etc) may change between invocations of these APIs. Processes may start or stop between API invocations, causing this information to change. @@ -77,7 +59,7 @@ The expected content type is `application/json`. ### Sample Request ```http -POST /logs/21632?durationSeconds=60 HTTP/1.1 +POST /logs?pid=21632&durationSeconds=60 HTTP/1.1 Host: localhost:52323 Authorization: MonitorApiKey fffffffffffffffffffffffffffffffffffffffffff= @@ -93,7 +75,7 @@ Authorization: MonitorApiKey fffffffffffffffffffffffffffffffffffffffffff= or ```http -POST /logs/cd4da319-fa9e-4987-ac4e-e57b2aac248b?durationSeconds=60 HTTP/1.1 +POST /logs?uid=cd4da319-fa9e-4987-ac4e-e57b2aac248b&durationSeconds=60 HTTP/1.1 Host: localhost:52323 Authorization: MonitorApiKey fffffffffffffffffffffffffffffffffffffffffff= @@ -136,4 +118,4 @@ data: => RequestId:0HM8M726ENU3K:0000002B, RequestPath:/, SpanId:|4791a4a7-433aa ### When to use `pid` vs `uid` -See [Process ID `pid` vs Unique ID `uid`](pidvsuid.md) for clarification on when it is best to use either parameter. \ No newline at end of file +See [Process ID `pid` vs Unique ID `uid`](pidvsuid.md) for clarification on when it is best to use either parameter. diff --git a/documentation/api/logs-get.md b/documentation/api/logs-get.md index 56a9ebc490d..d442a26f714 100644 --- a/documentation/api/logs-get.md +++ b/documentation/api/logs-get.md @@ -7,25 +7,7 @@ Captures log statements that are logged to the [ILogger<> infrastructure](https: ## HTTP Route ```http -GET /logs/{pid}?level={level}&durationSeconds={durationSeconds}&egressProvider={egressProvider} HTTP/1.1 -``` - -or - -```http -GET /logs/{uid}?level={level}&durationSeconds={durationSeconds}&egressProvider={egressProvider} HTTP/1.1 -``` - -or - -```http -GET /logs/{name}?level={level}&durationSeconds={durationSeconds}&egressProvider={egressProvider} HTTP/1.1 -``` - -or - -```http -GET /logs?level={level}&durationSeconds={durationSeconds}&egressProvider={egressProvider} HTTP/1.1 +GET /logs?pid={pid}&uid={uid}&name={name}&level={level}&durationSeconds={durationSeconds}&egressProvider={egressProvider} HTTP/1.1 ``` > **NOTE:** Process information (IDs, names, environment, etc) may change between invocations of these APIs. Processes may start or stop between API invocations, causing this information to change. @@ -72,7 +54,7 @@ Allowed schemes: ### Sample Request ```http -GET /logs/21632?level=Information&durationSeconds=60 HTTP/1.1 +GET /logs?pid=21632&level=Information&durationSeconds=60 HTTP/1.1 Host: localhost:52323 Authorization: MonitorApiKey fffffffffffffffffffffffffffffffffffffffffff= ``` @@ -80,7 +62,7 @@ Authorization: MonitorApiKey fffffffffffffffffffffffffffffffffffffffffff= or ```http -GET /logs/cd4da319-fa9e-4987-ac4e-e57b2aac248b?level=Information&durationSeconds=60 HTTP/1.1 +GET /logs?uid=cd4da319-fa9e-4987-ac4e-e57b2aac248b&level=Information&durationSeconds=60 HTTP/1.1 Host: localhost:52323 Authorization: MonitorApiKey fffffffffffffffffffffffffffffffffffffffffff= ``` @@ -118,4 +100,4 @@ data: Processing request 0b7ba879-fa80-4eb8-a87d-408f539952ca. ### When to use `pid` vs `uid` -See [Process ID `pid` vs Unique ID `uid`](pidvsuid.md) for clarification on when it is best to use either parameter. \ No newline at end of file +See [Process ID `pid` vs Unique ID `uid`](pidvsuid.md) for clarification on when it is best to use either parameter. diff --git a/documentation/api/pidvsuid.md b/documentation/api/pidvsuid.md index 4be58742846..832e94637bc 100644 --- a/documentation/api/pidvsuid.md +++ b/documentation/api/pidvsuid.md @@ -2,9 +2,9 @@ Many of the HTTP routes allow specifying either the process ID `pid` or the unique ID `uid`. Which one to use depends on the target process and the environment in which the process is running. -The `uid` value of a process is guaranteed to be unique, regardless of environment, as long is the application is running on .NET 5+. Applications running on .NET Core 3.1 will have an empty value of `00000000-0000-0000-0000-000000000000` for `uid`. +The `uid` value of a process is guaranteed to be unique, regardless of environment, as long as the application is running on .NET 5+. Applications running on .NET Core 3.1 will have an empty value of `00000000-0000-0000-0000-000000000000` for `uid`. Recommendations: - For applications running on .NET 5+, use the `uid` parameter. This is especially beneficial when running in Docker or Kubernetes, since containerized .NET applications within the same pod will likely report process IDs of 1. - For applications running on .NET Core 3.1, the `pid` parameter is the only option since .NET Core 3.1 processes have a `uid` of `00000000-0000-0000-0000-000000000000`. -- If `dotnet monitor` is configured to observe processes from only one process namespace (e.g. all containers share a single process namespace, the tool is not running in a container, etc), then it is allowable to use the `pid` parameter regardless of the runtime version. \ No newline at end of file +- If `dotnet monitor` is configured to observe processes from only one process namespace (e.g. all containers share a single process namespace, the tool is not running in a container, etc), then it is allowable to use the `pid` parameter regardless of the runtime version. diff --git a/documentation/api/processes-env.md b/documentation/api/process-env.md similarity index 92% rename from documentation/api/processes-env.md rename to documentation/api/process-env.md index 05a7596e241..bfc3ba33690 100644 --- a/documentation/api/processes-env.md +++ b/documentation/api/process-env.md @@ -5,19 +5,7 @@ Gets the environment block of a specified process. ## HTTP Route ```http -GET /processes/{pid}/env HTTP/1.1 -``` - -or - -```http -GET /processes/{uid}/env HTTP/1.1 -``` - -or - -```http -GET /processes/{name}/env HTTP/1.1 +GET /env?pid={pid}&uid={uid}&name={name} HTTP/1.1 ``` > **NOTE:** Process information (IDs, names, environment, etc) may change between invocations of these APIs. Processes may start or stop between API invocations, causing this information to change. @@ -59,7 +47,7 @@ Allowed schemes: ### Sample Request ```http -GET /processes/21632/env HTTP/1.1 +GET /env?pid=21632 HTTP/1.1 Host: localhost:52323 Authorization: MonitorApiKey fffffffffffffffffffffffffffffffffffffffffff= ``` @@ -67,7 +55,7 @@ Authorization: MonitorApiKey fffffffffffffffffffffffffffffffffffffffffff= or ```http -GET /processes/cd4da319-fa9e-4987-ac4e-e57b2aac248b/env HTTP/1.1 +GET /env?uid=cd4da319-fa9e-4987-ac4e-e57b2aac248b HTTP/1.1 Host: localhost:52323 Authorization: MonitorApiKey fffffffffffffffffffffffffffffffffffffffffff= ``` @@ -121,4 +109,4 @@ Content-Type: application/json ### When to use `pid` vs `uid` -See [Process ID `pid` vs Unique ID `uid`](pidvsuid.md) for clarification on when it is best to use either parameter. \ No newline at end of file +See [Process ID `pid` vs Unique ID `uid`](pidvsuid.md) for clarification on when it is best to use either parameter. diff --git a/documentation/api/processes-get.md b/documentation/api/process-get.md similarity index 90% rename from documentation/api/processes-get.md rename to documentation/api/process-get.md index 7bded82d241..8db8809c8b9 100644 --- a/documentation/api/processes-get.md +++ b/documentation/api/process-get.md @@ -5,19 +5,7 @@ Gets detailed information about a specified process. ## HTTP Route ```http -GET /processes/{pid} HTTP/1.1 -``` - -or - -```http -GET /processes/{uid} HTTP/1.1 -``` - -or - -```http -GET /processes/{name} HTTP/1.1 +GET /process?pid={pid}&uid={uid}&name={name} HTTP/1.1 ``` > **NOTE:** Process information (IDs, names, environment, etc) may change between invocations of these APIs. Processes may start or stop between API invocations, causing this information to change. @@ -59,7 +47,7 @@ Allowed schemes: ### Sample Request ```http -GET /processes/21632 HTTP/1.1 +GET /process?pid=21632 HTTP/1.1 Host: localhost:52323 Authorization: MonitorApiKey fffffffffffffffffffffffffffffffffffffffffff= ``` @@ -67,7 +55,7 @@ Authorization: MonitorApiKey fffffffffffffffffffffffffffffffffffffffffff= or ```http -GET /processes/cd4da319-fa9e-4987-ac4e-e57b2aac248b HTTP/1.1 +GET /process?uid=cd4da319-fa9e-4987-ac4e-e57b2aac248b HTTP/1.1 Host: localhost:52323 Authorization: MonitorApiKey fffffffffffffffffffffffffffffffffffffffffff= ``` @@ -100,4 +88,4 @@ Content-Type: application/json ### When to use `pid` vs `uid` -See [Process ID `pid` vs Unique ID `uid`](pidvsuid.md) for clarification on when it is best to use either parameter. \ No newline at end of file +See [Process ID `pid` vs Unique ID `uid`](pidvsuid.md) for clarification on when it is best to use either parameter. diff --git a/documentation/api/processes.md b/documentation/api/processes.md index 3eb08ef494e..c6b21bbcaf7 100644 --- a/documentation/api/processes.md +++ b/documentation/api/processes.md @@ -6,8 +6,8 @@ The Processes API enables enumeration of the processes that `dotnet monitor` can | Operation | Description | |---|---| -| [Get Process](processes-get.md) | Gets detailed information about a specified process. | -| [Get Process Environment](processes-env.md) | `.NET 5+` Gets the environment block of a specified process.
`.NET Core 3.1` Not supported. | +| [Get Process](process-get.md) | Gets detailed information about a specified process. | +| [Get Process Environment](process-env.md) | `.NET 5+` Gets the environment block of a specified process.
`.NET Core 3.1` Not supported. | | [List Processes](processes-list.md) | Lists the processes that are available from which diagnostic information can be obtained. | The `dotnet monitor` tool is able to detect .NET Core 3.1 and .NET 5+ applications. When connecting to a .NET Core 3.1 application, some information may not be available and is called out in the documentation. \ No newline at end of file diff --git a/documentation/api/trace-custom.md b/documentation/api/trace-custom.md index 97362f11a60..cf1cb706341 100644 --- a/documentation/api/trace-custom.md +++ b/documentation/api/trace-custom.md @@ -5,25 +5,7 @@ Captures a diagnostic trace of a process using the given set of event providers ## HTTP Route ```http -POST /trace/{pid}?durationSeconds={durationSeconds}&egressProvider={egressProvider} HTTP/1.1 -``` - -or - -```http -POST /trace/{uid}?durationSeconds={durationSeconds}&egressProvider={egressProvider} HTTP/1.1 -``` - -or - -```http -POST /trace/{name}?durationSeconds={durationSeconds}&egressProvider={egressProvider} HTTP/1.1 -``` - -or - -```http -POST /trace?durationSeconds={durationSeconds}&egressProvider={egressProvider} HTTP/1.1 +POST /trace?pid={pid}&uid={uid}&name={name}&durationSeconds={durationSeconds}&egressProvider={egressProvider} HTTP/1.1 ``` > **NOTE:** Process information (IDs, names, environment, etc) may change between invocations of these APIs. Processes may start or stop between API invocations, causing this information to change. @@ -76,7 +58,7 @@ The expected content type is `application/json`. ### Sample Request ```http -POST /trace/21632?durationSeconds=60 HTTP/1.1 +POST /trace?pid=21632&durationSeconds=60 HTTP/1.1 Host: localhost:52323 Authorization: MonitorApiKey fffffffffffffffffffffffffffffffffffffffffff= Content-Type: application/json @@ -97,7 +79,7 @@ Content-Type: application/json or ```http -POST /trace/cd4da319-fa9e-4987-ac4e-e57b2aac248b?durationSeconds=60 HTTP/1.1 +POST /trace?uid=cd4da319-fa9e-4987-ac4e-e57b2aac248b&durationSeconds=60 HTTP/1.1 Host: localhost:52323 Authorization: MonitorApiKey fffffffffffffffffffffffffffffffffffffffffff= Content-Type: application/json @@ -143,4 +125,4 @@ See [Process ID `pid` vs Unique ID `uid`](pidvsuid.md) for clarification on when On Windows, `.nettrace` files can be viewed in [PerfView](https://github.com/microsoft/perfview) for analysis or in Visual Studio. -A `.nettrace` files can be converted to another format (e.g. SpeedScope or Chromium) using the [dotnet-trace](https://docs.microsoft.com/dotnet/core/diagnostics/dotnet-trace) tool. \ No newline at end of file +A `.nettrace` files can be converted to another format (e.g. SpeedScope or Chromium) using the [dotnet-trace](https://docs.microsoft.com/dotnet/core/diagnostics/dotnet-trace) tool. diff --git a/documentation/api/trace-get.md b/documentation/api/trace-get.md index 98ada4e0716..14cc0d73c49 100644 --- a/documentation/api/trace-get.md +++ b/documentation/api/trace-get.md @@ -5,25 +5,7 @@ Captures a diagnostic trace of a process based on a predefined set of trace prof ## HTTP Route ```http -GET /trace/{pid}?profile={profile}&durationSeconds={durationSeconds}&metricsIntervalSeconds={metricsIntervalSeconds}&egressProvider={egressProvider} HTTP/1.1 -``` - -or - -```http -GET /trace/{uid}?profile={profile}&durationSeconds={durationSeconds}&metricsIntervalSeconds={metricsIntervalSeconds}&egressProvider={egressProvider} HTTP/1.1 -``` - -or - -```http -GET /trace/{name}?profile={profile}&durationSeconds={durationSeconds}&metricsIntervalSeconds={metricsIntervalSeconds}&egressProvider={egressProvider} HTTP/1.1 -``` - -or - -```http -GET /trace?profile={profile}&durationSeconds={durationSeconds}&metricsIntervalSeconds={metricsIntervalSeconds}&egressProvider={egressProvider} HTTP/1.1 +GET /trace?pid={pid}&uid={uid}&name={name}&profile={profile}&durationSeconds={durationSeconds}&metricsIntervalSeconds={metricsIntervalSeconds}&egressProvider={egressProvider} HTTP/1.1 ``` > **NOTE:** Process information (IDs, names, environment, etc) may change between invocations of these APIs. Processes may start or stop between API invocations, causing this information to change. @@ -72,7 +54,7 @@ Allowed schemes: ### Sample Request ```http -GET /trace/21632?profile=http,metrics&durationSeconds=60&metricsIntervalSeconds=5 HTTP/1.1 +GET /trace?pid=21632&profile=http,metrics&durationSeconds=60&metricsIntervalSeconds=5 HTTP/1.1 Host: localhost:52323 Authorization: MonitorApiKey fffffffffffffffffffffffffffffffffffffffffff= ``` @@ -80,7 +62,7 @@ Authorization: MonitorApiKey fffffffffffffffffffffffffffffffffffffffffff= or ```http -GET /trace/cd4da319-fa9e-4987-ac4e-e57b2aac248b?profile=http,metrics&durationSeconds=60&metricsIntervalSeconds=5 HTTP/1.1 +GET /trace?uid=cd4da319-fa9e-4987-ac4e-e57b2aac248b&profile=http,metrics&durationSeconds=60&metricsIntervalSeconds=5 HTTP/1.1 Host: localhost:52323 Authorization: MonitorApiKey fffffffffffffffffffffffffffffffffffffffffff= ``` @@ -113,4 +95,4 @@ See [Process ID `pid` vs Unique ID `uid`](pidvsuid.md) for clarification on when On Windows, `.nettrace` files can be viewed in [PerfView](https://github.com/microsoft/perfview) for analysis or in Visual Studio. -A `.nettrace` files can be converted to another format (e.g. SpeedScope or Chromium) using the [dotnet-trace](https://docs.microsoft.com/dotnet/core/diagnostics/dotnet-trace) tool. \ No newline at end of file +A `.nettrace` files can be converted to another format (e.g. SpeedScope or Chromium) using the [dotnet-trace](https://docs.microsoft.com/dotnet/core/diagnostics/dotnet-trace) tool. diff --git a/documentation/configuration.md b/documentation/configuration.md index 2697a0b9f6b..44cb2bb2039 100644 --- a/documentation/configuration.md +++ b/documentation/configuration.md @@ -1,6 +1,6 @@ # Configuration -`dotnet monitor` has extensive configuration to control various aspects of it's behavior. Ordinarily, you are not required to specify most of this configuration and only exists if you wish the change the default behavior in `dotnet monitor`. +`dotnet monitor` has extensive configuration to control various aspects of its behavior. Ordinarily, you are not required to specify most of this configuration and only exists if you wish to change the default behavior in `dotnet monitor`. ## Configuration Sources @@ -65,7 +65,7 @@ spec: mountPath: /etc/dotnet-monitor ``` -Alternatively, you can also configuration maps to specify configuration to the container at runtime. +Alternatively, you can also use configuration maps to specify configuration to the container at runtime. ```yaml apiVersion: v1 @@ -92,7 +92,7 @@ spec: mountPath: /etc/dotnet-monitor ``` -If using multiple configuration maps, secrets, or some combination of both, you need use a [projected volume](https://kubernetes.io/docs/concepts/storage/volumes/#projected) to map serveral volume sources into a single directory +If using multiple configuration maps, secrets, or some combination of both, you need to use a [projected volume](https://kubernetes.io/docs/concepts/storage/volumes/#projected) to map serveral volume sources into a single directory ```yaml spec: @@ -125,20 +125,20 @@ To get completion support in your editor, simply add the `$schema` property to t } ``` -Once you've added the `$schema` property, you should started support for completions in your editor. +Once you've added the `$schema` property, you should have support for completions in your editor. ![completions](https://user-images.githubusercontent.com/4734691/115377729-bf2bb600-a184-11eb-9b8e-50f361c112f0.gif) ## View merged configuration -`dotnet monitor` includes a diagnostic command that allows you to output the the resulting configuration after merging the configuration from all the various sources. +`dotnet monitor` includes a diagnostic command that allows you to output the resulting configuration after merging the configuration from all the various sources. To view the merged configuration, run the following command: ```cmd dotnet monitor config show ``` -The output of command should resemble the following JSON object: +The output of the command should resemble the following JSON object: ```json { @@ -182,7 +182,7 @@ The output of command should resemble the following JSON object: ### Connection Mode -It is possible to change this behavior and have .NET processes connect to `dotnet monitor`. This allow you to monitor a process from start and collect traces for events such assembly load events that primarily occur at process startup and weren't possible to collect previously. +It is possible to change this behavior and have .NET processes connect to `dotnet monitor`. This allow you to monitor a process from start and collect traces for events such as assembly load events that primarily occur at process startup and weren't possible to collect previously. ```json "DiagnosticPort": { @@ -191,7 +191,7 @@ It is possible to change this behavior and have .NET processes connect to `dotne } ``` -When `dotnet monitor` is in `Listen` mode, you have to configure .NET processes to connect to `dotnet monitor`. You can do so specifying the appropriate environment variable on your .NET process +When `dotnet monitor` is in `Listen` mode, you have to configure .NET processes to connect to `dotnet monitor`. You can do so by specifying the appropriate environment variable on your .NET process ```powershell $env:DOTNET_DiagnosticPorts="dotnet-monitor-pipe,suspend" @@ -213,7 +213,7 @@ When operating in `Listen` mode, you can also specify the maximum number of inco ## Storage Configuration -Unlike the other diagnostic artifacts (for example, traces), memory dumps aren't streamed back from the target process to `dotnet monitor`. Instead, they are written directly to disk by the runtime. After successful collection of a process dump, `dotnet monitor` will read the process dump directly from disk. In the default configuration, the directory that the runtime writes it's process dump to is the temp directory (`%TMP%` on Windows, `/tmp` on \*nix). It is possible to change to the ephemeral directory that these dump files get written to via the following configuration: +Unlike the other diagnostic artifacts (for example, traces), memory dumps aren't streamed back from the target process to `dotnet monitor`. Instead, they are written directly to disk by the runtime. After successful collection of a process dump, `dotnet monitor` will read the process dump directly from disk. In the default configuration, the directory that the runtime writes its process dump to is the temp directory (`%TMP%` on Windows, `/tmp` on \*nix). It is possible to change to the ephemeral directory that these dump files get written to via the following configuration: ```json { @@ -225,7 +225,7 @@ Unlike the other diagnostic artifacts (for example, traces), memory dumps aren't ## Default Process Configuration -Default process configuration is used to determine which process is used for metrics, and in situations where the process is not specified in the query to retrieve an artifact. A process must match all the specified filters. +Default process configuration is used to determine which process is used for metrics and in situations where the process is not specified in the query to retrieve an artifact. A process must match all the specified filters. | Name | Type | Description | |---|---|---| @@ -270,7 +270,7 @@ Match pid 1 In addition to the ordinary diagnostics urls that `dotnet monitor` binds to, it also binds to metric urls that only expose the `/metrics` endpoint. Unlike the other endpoints, the metrics urls do not require authentication. Unless you enable collection of custom providers that may contain sensitive business logic, it is generally considered safe to expose metrics endpoints. -Metrics urls can configured via the command line: +Metrics urls can be configured via the command line: ```cmd dotnet monitor collect --metricUrls http://*:52325/ @@ -288,7 +288,7 @@ Or configured via a configuration file: ### Customize collection interval and counts -In the default configuration, `dotnet monitor` requests that the connected runtime provides updated counter values every 10 seconds and will retain 3 data point for every collected metric. When using a collection tool like Prometheus, it is recommended that you set your scrape interval to `MetricCount` * `UpdateIntervalSeconds`. In the default configuration, we recommend you scrape `dotnet monitor` for metrics every 30 seconds. +In the default configuration, `dotnet monitor` requests that the connected runtime provides updated counter values every 10 seconds and will retain 3 data points for every collected metric. When using a collection tool like Prometheus, it is recommended that you set your scrape interval to `MetricCount` * `UpdateIntervalSeconds`. In the default configuration, we recommend you scrape `dotnet monitor` for metrics every 30 seconds. You can customize the number of data points stored per metric and the frequency at which the runtime updates each metric via the following configuration: diff --git a/documentation/egress.md b/documentation/egress.md index 08b97d2134d..1ef56c61b77 100644 --- a/documentation/egress.md +++ b/documentation/egress.md @@ -10,7 +10,7 @@ Egress providers must first be named and configured in dotnet-monitor configurat ### Sample Request ```http -GET /dump/?egressProvider=monitorBlob HTTP/1.1 +GET /dump?egressProvider=monitorBlob HTTP/1.1 ``` ### Sample Response diff --git a/documentation/openapi.json b/documentation/openapi.json index db646230587..bfe6c3ffec0 100644 --- a/documentation/openapi.json +++ b/documentation/openapi.json @@ -35,7 +35,7 @@ } } }, - "/processes/{processKey}": { + "/process": { "get": { "tags": [ "Diag" @@ -44,28 +44,35 @@ "operationId": "GetProcessInfo", "parameters": [ { - "name": "processKey", - "in": "path", - "description": "Value used to identify the target process, either the process ID, the runtime instance cookie, or process name.", - "required": true, - "schema": { - "oneOf": [ - { - "type": "integer", - "description": "The ID of the process.", - "format": "int32" - }, - { - "type": "string", - "description": "The runtime instance cookie of the runtime.", - "format": "uuid" - }, - { - "type": "string", - "description": "The name of the process." - } - ], - "description": "Value used to identify the target process, either the process ID, the runtime instance cookie, or process name." + "name": "pid", + "in": "query", + "description": "Process ID used to identify the target process.", + "schema": { + "type": "integer", + "description": "Process ID used to identify the target process.", + "format": "int32", + "nullable": true + } + }, + { + "name": "uid", + "in": "query", + "description": "The Runtime instance cookie used to identify the target process.", + "schema": { + "type": "string", + "description": "The Runtime instance cookie used to identify the target process.", + "format": "uuid", + "nullable": true + } + }, + { + "name": "name", + "in": "query", + "description": "Process name used to identify the target process.", + "schema": { + "type": "string", + "description": "Process name used to identify the target process.", + "nullable": true } } ], @@ -89,7 +96,7 @@ } } }, - "/processes/{processKey}/env": { + "/env": { "get": { "tags": [ "Diag" @@ -98,28 +105,35 @@ "operationId": "GetProcessEnvironment", "parameters": [ { - "name": "processKey", - "in": "path", - "description": "Value used to identify the target process, either the process ID, the runtime instance cookie, or process name.", - "required": true, - "schema": { - "oneOf": [ - { - "type": "integer", - "description": "The ID of the process.", - "format": "int32" - }, - { - "type": "string", - "description": "The runtime instance cookie of the runtime.", - "format": "uuid" - }, - { - "type": "string", - "description": "The name of the process." - } - ], - "description": "Value used to identify the target process, either the process ID, the runtime instance cookie, or process name." + "name": "pid", + "in": "query", + "description": "Process ID used to identify the target process.", + "schema": { + "type": "integer", + "description": "Process ID used to identify the target process.", + "format": "int32", + "nullable": true + } + }, + { + "name": "uid", + "in": "query", + "description": "The Runtime instance cookie used to identify the target process.", + "schema": { + "type": "string", + "description": "The Runtime instance cookie used to identify the target process.", + "format": "uuid", + "nullable": true + } + }, + { + "name": "name", + "in": "query", + "description": "Process name used to identify the target process.", + "schema": { + "type": "string", + "description": "Process name used to identify the target process.", + "nullable": true } } ], @@ -146,7 +160,7 @@ } } }, - "/dump/{processKey}": { + "/dump": { "get": { "tags": [ "Diag" @@ -155,28 +169,34 @@ "operationId": "CaptureDump", "parameters": [ { - "name": "processKey", - "in": "path", - "description": "Value used to identify the target process, either the process ID, the runtime instance cookie, or process name.", - "required": true, - "schema": { - "oneOf": [ - { - "type": "integer", - "description": "The ID of the process.", - "format": "int32" - }, - { - "type": "string", - "description": "The runtime instance cookie of the runtime.", - "format": "uuid" - }, - { - "type": "string", - "description": "The name of the process." - } - ], - "description": "Value used to identify the target process, either the process ID, the runtime instance cookie, or process name.", + "name": "pid", + "in": "query", + "description": "Process ID used to identify the target process.", + "schema": { + "type": "integer", + "description": "Process ID used to identify the target process.", + "format": "int32", + "nullable": true + } + }, + { + "name": "uid", + "in": "query", + "description": "The Runtime instance cookie used to identify the target process.", + "schema": { + "type": "string", + "description": "The Runtime instance cookie used to identify the target process.", + "format": "uuid", + "nullable": true + } + }, + { + "name": "name", + "in": "query", + "description": "Process name used to identify the target process.", + "schema": { + "type": "string", + "description": "Process name used to identify the target process.", "nullable": true } }, @@ -223,7 +243,7 @@ } } }, - "/gcdump/{processKey}": { + "/gcdump": { "get": { "tags": [ "Diag" @@ -232,28 +252,34 @@ "operationId": "CaptureGcDump", "parameters": [ { - "name": "processKey", - "in": "path", - "description": "Value used to identify the target process, either the process ID, the runtime instance cookie, or process name.", - "required": true, - "schema": { - "oneOf": [ - { - "type": "integer", - "description": "The ID of the process.", - "format": "int32" - }, - { - "type": "string", - "description": "The runtime instance cookie of the runtime.", - "format": "uuid" - }, - { - "type": "string", - "description": "The name of the process." - } - ], - "description": "Value used to identify the target process, either the process ID, the runtime instance cookie, or process name.", + "name": "pid", + "in": "query", + "description": "Process ID used to identify the target process.", + "schema": { + "type": "integer", + "description": "Process ID used to identify the target process.", + "format": "int32", + "nullable": true + } + }, + { + "name": "uid", + "in": "query", + "description": "The Runtime instance cookie used to identify the target process.", + "schema": { + "type": "string", + "description": "The Runtime instance cookie used to identify the target process.", + "format": "uuid", + "nullable": true + } + }, + { + "name": "name", + "in": "query", + "description": "Process name used to identify the target process.", + "schema": { + "type": "string", + "description": "Process name used to identify the target process.", "nullable": true } }, @@ -292,7 +318,7 @@ } } }, - "/trace/{processKey}": { + "/trace": { "get": { "tags": [ "Diag" @@ -301,28 +327,34 @@ "operationId": "CaptureTrace", "parameters": [ { - "name": "processKey", - "in": "path", - "description": "Value used to identify the target process, either the process ID, the runtime instance cookie, or process name.", - "required": true, - "schema": { - "oneOf": [ - { - "type": "integer", - "description": "The ID of the process.", - "format": "int32" - }, - { - "type": "string", - "description": "The runtime instance cookie of the runtime.", - "format": "uuid" - }, - { - "type": "string", - "description": "The name of the process." - } - ], - "description": "Value used to identify the target process, either the process ID, the runtime instance cookie, or process name.", + "name": "pid", + "in": "query", + "description": "Process ID used to identify the target process.", + "schema": { + "type": "integer", + "description": "Process ID used to identify the target process.", + "format": "int32", + "nullable": true + } + }, + { + "name": "uid", + "in": "query", + "description": "The Runtime instance cookie used to identify the target process.", + "schema": { + "type": "string", + "description": "The Runtime instance cookie used to identify the target process.", + "format": "uuid", + "nullable": true + } + }, + { + "name": "name", + "in": "query", + "description": "Process name used to identify the target process.", + "schema": { + "type": "string", + "description": "Process name used to identify the target process.", "nullable": true } }, @@ -402,28 +434,34 @@ "operationId": "CaptureTraceCustom", "parameters": [ { - "name": "processKey", - "in": "path", - "description": "Value used to identify the target process, either the process ID, the runtime instance cookie, or process name.", - "required": true, - "schema": { - "oneOf": [ - { - "type": "integer", - "description": "The ID of the process.", - "format": "int32" - }, - { - "type": "string", - "description": "The runtime instance cookie of the runtime.", - "format": "uuid" - }, - { - "type": "string", - "description": "The name of the process." - } - ], - "description": "Value used to identify the target process, either the process ID, the runtime instance cookie, or process name.", + "name": "pid", + "in": "query", + "description": "Process ID used to identify the target process.", + "schema": { + "type": "integer", + "description": "Process ID used to identify the target process.", + "format": "int32", + "nullable": true + } + }, + { + "name": "uid", + "in": "query", + "description": "The Runtime instance cookie used to identify the target process.", + "schema": { + "type": "string", + "description": "The Runtime instance cookie used to identify the target process.", + "format": "uuid", + "nullable": true + } + }, + { + "name": "name", + "in": "query", + "description": "Process name used to identify the target process.", + "schema": { + "type": "string", + "description": "Process name used to identify the target process.", "nullable": true } }, @@ -496,7 +534,7 @@ } } }, - "/logs/{processKey}": { + "/logs": { "get": { "tags": [ "Diag" @@ -505,28 +543,34 @@ "operationId": "CaptureLogs", "parameters": [ { - "name": "processKey", - "in": "path", - "description": "Value used to identify the target process, either the process ID, the runtime instance cookie, or process name.", - "required": true, - "schema": { - "oneOf": [ - { - "type": "integer", - "description": "The ID of the process.", - "format": "int32" - }, - { - "type": "string", - "description": "The runtime instance cookie of the runtime.", - "format": "uuid" - }, - { - "type": "string", - "description": "The name of the process." - } - ], - "description": "Value used to identify the target process, either the process ID, the runtime instance cookie, or process name.", + "name": "pid", + "in": "query", + "description": "Process ID used to identify the target process.", + "schema": { + "type": "integer", + "description": "Process ID used to identify the target process.", + "format": "int32", + "nullable": true + } + }, + { + "name": "uid", + "in": "query", + "description": "The Runtime instance cookie used to identify the target process.", + "schema": { + "type": "string", + "description": "The Runtime instance cookie used to identify the target process.", + "format": "uuid", + "nullable": true + } + }, + { + "name": "name", + "in": "query", + "description": "Process name used to identify the target process.", + "schema": { + "type": "string", + "description": "Process name used to identify the target process.", "nullable": true } }, @@ -602,28 +646,34 @@ "operationId": "CaptureLogsCustom", "parameters": [ { - "name": "processKey", - "in": "path", - "description": "Value used to identify the target process, either the process ID, the runtime instance cookie, or process name.", - "required": true, - "schema": { - "oneOf": [ - { - "type": "integer", - "description": "The ID of the process.", - "format": "int32" - }, - { - "type": "string", - "description": "The runtime instance cookie of the runtime.", - "format": "uuid" - }, - { - "type": "string", - "description": "The name of the process." - } - ], - "description": "Value used to identify the target process, either the process ID, the runtime instance cookie, or process name.", + "name": "pid", + "in": "query", + "description": "Process ID used to identify the target process.", + "schema": { + "type": "integer", + "description": "Process ID used to identify the target process.", + "format": "int32", + "nullable": true + } + }, + { + "name": "uid", + "in": "query", + "description": "The Runtime instance cookie used to identify the target process.", + "schema": { + "type": "string", + "description": "The Runtime instance cookie used to identify the target process.", + "format": "uuid", + "nullable": true + } + }, + { + "name": "name", + "in": "query", + "description": "Process name used to identify the target process.", + "schema": { + "type": "string", + "description": "Process name used to identify the target process.", "nullable": true } }, @@ -783,6 +833,9 @@ "name": { "type": "string", "nullable": true + }, + "isDefault": { + "type": "boolean" } }, "additionalProperties": false diff --git a/documentation/setup.md b/documentation/setup.md index 2c7826fceaf..4886de3ec33 100644 --- a/documentation/setup.md +++ b/documentation/setup.md @@ -1,6 +1,6 @@ # Setup -`dotnet monitor` is available via two different distribution mechanism: +`dotnet monitor` is available via two different distribution mechanisms: - As a .NET Core global tool; and - As a container image available via the Microsoft Container Registry (MCR) @@ -33,7 +33,7 @@ docker pull mcr.microsoft.com/dotnet/monitor:5.0.0-preview.5 In addition to public previews, we also publish last-known-good (LKG) builds for the next release of `dotnet monitor`. -The LKG build of `dotnet monitor` is available on a private package feed. You can download the latest versionof the .NET global tool using the following command: +The LKG build of `dotnet monitor` is available on a private package feed. You can download the latest version of the .NET global tool using the following command: ```cmd dotnet tool install -g dotnet-monitor --add-source https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet-tools/nuget/v3/index.json --version 5.0.0-preview.6.* diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.cs index f403e6c1e7e..45d4bdc7fb4 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.cs @@ -64,6 +64,16 @@ public DiagController(ILogger logger, IServiceProvider servicePr { return this.InvokeService(async () => { + IProcessInfo defaultProcessInfo = null; + try + { + defaultProcessInfo = await _diagnosticServices.GetProcessAsync(null, HttpContext.RequestAborted); + } + catch (Exception) + { + // Unable to locate a default process; no action required + } + IList processesIdentifiers = new List(); foreach (IProcessInfo p in await _diagnosticServices.GetProcessesAsync(processFilter: null, HttpContext.RequestAborted)) { @@ -71,7 +81,10 @@ public DiagController(ILogger logger, IServiceProvider servicePr { Pid = p.EndpointInfo.ProcessId, Uid = p.EndpointInfo.RuntimeInstanceCookie, - Name = p.ProcessName + Name = p.ProcessName, + IsDefault = (defaultProcessInfo != null && + p.EndpointInfo.ProcessId == defaultProcessInfo.EndpointInfo.ProcessId && + p.EndpointInfo.RuntimeInstanceCookie == defaultProcessInfo.EndpointInfo.RuntimeInstanceCookie) }); } _logger.WrittenToHttpStream(); @@ -82,13 +95,22 @@ public DiagController(ILogger logger, IServiceProvider servicePr /// /// Get information about the specified process. /// - /// Value used to identify the target process, either the process ID, the runtime instance cookie, or process name. - [HttpGet("processes/{processKey}", Name = nameof(GetProcessInfo))] + /// Process ID used to identify the target process. + /// The Runtime instance cookie used to identify the target process. + /// Process name used to identify the target process. + [HttpGet("process", Name = nameof(GetProcessInfo))] [ProducesWithProblemDetails(ContentTypes.ApplicationJson)] [ProducesResponseType(typeof(Models.ProcessInfo), StatusCodes.Status200OK)] public Task> GetProcessInfo( - ProcessKey processKey) + [FromQuery] + int? pid = null, + [FromQuery] + Guid? uid = null, + [FromQuery] + string name = null) { + ProcessKey? processKey = GetProcessKey(pid, uid, name); + return InvokeForProcess(processInfo => { Models.ProcessInfo processModel = new Models.ProcessInfo() @@ -111,13 +133,22 @@ public DiagController(ILogger logger, IServiceProvider servicePr /// /// Get the environment block of the specified process. /// - /// Value used to identify the target process, either the process ID, the runtime instance cookie, or process name. - [HttpGet("processes/{processKey}/env", Name = nameof(GetProcessEnvironment))] + /// Process ID used to identify the target process. + /// The Runtime instance cookie used to identify the target process. + /// Process name used to identify the target process. + [HttpGet("env", Name = nameof(GetProcessEnvironment))] [ProducesWithProblemDetails(ContentTypes.ApplicationJson)] [ProducesResponseType(typeof(Dictionary), StatusCodes.Status200OK)] public Task>> GetProcessEnvironment( - ProcessKey processKey) + [FromQuery] + int? pid = null, + [FromQuery] + Guid? uid = null, + [FromQuery] + string name = null) { + ProcessKey? processKey = GetProcessKey(pid, uid, name); + return InvokeForProcess>(processInfo => { var client = new DiagnosticsClient(processInfo.EndpointInfo.Endpoint); @@ -141,11 +172,13 @@ public Task>> GetProcessEnvironment( /// /// Capture a dump of a process. /// - /// Value used to identify the target process, either the process ID, the runtime instance cookie, or process name. + /// Process ID used to identify the target process. + /// The Runtime instance cookie used to identify the target process. + /// Process name used to identify the target process. /// The type of dump to capture. /// The egress provider to which the dump is saved. /// - [HttpGet("dump/{processKey?}", Name = nameof(CaptureDump))] + [HttpGet("dump", Name = nameof(CaptureDump))] [ProducesWithProblemDetails(ContentTypes.ApplicationOctetStream)] // FileResult is the closest representation of the output so that the OpenAPI document correctly // describes the result as a binary file. @@ -153,12 +186,19 @@ public Task>> GetProcessEnvironment( [ProducesResponseType(typeof(FileResult), StatusCodes.Status200OK)] [RequestLimit(MaxConcurrency = 1)] public Task CaptureDump( - ProcessKey? processKey, + [FromQuery] + int? pid = null, + [FromQuery] + Guid? uid = null, + [FromQuery] + string name = null, [FromQuery] Models.DumpType type = Models.DumpType.WithHeap, [FromQuery] string egressProvider = null) { + ProcessKey? processKey = GetProcessKey(pid, uid, name); + return InvokeForProcess(async processInfo => { string dumpFileName = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? @@ -194,10 +234,12 @@ public Task CaptureDump( /// /// Capture a GC dump of a process. /// - /// Value used to identify the target process, either the process ID, the runtime instance cookie, or process name. + /// Process ID used to identify the target process. + /// The Runtime instance cookie used to identify the target process. + /// Process name used to identify the target process. /// The egress provider to which the GC dump is saved. /// - [HttpGet("gcdump/{processKey?}", Name = nameof(CaptureGcDump))] + [HttpGet("gcdump", Name = nameof(CaptureGcDump))] [ProducesWithProblemDetails(ContentTypes.ApplicationOctetStream)] // FileResult is the closest representation of the output so that the OpenAPI document correctly // describes the result as a binary file. @@ -205,10 +247,17 @@ public Task CaptureDump( [ProducesResponseType(typeof(FileResult), StatusCodes.Status200OK)] [RequestLimit(MaxConcurrency = 1)] public Task CaptureGcDump( - ProcessKey? processKey, + [FromQuery] + int? pid = null, + [FromQuery] + Guid? uid = null, + [FromQuery] + string name = null, [FromQuery] string egressProvider = null) { + ProcessKey? processKey = GetProcessKey(pid, uid, name); + return InvokeForProcess(processInfo => { string fileName = FormattableString.Invariant($"{GetFileNameTimeStampUtcNow()}_{processInfo.EndpointInfo.ProcessId}.gcdump"); @@ -245,12 +294,14 @@ public Task CaptureGcDump( /// /// Capture a trace of a process. /// - /// Value used to identify the target process, either the process ID, the runtime instance cookie, or process name. + /// Process ID used to identify the target process. + /// The Runtime instance cookie used to identify the target process. + /// Process name used to identify the target process. /// The profiles enabled for the trace session. /// The duration of the trace session (in seconds). /// The reporting interval (in seconds) for event counters. /// The egress provider to which the trace is saved. - [HttpGet("trace/{processKey?}", Name = nameof(CaptureTrace))] + [HttpGet("trace", Name = nameof(CaptureTrace))] [ProducesWithProblemDetails(ContentTypes.ApplicationOctetStream)] // FileResult is the closest representation of the output so that the OpenAPI document correctly // describes the result as a binary file. @@ -258,7 +309,12 @@ public Task CaptureGcDump( [ProducesResponseType(typeof(FileResult), StatusCodes.Status200OK)] [RequestLimit(MaxConcurrency = 3)] public Task CaptureTrace( - ProcessKey? processKey, + [FromQuery] + int? pid = null, + [FromQuery] + Guid? uid = null, + [FromQuery] + string name = null, [FromQuery] Models.TraceProfile profile = DefaultTraceProfiles, [FromQuery][Range(-1, int.MaxValue)] @@ -268,6 +324,8 @@ public Task CaptureTrace( [FromQuery] string egressProvider = null) { + ProcessKey? processKey = GetProcessKey(pid, uid, name); + return InvokeForProcess(processInfo => { TimeSpan duration = ConvertSecondsToTimeSpan(durationSeconds); @@ -303,11 +361,13 @@ public Task CaptureTrace( /// /// Capture a trace of a process. /// - /// Value used to identify the target process, either the process ID, the runtime instance cookie, or process name. /// The trace configuration describing which events to capture. + /// Process ID used to identify the target process. + /// The Runtime instance cookie used to identify the target process. + /// Process name used to identify the target process. /// The duration of the trace session (in seconds). /// The egress provider to which the trace is saved. - [HttpPost("trace/{processKey?}", Name = nameof(CaptureTraceCustom))] + [HttpPost("trace", Name = nameof(CaptureTraceCustom))] [ProducesWithProblemDetails(ContentTypes.ApplicationOctetStream)] // FileResult is the closest representation of the output so that the OpenAPI document correctly // describes the result as a binary file. @@ -315,14 +375,21 @@ public Task CaptureTrace( [ProducesResponseType(typeof(FileResult), StatusCodes.Status200OK)] [RequestLimit(MaxConcurrency = 3)] public Task CaptureTraceCustom( - ProcessKey? processKey, [FromBody][Required] Models.EventPipeConfiguration configuration, + [FromQuery] + int? pid = null, + [FromQuery] + Guid? uid = null, + [FromQuery] + string name = null, [FromQuery][Range(-1, int.MaxValue)] int durationSeconds = 30, [FromQuery] string egressProvider = null) { + ProcessKey? processKey = GetProcessKey(pid, uid, name); + return InvokeForProcess(processInfo => { TimeSpan duration = ConvertSecondsToTimeSpan(durationSeconds); @@ -356,17 +423,24 @@ public Task CaptureTraceCustom( /// /// Capture a stream of logs from a process. /// - /// Value used to identify the target process, either the process ID, the runtime instance cookie, or process name. + /// Process ID used to identify the target process. + /// The Runtime instance cookie used to identify the target process. + /// Process name used to identify the target process. /// The duration of the logs session (in seconds). /// The level of the logs to capture. /// The egress provider to which the logs are saved. - [HttpGet("logs/{processKey?}", Name = nameof(CaptureLogs))] + [HttpGet("logs", Name = nameof(CaptureLogs))] [ProducesWithProblemDetails(ContentTypes.ApplicationNdJson, ContentTypes.ApplicationJsonSequence, ContentTypes.TextEventStream)] [ProducesResponseType(typeof(void), StatusCodes.Status429TooManyRequests)] [ProducesResponseType(typeof(string), StatusCodes.Status200OK)] [RequestLimit(MaxConcurrency = 3)] public Task CaptureLogs( - ProcessKey? processKey, + [FromQuery] + int? pid = null, + [FromQuery] + Guid? uid = null, + [FromQuery] + string name = null, [FromQuery][Range(-1, int.MaxValue)] int durationSeconds = 30, [FromQuery] @@ -374,6 +448,8 @@ public Task CaptureLogs( [FromQuery] string egressProvider = null) { + ProcessKey? processKey = GetProcessKey(pid, uid, name); + return InvokeForProcess(processInfo => { TimeSpan duration = ConvertSecondsToTimeSpan(durationSeconds); @@ -401,24 +477,33 @@ public Task CaptureLogs( /// /// Capture a stream of logs from a process. /// - /// Value used to identify the target process, either the process ID, the runtime instance cookie, or process name. /// The logs configuration describing which logs to capture. + /// Process ID used to identify the target process. + /// The Runtime instance cookie used to identify the target process. + /// Process name used to identify the target process. /// The duration of the logs session (in seconds). /// The egress provider to which the logs are saved. - [HttpPost("logs/{processKey?}", Name = nameof(CaptureLogsCustom))] + [HttpPost("logs", Name = nameof(CaptureLogsCustom))] [ProducesWithProblemDetails(ContentTypes.ApplicationNdJson, ContentTypes.ApplicationJsonSequence, ContentTypes.TextEventStream)] [ProducesResponseType(typeof(void), StatusCodes.Status429TooManyRequests)] [ProducesResponseType(typeof(string), StatusCodes.Status200OK)] [RequestLimit(MaxConcurrency = 3)] public Task CaptureLogsCustom( - ProcessKey? processKey, [FromBody] Models.LogsConfiguration configuration, + [FromQuery] + int? pid = null, + [FromQuery] + Guid? uid = null, + [FromQuery] + string name = null, [FromQuery][Range(-1, int.MaxValue)] int durationSeconds = 30, [FromQuery] string egressProvider = null) { + ProcessKey? processKey = GetProcessKey(pid, uid, name); + return InvokeForProcess(processInfo => { TimeSpan duration = ConvertSecondsToTimeSpan(durationSeconds); @@ -528,6 +613,11 @@ private static TimeSpan ConvertSecondsToTimeSpan(int durationSeconds) TimeSpan.FromSeconds(durationSeconds); } + private static ProcessKey? GetProcessKey(int? pid, Guid? uid, string name) + { + return (pid == null && uid == null && name == null) ? null : new ProcessKey(pid, uid, name); + } + private static string GetFileNameTimeStampUtcNow() { return DateTime.UtcNow.ToString("yyyyMMdd_HHmmss"); @@ -691,4 +781,4 @@ private async Task> InvokeForProcess(Func filterEntries = TransformKey(processKey); + + for (int index = 0; index < filterEntries.Count; ++index) + { + filter.Filters.Add(filterEntries[index]); + } + return filter; } @@ -38,19 +44,26 @@ public static DiagProcessFilter FromConfiguration(ProcessFilterOptions options) return filter; } - private static DiagProcessFilterEntry TransformKey(ProcessKey processKey) + private static List TransformKey(ProcessKey processKey) { + List filterEntries = new List(); + if (processKey.ProcessId.HasValue) { - return new DiagProcessFilterEntry { Criteria = DiagProcessFilterCriteria.ProcessId, MatchType = DiagProcessFilterMatchType.Exact, Value = processKey.ProcessId.Value.ToString(CultureInfo.InvariantCulture) }; + filterEntries.Add(new DiagProcessFilterEntry { Criteria = DiagProcessFilterCriteria.ProcessId, MatchType = DiagProcessFilterMatchType.Exact, Value = processKey.ProcessId.Value.ToString(CultureInfo.InvariantCulture) }); } if (processKey.ProcessName != null) { - return new DiagProcessFilterEntry { Criteria = DiagProcessFilterCriteria.ProcessName, MatchType = DiagProcessFilterMatchType.Exact, Value = processKey.ProcessName }; + filterEntries.Add(new DiagProcessFilterEntry { Criteria = DiagProcessFilterCriteria.ProcessName, MatchType = DiagProcessFilterMatchType.Exact, Value = processKey.ProcessName }); } if (processKey.RuntimeInstanceCookie.HasValue) { - return new DiagProcessFilterEntry { Criteria = DiagProcessFilterCriteria.RuntimeId, MatchType = DiagProcessFilterMatchType.Exact, Value = processKey.RuntimeInstanceCookie.Value.ToString("D") }; + filterEntries.Add(new DiagProcessFilterEntry { Criteria = DiagProcessFilterCriteria.RuntimeId, MatchType = DiagProcessFilterMatchType.Exact, Value = processKey.RuntimeInstanceCookie.Value.ToString("D") }); + } + + if (filterEntries.Count > 0) + { + return filterEntries; } throw new ArgumentException($"Invalid {nameof(processKey)}"); diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/ProcessIdentifier.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/ProcessIdentifier.cs index 5799c263551..6bd3f72150b 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/ProcessIdentifier.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/ProcessIdentifier.cs @@ -21,5 +21,8 @@ public class ProcessIdentifier [JsonPropertyName("name")] public string Name { get; set; } + + [JsonPropertyName("isDefault")] + public bool IsDefault { get; set; } } } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/ProcessKey.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/ProcessKey.cs index b3ec3289bb3..10768a1dd51 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/ProcessKey.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/ProcessKey.cs @@ -9,34 +9,41 @@ namespace Microsoft.Diagnostics.Monitoring { [TypeConverter(typeof(ProcessKeyTypeConverter))] - public struct ProcessKey + internal struct ProcessKey { - public ProcessKey(int processId) + internal ProcessKey(int processId) { ProcessId = processId; ProcessName = null; RuntimeInstanceCookie = null; } - public ProcessKey(Guid runtimeInstanceCookie) + internal ProcessKey(Guid runtimeInstanceCookie) { ProcessId = null; ProcessName = null; RuntimeInstanceCookie = runtimeInstanceCookie; } - public ProcessKey(string processName) + internal ProcessKey(string processName) { ProcessId = null; ProcessName = processName; RuntimeInstanceCookie = null; } - public int? ProcessId { get; } + internal ProcessKey(int? processId = null, Guid? runtimeInstanceCookie = null, string processName = null) + { + ProcessId = processId; + ProcessName = processName; + RuntimeInstanceCookie = runtimeInstanceCookie; + } + + internal int? ProcessId { get; } - public string ProcessName { get; } + internal string ProcessName { get; } - public Guid? RuntimeInstanceCookie { get; } + internal Guid? RuntimeInstanceCookie { get; } } internal class ProcessKeyTypeConverter : TypeConverter diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.OpenApiGen/Program.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.OpenApiGen/Program.cs index cfe55cf1ca1..226f88e2761 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.OpenApiGen/Program.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.OpenApiGen/Program.cs @@ -55,9 +55,6 @@ public static void Main(string[] args) { services.AddSwaggerGen(options => { - options.MapType(CreateProcessKeySchema); - options.MapType(CreateProcessKeySchema); - options.DocumentFilter(); options.DocumentFilter(); options.DocumentFilter(); diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClient.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClient.cs index 2677a95fc22..5448b201241 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClient.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClient.cs @@ -29,7 +29,6 @@ internal sealed class ApiClient private readonly HttpClient _httpClient; private readonly ITestOutputHelper _outputHelper; - public ApiClient(ITestOutputHelper outputHelper, HttpClient httpClient) { _httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient)); @@ -67,24 +66,17 @@ public ApiClient(ITestOutputHelper outputHelper, HttpClient httpClient) } /// - /// Get /processes/{pid} - /// - public Task GetProcessAsync(int pid, CancellationToken token) - { - return GetProcessAsync(pid.ToString(CultureInfo.InvariantCulture), token); - } - - /// - /// Get /processes/{uid} + /// Capable of getting every combination of process query: PID, UID, and/or Name + /// Get /process?pid={pid}&uid={uid}&name={name} /// - public Task GetProcessAsync(Guid uid, CancellationToken token) + public Task GetProcessAsync(int? pid, Guid? uid, string name, CancellationToken token) { - return GetProcessAsync(uid.ToString("D"), token); + return GetProcessAsync(GetProcessQuery(pid: pid, uid: uid, name: name), token); } - private async Task GetProcessAsync(string processKey, CancellationToken token) + private async Task GetProcessAsync(string processQuery, CancellationToken token) { - using HttpRequestMessage request = new(HttpMethod.Get, $"/processes/{processKey}"); + using HttpRequestMessage request = new(HttpMethod.Get, $"/process?" + processQuery); request.Headers.Add(HeaderNames.Accept, ContentTypes.ApplicationJson); using HttpResponseMessage response = await SendAndLogAsync( @@ -110,24 +102,24 @@ public ApiClient(ITestOutputHelper outputHelper, HttpClient httpClient) } /// - /// Get /processes/{pid}/env + /// Get /env?pid={pid} /// public Task> GetProcessEnvironmentAsync(int pid, CancellationToken token) { - return GetProcessEnvironmentAsync(pid.ToString(CultureInfo.InvariantCulture), token); + return GetProcessEnvironmentAsync(GetProcessQuery(pid:pid), token); } /// - /// Get /processes/{uid}/env + /// Get /env?uid={uid} /// public Task> GetProcessEnvironmentAsync(Guid uid, CancellationToken token) { - return GetProcessEnvironmentAsync(uid.ToString("D"), token); + return GetProcessEnvironmentAsync(GetProcessQuery(uid:uid), token); } - private async Task> GetProcessEnvironmentAsync(string processKey, CancellationToken token) + private async Task> GetProcessEnvironmentAsync(string processQuery, CancellationToken token) { - using HttpRequestMessage request = new(HttpMethod.Get, $"/processes/{processKey}/env"); + using HttpRequestMessage request = new(HttpMethod.Get, $"/env?" + processQuery); request.Headers.Add(HeaderNames.Accept, ContentTypes.ApplicationJson); using HttpResponseMessage response = await SendAndLogAsync( @@ -153,24 +145,24 @@ private async Task> GetProcessEnvironmentAsync(string } /// - /// Get /dump/{pid}?type={dumpType} + /// Get /dump?pid={pid}&type={dumpType} /// public Task CaptureDumpAsync(int pid, DumpType dumpType, CancellationToken token) { - return CaptureDumpAsync(pid.ToString(CultureInfo.InvariantCulture), dumpType, token); + return CaptureDumpAsync(GetProcessQuery(pid:pid), dumpType, token); } /// - /// Get /dump/{uid}?type={dumpType} + /// Get /dump?uid={uid}&type={dumpType} /// public Task CaptureDumpAsync(Guid uid, DumpType dumpType, CancellationToken token) { - return CaptureDumpAsync(uid.ToString("D"), dumpType, token); + return CaptureDumpAsync(GetProcessQuery(uid:uid), dumpType, token); } - private async Task CaptureDumpAsync(string processKey, DumpType dumpType, CancellationToken token) + private async Task CaptureDumpAsync(string processQuery, DumpType dumpType, CancellationToken token) { - using HttpRequestMessage request = new(HttpMethod.Get, $"/dump/{processKey}?type={dumpType.ToString("G")}"); + using HttpRequestMessage request = new(HttpMethod.Get, $"/dump?{processQuery}&type={dumpType.ToString("G")}"); request.Headers.Add(HeaderNames.Accept, ContentTypes.ApplicationOctetStream); using DisposableBox responseBox = new( @@ -198,48 +190,40 @@ await SendAndLogAsync( } /// - /// GET /logs/{pid}?level={logLevel}&durationSeconds={duration} + /// GET /logs?pid={pid}&level={logLevel}&durationSeconds={duration} /// public Task CaptureLogsAsync(int pid, TimeSpan duration, LogLevel? logLevel, LogFormat logFormat, CancellationToken token) { - return CaptureLogsAsync(pid.ToString(CultureInfo.InvariantCulture), duration, logLevel, logFormat, token); + return CaptureLogsAsync(GetProcessQuery(pid:pid), duration, logLevel, logFormat, token); } /// - /// GET /logs/{uid}?level={logLevel}&durationSeconds={duration} + /// GET /logs?uid={uid}&level={logLevel}&durationSeconds={duration} /// public Task CaptureLogsAsync(Guid uid, TimeSpan duration, LogLevel? logLevel, LogFormat logFormat, CancellationToken token) { - return CaptureLogsAsync(uid.ToString("D"), duration, logLevel, logFormat, token); + return CaptureLogsAsync(GetProcessQuery(uid:uid), duration, logLevel, logFormat, token); } - private Task CaptureLogsAsync(string processKey, TimeSpan duration, LogLevel? logLevel, LogFormat logFormat, CancellationToken token) + private Task CaptureLogsAsync(string processQuery, TimeSpan duration, LogLevel? logLevel, LogFormat logFormat, CancellationToken token) { return CaptureLogsAsync( HttpMethod.Get, - CreateLogsUriString(processKey, duration, logLevel), + CreateLogsUriString(processQuery, duration, logLevel), content: null, logFormat, token); } /// - /// POST /logs/{pid}?durationSeconds={duration} + /// POST /logs?pid={pid}&durationSeconds={duration} /// public Task CaptureLogsAsync(int pid, TimeSpan duration, LogsConfiguration configuration, LogFormat logFormat, CancellationToken token) { - return CaptureLogsAsync(pid.ToString(CultureInfo.InvariantCulture), duration, configuration, logFormat, token); + return CaptureLogsAsync(GetProcessQuery(pid:pid), duration, configuration, logFormat, token); } - /// - /// POST /logs/{uid}?durationSeconds={duration} - /// - public Task CaptureLogsAsync(Guid uid, TimeSpan duration, LogsConfiguration configuration, LogFormat logFormat, CancellationToken token) - { - return CaptureLogsAsync(uid.ToString("D"), duration, configuration, logFormat, token); - } - - private Task CaptureLogsAsync(string processKey, TimeSpan duration, LogsConfiguration configuration, LogFormat logFormat, CancellationToken token) + private Task CaptureLogsAsync(string processQuery, TimeSpan duration, LogsConfiguration configuration, LogFormat logFormat, CancellationToken token) { JsonSerializerOptions options = new(); options.Converters.Add(new JsonStringEnumConverter()); @@ -247,7 +231,7 @@ private Task CaptureLogsAsync(string processKey, TimeSpan return CaptureLogsAsync( HttpMethod.Post, - CreateLogsUriString(processKey, duration, logLevel: null), + CreateLogsUriString(processQuery, duration, logLevel: null), new StringContent(json, Encoding.UTF8, ContentTypes.ApplicationJson), logFormat, token); @@ -381,12 +365,12 @@ private void ValidateContentType(HttpResponseMessage responseMessage, string exp Assert.Equal(expectedMediaType, responseMessage.Content.Headers.ContentType?.MediaType); } - private static string CreateLogsUriString(string processKey, TimeSpan duration, LogLevel? logLevel) + private static string CreateLogsUriString(string processIdentifierQuery, TimeSpan duration, LogLevel? logLevel) { StringBuilder routeBuilder = new(); - routeBuilder.Append("/logs/"); - routeBuilder.Append(processKey); - routeBuilder.Append("?"); + routeBuilder.Append("/logs?"); + routeBuilder.Append(processIdentifierQuery); + routeBuilder.Append("&"); AppendDuration(routeBuilder, duration); if (logLevel.HasValue) { @@ -408,5 +392,42 @@ private static void AppendDuration(StringBuilder builder, TimeSpan duration) builder.Append(Convert.ToInt32(duration.TotalSeconds).ToString(CultureInfo.InvariantCulture)); } } + + private static string GetProcessQuery(int? pid = null, Guid? uid = null, string name = null) + { + string assembledQuery = ""; + + if (pid != null) + { + assembledQuery += "pid=" + pid.Value.ToString(CultureInfo.InvariantCulture); + } + + if (uid != null) + { + if (assembledQuery.Length > 0) + { + assembledQuery += "&"; + } + + assembledQuery += "uid=" + uid.Value.ToString("D"); + } + + if (name != null) + { + if (assembledQuery.Length > 0) + { + assembledQuery += "&"; + } + + assembledQuery += "name=" + name; + } + + if (!assembledQuery.Equals("")) + { + return assembledQuery; + } + + throw new ArgumentException("One of PID, UID, or Name must be specified."); + } } -} +} \ No newline at end of file diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClientExtensions.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClientExtensions.cs index 4d9d83fc763..574e1560d97 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClientExtensions.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClientExtensions.cs @@ -32,7 +32,7 @@ public static async Task> GetProcessesAsync(this } /// - /// Get /processes/{pid} + /// Get /process?pid={pid} /// public static Task GetProcessAsync(this ApiClient client, int pid) { @@ -40,16 +40,16 @@ public static Task GetProcessAsync(this ApiClient client, int pid) } /// - /// Get /processes/{pid} + /// Get /process?pid={pid} /// public static async Task GetProcessAsync(this ApiClient client, int pid, TimeSpan timeout) { using CancellationTokenSource timeoutSource = new(timeout); - return await client.GetProcessAsync(pid, timeoutSource.Token).ConfigureAwait(false); + return await client.GetProcessAsync(pid: pid, uid: null, name: null, token: timeoutSource.Token).ConfigureAwait(false); } /// - /// Get /processes/{uid} + /// Get /process?uid={uid} /// public static Task GetProcessAsync(this ApiClient client, Guid uid) { @@ -57,16 +57,34 @@ public static Task GetProcessAsync(this ApiClient client, Guid uid) } /// - /// Get /processes/{uid} + /// Get /process?uid={uid} + /// + public static Task GetProcessAsync(this ApiClient client, int? pid, Guid? uid, string name) + { + return client.GetProcessAsync(pid: pid, uid: uid, name: name, TestTimeouts.HttpApi); + } + + /// + /// Get /process?uid={uid} /// public static async Task GetProcessAsync(this ApiClient client, Guid uid, TimeSpan timeout) { using CancellationTokenSource timeoutSource = new(timeout); - return await client.GetProcessAsync(uid, timeoutSource.Token).ConfigureAwait(false); + return await client.GetProcessAsync(pid: null, uid: uid, name: null, token: timeoutSource.Token).ConfigureAwait(false); + } + + /// + /// Capable of getting every combination of process query: PID, UID, and/or Name + /// Get /process?pid={pid}&uid={uid}&name={name} + /// + public static async Task GetProcessAsync(this ApiClient client, int? pid, Guid? uid, string name, TimeSpan timeout) + { + using CancellationTokenSource timeoutSource = new(timeout); + return await client.GetProcessAsync(pid: pid, uid: uid, name: name, token: timeoutSource.Token).ConfigureAwait(false); } /// - /// Get /processes/{pid}/env + /// Get /env?pid={pid} /// public static Task> GetProcessEnvironmentAsync(this ApiClient client, int pid) { @@ -74,7 +92,7 @@ public static Task> GetProcessEnvironmentAsync(this A } /// - /// Get /processes/{pid}/env + /// Get /env?pid={pid} /// public static async Task> GetProcessEnvironmentAsync(this ApiClient client, int pid, TimeSpan timeout) { @@ -83,7 +101,7 @@ public static async Task> GetProcessEnvironmentAsync( } /// - /// Get /processes/{uid}/env + /// Get /env?uid={uid} /// public static Task> GetProcessEnvironmentAsync(this ApiClient client, Guid uid) { @@ -91,7 +109,7 @@ public static Task> GetProcessEnvironmentAsync(this A } /// - /// Get /processes/{uid}/env + /// Get /env?uid={uid} /// public static async Task> GetProcessEnvironmentAsync(this ApiClient client, Guid uid, TimeSpan timeout) { @@ -100,7 +118,7 @@ public static async Task> GetProcessEnvironmentAsync( } /// - /// Get /dump/{pid}?type={dumpType} + /// Get /dump?pid={pid}&type={dumpType} /// public static Task CaptureDumpAsync(this ApiClient client, int pid, DumpType dumpType) { @@ -108,7 +126,7 @@ public static Task CaptureDumpAsync(this ApiClient client, } /// - /// Get /dump/{pid}?type={dumpType} + /// Get /dump?pid={pid}&type={dumpType} /// public static async Task CaptureDumpAsync(this ApiClient client, int pid, DumpType dumpType, TimeSpan timeout) { @@ -117,7 +135,7 @@ public static async Task CaptureDumpAsync(this ApiClient c } /// - /// Get /dump/{uid}?type={dumpType} + /// Get /dump?uid={uid}&type={dumpType} /// public static Task CaptureDumpAsync(this ApiClient client, Guid uid, DumpType dumpType) { @@ -125,7 +143,7 @@ public static Task CaptureDumpAsync(this ApiClient client, } /// - /// Get /dump/{uid}?type={dumpType} + /// Get /dump?uid={uid}&type={dumpType} /// public static async Task CaptureDumpAsync(this ApiClient client, Guid uid, DumpType dumpType, TimeSpan timeout) { @@ -134,7 +152,7 @@ public static async Task CaptureDumpAsync(this ApiClient c } /// - /// GET /logs/{pid}?level={logLevel}&durationSeconds={duration} + /// GET /logs?pid={pid}&level={logLevel}&durationSeconds={duration} /// public static Task CaptureLogsAsync(this ApiClient client, int pid, TimeSpan duration, LogLevel? logLevel, LogFormat logFormat) { @@ -142,7 +160,7 @@ public static Task CaptureLogsAsync(this ApiClient client, } /// - /// GET /logs/{pid}?level={logLevel}&durationSeconds={duration} + /// GET /logs?pid={pid}&level={logLevel}&durationSeconds={duration} /// public static async Task CaptureLogsAsync(this ApiClient client, int pid, TimeSpan duration, LogLevel? logLevel, TimeSpan timeout, LogFormat logFormat) { @@ -151,7 +169,7 @@ public static async Task CaptureLogsAsync(this ApiClient c } /// - /// POST /logs/{pid}?durationSeconds={duration} + /// POST /logs?pid={pid}&durationSeconds={duration} /// public static Task CaptureLogsAsync(this ApiClient client, int pid, TimeSpan duration, LogsConfiguration configuration, LogFormat logFormat) { diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/ProcessTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/ProcessTests.cs index bce2f8ac2c9..7c7ce3153ab 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/ProcessTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/ProcessTests.cs @@ -75,6 +75,7 @@ public Task SingleProcessIdentificationTest(DiagnosticPortConnectionMode mode) /// /// Tests that multiple processes are discoverable by dotnet-monitor. + /// Also tests for correct behavior in response to queries with different/multiple process identifiers. /// [Theory] [InlineData(DiagnosticPortConnectionMode.Connect)] @@ -117,6 +118,47 @@ await appRunners.ExecuteAsync(async () => identifiers = await apiClient.GetProcessesAsync(); Assert.NotNull(identifiers); + List pids = new List(); + List uids = new List(); + List names = new List(); + + foreach (ProcessIdentifier processIdentifier in identifiers) + { + pids.Add(processIdentifier.Pid); + uids.Add(processIdentifier.Uid); + names.Add(processIdentifier.Name); + } + +#if NET5_0_OR_GREATER + // CHECK 1: Get response for processes using PID, UID, and Name and check for consistency + + List processInfoQueriesCheck1 = new List(); + + processInfoQueriesCheck1.Add(await apiClient.GetProcessAsync(pid: pids[0], uid: null, name: null)); + processInfoQueriesCheck1.Add(await apiClient.GetProcessAsync(pid: null, uid: uids[0], name: null)); + + VerifyProcessInfoEquality(processInfoQueriesCheck1); +#endif + // CHECK 2: Get response for requests using PID | PID and UID | PID, UID, and Name and check for consistency + + List processInfoQueriesCheck2 = new List(); + + processInfoQueriesCheck2.Add(await apiClient.GetProcessAsync(pid: pids[0], uid: null, name: null)); + processInfoQueriesCheck2.Add(await apiClient.GetProcessAsync(pid: pids[0], uid: uids[0], name: null)); + processInfoQueriesCheck2.Add(await apiClient.GetProcessAsync(pid: pids[0], uid: uids[0], name: names[0])); + + VerifyProcessInfoEquality(processInfoQueriesCheck2); + + // CHECK 3: Get response for processes using PID and an unassociated (randomly generated) UID and ensure the proper exception is thrown + + await VerifyInvalidRequestException(apiClient, pids[0], Guid.NewGuid(), null); + + // CHECK 4: Get response for processes using invalid PID, UID, or Name and ensure the proper exception is thrown + + await VerifyInvalidRequestException(apiClient, -1, null, null); + await VerifyInvalidRequestException(apiClient, null, Guid.NewGuid(), null); + await VerifyInvalidRequestException(apiClient, null, null, ""); + // Verify each app instance is reported and shut them down. foreach (AppRunner runner in appRunners) { @@ -145,7 +187,39 @@ await appRunners.ExecuteAsync(async () => } /// - /// Verifies that a process was found in the identifiers list and checks the /processes/{processKey} route for the same process. + /// Verifies that each provided instance of ProcessInfo is equivalent in terms of PID, UID, and Name. + /// + private static void VerifyProcessInfoEquality(List processInfos) + { + List processInfoPIDs = new List(); + List processInfoUIDs = new List(); + List processInfoNames = new List(); + + foreach (ProcessInfo processInfo in processInfos) + { + processInfoPIDs.Add(processInfo.Pid); + processInfoUIDs.Add(processInfo.Uid); + processInfoNames.Add(processInfo.Name); + } + + Assert.Single(processInfoPIDs.Distinct()); + Assert.Single(processInfoUIDs.Distinct()); + Assert.Single(processInfoNames.Distinct(StringComparer.Ordinal)); + } + + /// + /// Verifies that an invalid Process request throws the correct exception (ValidationProblemDetailsException) and has the correct Status and StatusCode. + /// + private static async Task VerifyInvalidRequestException(ApiClient client, int? pid, Guid? uid, string name) + { + ValidationProblemDetailsException validationProblemDetailsException = await Assert.ThrowsAsync( + () => client.GetProcessAsync(pid: pid, uid: uid, name: name)); + Assert.Equal(HttpStatusCode.BadRequest, validationProblemDetailsException.StatusCode); + Assert.Equal(StatusCodes.Status400BadRequest, validationProblemDetailsException.Details.Status); + } + + /// + /// Verifies that a process was found in the identifiers list and checks the /process?pid={processKey} route for the same process. /// private static async Task VerifyProcessAsync(ApiClient client, IEnumerable identifiers, int processId, string expectedEnvVarValue) { From 4d37c9077c04d424939c76f003889f3e7bf37fc7 Mon Sep 17 00:00:00 2001 From: Justin Anderson Date: Wed, 30 Jun 2021 13:24:15 -0700 Subject: [PATCH 122/185] Check if test process exits before it is ready. (#488) --- .../Runners/DotNetRunner.cs | 13 +++++++++---- .../Runners/MonitorRunner.cs | 7 +++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.TestCommon/Runners/DotNetRunner.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.TestCommon/Runners/DotNetRunner.cs index f050ebe28ff..f55085fdb69 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.TestCommon/Runners/DotNetRunner.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.TestCommon/Runners/DotNetRunner.cs @@ -22,7 +22,7 @@ public sealed class DotNetRunner : IDisposable private readonly EventHandler _exitedHandler; // Completion source that is signaled when the process exits - private readonly TaskCompletionSource _exitedSource; + private readonly TaskCompletionSource _exitedSource; // The process object of the started process private readonly Process _process; @@ -47,6 +47,11 @@ public sealed class DotNetRunner : IDisposable /// public int ExitCode => _process.ExitCode; + /// + /// Gets a task that completes with the process exit code when it exits. + /// + public Task ExitedTask => _exitedSource.Task; + /// /// The framework reference of the app to run. /// @@ -91,8 +96,8 @@ public DotNetRunner() _process.StartInfo.RedirectStandardInput = true; _process.StartInfo.RedirectStandardOutput = true; - _exitedSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - _exitedHandler = (s, e) => _exitedSource.SetResult(null); + _exitedSource = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); + _exitedHandler = (s, e) => _exitedSource.SetResult(_process.ExitCode); _process.EnableRaisingEvents = true; _process.Exited += _exitedHandler; @@ -163,7 +168,7 @@ public async Task WaitForExitAsync(CancellationToken token) using IDisposable _ = token.Register(() => cancellationSource.TrySetCanceled(token)); await Task.WhenAny( - _exitedSource.Task, + ExitedTask, cancellationSource.Task).Unwrap(); } } diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Runners/MonitorRunner.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Runners/MonitorRunner.cs index 7bbc31c4c5e..16ed759d170 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Runners/MonitorRunner.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Runners/MonitorRunner.cs @@ -230,6 +230,13 @@ public async Task StartAsync(CancellationToken token) using IDisposable _ = token.Register(() => CancelCompletionSources(token)); + // Await ready and exited tasks in case process exits before it is ready. + if (_runner.ExitedTask == await Task.WhenAny(_readySource.Task, _runner.ExitedTask)) + { + throw new InvalidOperationException("Process exited before it was ready."); + } + + // Await ready task to check if it faulted or cancelled. await _readySource.Task; } From 95e4140dcb78b49788e764bbad9a059d134b28e4 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 01:03:18 +0000 Subject: [PATCH 123/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210629.9 (#514) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index cc806d4d80d..171200864a6 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - 348b810d286fd2258aa763d6eda667a83ff972dc + 451799284a7ebd05752636f4adc7f0ac7866db19 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 29618522890..294cef64b00 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21329.8 - 6.0.0-preview.7.21328.9 + 6.0.0-preview.7.21329.9 5.0.0-preview.21329.1 5.0.0-preview.21329.1 From f9f4974709aa6046afef3d24ffb02ffe8a84b333 Mon Sep 17 00:00:00 2001 From: Justin Anderson Date: Wed, 30 Jun 2021 23:33:48 -0700 Subject: [PATCH 124/185] Skip uid-only check for failed uid values. (#516) --- .../ProcessTests.cs | 95 +++++++++++++------ 1 file changed, 68 insertions(+), 27 deletions(-) diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/ProcessTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/ProcessTests.cs index 7c7ce3153ab..d2e4338dbfa 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/ProcessTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/ProcessTests.cs @@ -111,47 +111,80 @@ public async Task MultiProcessIdentificationTest(DiagnosticPortConnectionMode mo appRunners[i] = runner; } - IEnumerable identifiers; + IList identifiers; await appRunners.ExecuteAsync(async () => { // Query for process identifiers - identifiers = await apiClient.GetProcessesAsync(); + identifiers = (await apiClient.GetProcessesAsync()).ToList(); Assert.NotNull(identifiers); - List pids = new List(); - List uids = new List(); - List names = new List(); - - foreach (ProcessIdentifier processIdentifier in identifiers) + // Scope to only the processes that were launched by the test + IList unmatchedPids = new List(); + foreach (AppRunner runner in appRunners) { - pids.Add(processIdentifier.Pid); - uids.Add(processIdentifier.Uid); - names.Add(processIdentifier.Name); + unmatchedPids.Add(runner.ProcessId); } -#if NET5_0_OR_GREATER - // CHECK 1: Get response for processes using PID, UID, and Name and check for consistency - - List processInfoQueriesCheck1 = new List(); + _outputHelper.WriteLine("Start enumerating discovered processes."); + foreach (ProcessIdentifier identifier in identifiers.ToList()) + { + _outputHelper.WriteLine($"- PID: {identifier.Pid}"); + _outputHelper.WriteLine($" UID: {identifier.Uid}"); + _outputHelper.WriteLine($" Name: {identifier.Name}"); + + if (!unmatchedPids.Remove(identifier.Pid)) + { + _outputHelper.WriteLine($" State: Ignored"); + identifiers.Remove(identifier); + } + else + { + _outputHelper.WriteLine($" State: Included"); + } + } + _outputHelper.WriteLine("End enumerating discovered processes"); - processInfoQueriesCheck1.Add(await apiClient.GetProcessAsync(pid: pids[0], uid: null, name: null)); - processInfoQueriesCheck1.Add(await apiClient.GetProcessAsync(pid: null, uid: uids[0], name: null)); + Assert.Empty(unmatchedPids); + Assert.Equal(appRunners.Length, identifiers.Count); - VerifyProcessInfoEquality(processInfoQueriesCheck1); + foreach (ProcessIdentifier processIdentifier in identifiers) + { + int pid = processIdentifier.Pid; + Guid uid = processIdentifier.Uid; + string name = processIdentifier.Name; +#if NET5_0_OR_GREATER + // CHECK 1: Get response for processes using PID, UID, and Name and check for consistency + + List processInfoQueriesCheck1 = new List(); + + processInfoQueriesCheck1.Add(await apiClient.GetProcessAsync(pid: pid, uid: null, name: null)); + // Only check with uid if it is non-empty; this can happen in connect mode if the ProcessInfo command fails + // to respond within the short period of time that is used to get the additional process information. + if (uid == Guid.Empty) + { + _outputHelper.WriteLine("Skipped uid-only check because it is empty GUID."); + } + else + { + processInfoQueriesCheck1.Add(await apiClient.GetProcessAsync(pid: null, uid: uid, name: null)); + } + + VerifyProcessInfoEquality(processInfoQueriesCheck1); #endif - // CHECK 2: Get response for requests using PID | PID and UID | PID, UID, and Name and check for consistency + // CHECK 2: Get response for requests using PID | PID and UID | PID, UID, and Name and check for consistency - List processInfoQueriesCheck2 = new List(); + List processInfoQueriesCheck2 = new List(); - processInfoQueriesCheck2.Add(await apiClient.GetProcessAsync(pid: pids[0], uid: null, name: null)); - processInfoQueriesCheck2.Add(await apiClient.GetProcessAsync(pid: pids[0], uid: uids[0], name: null)); - processInfoQueriesCheck2.Add(await apiClient.GetProcessAsync(pid: pids[0], uid: uids[0], name: names[0])); + processInfoQueriesCheck2.Add(await apiClient.GetProcessAsync(pid: pid, uid: null, name: null)); + processInfoQueriesCheck2.Add(await apiClient.GetProcessAsync(pid: pid, uid: uid, name: null)); + processInfoQueriesCheck2.Add(await apiClient.GetProcessAsync(pid: pid, uid: uid, name: name)); - VerifyProcessInfoEquality(processInfoQueriesCheck2); + VerifyProcessInfoEquality(processInfoQueriesCheck2); - // CHECK 3: Get response for processes using PID and an unassociated (randomly generated) UID and ensure the proper exception is thrown + // CHECK 3: Get response for processes using PID and an unassociated (randomly generated) UID and ensure the proper exception is thrown - await VerifyInvalidRequestException(apiClient, pids[0], Guid.NewGuid(), null); + await VerifyInvalidRequestException(apiClient, pid, Guid.NewGuid(), null); + } // CHECK 4: Get response for processes using invalid PID, UID, or Name and ensure the proper exception is thrown @@ -176,7 +209,7 @@ await appRunners.ExecuteAsync(async () => } // Query for process identifiers - identifiers = await apiClient.GetProcessesAsync(); + identifiers = (await apiClient.GetProcessesAsync()).ToList(); Assert.NotNull(identifiers); // Verify none of the apps are reported @@ -189,19 +222,27 @@ await appRunners.ExecuteAsync(async () => /// /// Verifies that each provided instance of ProcessInfo is equivalent in terms of PID, UID, and Name. /// - private static void VerifyProcessInfoEquality(List processInfos) + private void VerifyProcessInfoEquality(List processInfos) { List processInfoPIDs = new List(); List processInfoUIDs = new List(); List processInfoNames = new List(); + _outputHelper.WriteLine("Start enumerating collected process information."); + foreach (ProcessInfo processInfo in processInfos) { + _outputHelper.WriteLine($"- PID: {processInfo.Pid}"); + _outputHelper.WriteLine($" UID: {processInfo.Uid}"); + _outputHelper.WriteLine($" Name: {processInfo.Name}"); + processInfoPIDs.Add(processInfo.Pid); processInfoUIDs.Add(processInfo.Uid); processInfoNames.Add(processInfo.Name); } + _outputHelper.WriteLine("End enumerating collected process information."); + Assert.Single(processInfoPIDs.Distinct()); Assert.Single(processInfoUIDs.Distinct()); Assert.Single(processInfoNames.Distinct(StringComparer.Ordinal)); From 23ddb51e98c29ebf21f8298128d2a83b4552b687 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 12:47:43 +0000 Subject: [PATCH 125/185] Update dependencies from https://github.com/dotnet/arcade build 20210630.2 (#518) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- global.json | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 171200864a6..b8d1ede511a 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -14,13 +14,13 @@ - + https://github.com/dotnet/arcade - 6b9d24236d8d1906284e6cb6c28e3fe93a69b7d2 + 26345756f99087811b1fe4d02ff213eb172ec506 - + https://github.com/dotnet/arcade - 6b9d24236d8d1906284e6cb6c28e3fe93a69b7d2 + 26345756f99087811b1fe4d02ff213eb172ec506 https://github.com/dotnet/symstore diff --git a/eng/Versions.props b/eng/Versions.props index 294cef64b00..dddc85deefb 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -27,7 +27,7 @@ --> - 6.0.0-beta.21329.8 + 6.0.0-beta.21330.2 6.0.0-preview.7.21329.9 diff --git a/global.json b/global.json index 28840b16a82..f0613c80d74 100644 --- a/global.json +++ b/global.json @@ -16,6 +16,6 @@ }, "msbuild-sdks": { "Microsoft.Build.NoTargets": "2.0.1", - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21329.8" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21330.2" } } From de6f27447b640b98693586e4e5be9bcaf8d4b1ad Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 16:04:48 +0000 Subject: [PATCH 126/185] Update dependencies from https://github.com/dotnet/diagnostics build 20210630.1 (#517) [main] Update dependencies from dotnet/diagnostics --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index b8d1ede511a..38ebf8a2010 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics - a584d05969d1951a86e5d290d5654e30cd10d5aa + 74ee1668d2aba9569a517b6dbd143541283620c3 - + https://github.com/dotnet/diagnostics - a584d05969d1951a86e5d290d5654e30cd10d5aa + 74ee1668d2aba9569a517b6dbd143541283620c3 diff --git a/eng/Versions.props b/eng/Versions.props index dddc85deefb..6c720cd12fa 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-preview.7.21329.9 - 5.0.0-preview.21329.1 - 5.0.0-preview.21329.1 + 5.0.0-preview.21330.1 + 5.0.0-preview.21330.1 6.0.0-preview.7.21330.2 From 811dc33ac4139f1aebdc644567e1da53d4a73792 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 16:10:43 +0000 Subject: [PATCH 127/185] Update dependencies from https://github.com/dotnet/runtime build 20210701.2 (#519) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 38ebf8a2010..0f00e2ccd16 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 451799284a7ebd05752636f4adc7f0ac7866db19 - + https://github.com/dotnet/runtime - ff88d1d3a022021a54fbe05949a27db29c690f0c + cf2938f44fc1494ae984c52a1568a03d51e513ca diff --git a/eng/Versions.props b/eng/Versions.props index 6c720cd12fa..6c62fcb1899 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21330.1 5.0.0-preview.21330.1 - 6.0.0-preview.7.21330.2 + 6.0.0-preview.7.21351.2 1.0.215101 From 2fa567ca9411e115b8c73cdcf679e6fa8df42094 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 16:46:29 +0000 Subject: [PATCH 128/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210630.3 (#520) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 0f00e2ccd16..1bb387a30e4 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - 451799284a7ebd05752636f4adc7f0ac7866db19 + b9efadc59ddbf6743775244622fb95301dd1846c https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 6c62fcb1899..3987feb3b18 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21330.2 - 6.0.0-preview.7.21329.9 + 6.0.0-preview.7.21330.3 5.0.0-preview.21330.1 5.0.0-preview.21330.1 From f23f4bc950c9290313081fbb19f8c62fdf881c6c Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 2 Jul 2021 12:56:11 +0000 Subject: [PATCH 129/185] Update dependencies from https://github.com/dotnet/runtime build 20210702.2 (#526) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 1bb387a30e4..b0eaff032aa 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore b9efadc59ddbf6743775244622fb95301dd1846c - + https://github.com/dotnet/runtime - cf2938f44fc1494ae984c52a1568a03d51e513ca + 4c92aef2b08f9c4374c520e7e664a44f1ad8ce56 diff --git a/eng/Versions.props b/eng/Versions.props index 3987feb3b18..555fad774d0 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21330.1 5.0.0-preview.21330.1 - 6.0.0-preview.7.21351.2 + 6.0.0-preview.7.21352.2 1.0.215101 From c089e1c02525caec316f9eceea5cddb0cf8201c6 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 2 Jul 2021 12:56:20 +0000 Subject: [PATCH 130/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210701.9 (#527) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index b0eaff032aa..806a9abddcf 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - b9efadc59ddbf6743775244622fb95301dd1846c + 640b77f0823f9de872359aa174669efbbd742e72 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 555fad774d0..194eec3f9a1 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21330.2 - 6.0.0-preview.7.21330.3 + 6.0.0-preview.7.21351.9 5.0.0-preview.21330.1 5.0.0-preview.21330.1 From c40fd1c48cc7ddb43dd10b1dbcf32e081314dbc3 Mon Sep 17 00:00:00 2001 From: Justin Anderson Date: Fri, 2 Jul 2021 18:47:45 -0700 Subject: [PATCH 131/185] Retry process routes when name is "unknown" (#521) * Filter "unknown" process names before comparing them. * Fix spelling and add more comments. * Add ability to retry process routes if they do not produce process names. * Change process identifier filter to array of PIDs. --- .../HttpApi/ApiClientExtensions.cs | 82 +++++++++++++++++++ .../ProcessTests.cs | 56 +++++++------ 2 files changed, 112 insertions(+), 26 deletions(-) diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClientExtensions.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClientExtensions.cs index 574e1560d97..ea4b80eb134 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClientExtensions.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClientExtensions.cs @@ -7,8 +7,11 @@ using Microsoft.Extensions.Logging; using System; using System.Collections.Generic; +using System.Linq; +using System.Net; using System.Threading; using System.Threading.Tasks; +using Xunit.Abstractions; namespace Microsoft.Diagnostics.Monitoring.UnitTests.HttpApi { @@ -31,6 +34,45 @@ public static async Task> GetProcessesAsync(this return await client.GetProcessesAsync(timeoutSource.Token).ConfigureAwait(false); } + /// + /// GET /processes with retry attempts + /// + public static async Task> GetProcessesWithRetryAsync(this ApiClient client, ITestOutputHelper outputHelper, int[] pidFilters, int maxAttempts = 5) + { + IList identifiers = null; + + int attempt = 0; + while (attempt < maxAttempts) + { + attempt++; + + outputHelper.WriteLine($"Attempt #{attempt} of {maxAttempts}: GET /processes"); + + identifiers = (await client.GetProcessesAsync()).ToList(); + + if (pidFilters.Length > 0) + { + identifiers = identifiers.Where(i => pidFilters.Contains(i.Pid)).ToList(); + } + + // In .NET 5+, the process name comes from the command line from the ProcessInfo command, which can fail + // or be abandoned if it takes too long to respond. In .NET Core 3.1, the process name comes from the + // command line from issuing a very brief event source trace, which can also fail or be abandoned if it + // takes too long to finish. Additionally, for 'connect' mode, these values are recomputed for every http + // invocation, so a prior invocation could succeed whereas a subsequent one could fail. Much of this could + // be mitigated if process information could be cached between calls. In any of these scenarios, if the + // process name is failed to be determined, the http api will return "unknown". For testing purposes, + // retry getting the process information until it gets the process name successfully or fail the operation + // after a small number of attempts. + if (null != identifiers && !identifiers.Any(identifier => string.Equals("unknown", identifier.Name, StringComparison.Ordinal))) + { + return identifiers; + } + } + + throw new InvalidOperationException("Unable to get processes that have process names."); + } + /// /// Get /process?pid={pid} /// @@ -83,6 +125,46 @@ public static async Task GetProcessAsync(this ApiClient client, Gui return await client.GetProcessAsync(pid: pid, uid: uid, name: name, token: timeoutSource.Token).ConfigureAwait(false); } + /// + /// Get /process?pid={pid}&uid={uid}&name={name} with retry attempts. + /// + public static async Task GetProcessWithRetryAsync(this ApiClient client, ITestOutputHelper outputHelper, int? pid = null, Guid? uid = null, string name = null, int maxAttempts = 5) + { + ProcessInfo processInfo = null; + + int attempt = 0; + while (attempt < maxAttempts) + { + attempt++; + + outputHelper.WriteLine($"Attempt #{attempt} of {maxAttempts}: GET /process"); + try + { + processInfo = await client.GetProcessAsync(pid: pid, uid: uid, name: name); + } + catch (ApiStatusCodeException ex) when (ex.StatusCode == HttpStatusCode.BadRequest) + { + // Handle cases where it fails to locate the single process. + } + + // In .NET 5+, the process name comes from the command line from the ProcessInfo command, which can fail + // or be abandoned if it takes too long to respond. In .NET Core 3.1, the process name comes from the + // command line from issuing a very brief event source trace, which can also fail or be abandoned if it + // takes too long to finish. Additionally, for 'connect' mode, these values are recomputed for every http + // invocation, so a prior invocation could succeed whereas a subsequent one could fail. Much of this could + // be mitigated if process information could be cached between calls. In any of these scenarios, if the + // process name is failed to be determined, the http api will return "unknown". For testing purposes, + // retry getting the process information until it gets the process name successfully or fail the operation + // after a small number of attempts. + if (null != processInfo && !string.Equals("unknown", processInfo.Name, StringComparison.Ordinal)) + { + return processInfo; + } + } + + throw new InvalidOperationException("Unable to get process information that has a process name."); + } + /// /// Get /env?pid={pid} /// diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/ProcessTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/ProcessTests.cs index d2e4338dbfa..01a33e0c0a7 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/ProcessTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/ProcessTests.cs @@ -55,17 +55,27 @@ public Task SingleProcessIdentificationTest(DiagnosticPortConnectionMode mode) TestAppScenarios.AsyncWait.Name, appValidate: async (runner, client) => { - await VerifyProcessAsync(client, await client.GetProcessesAsync(), runner.ProcessId, expectedEnvVarValue); + // GET /processes and filter to just the single process + IEnumerable identifiers = await client.GetProcessesWithRetryAsync( + _outputHelper, + new[] { runner.ProcessId }); + Assert.NotNull(identifiers); + Assert.Single(identifiers); + + await VerifyProcessAsync(client, identifiers, runner.ProcessId, expectedEnvVarValue); await runner.SendCommandAsync(TestAppScenarios.AsyncWait.Commands.Continue); }, postAppValidate: async (client, processId) => { + // GET /processes and filter to just the single process + IEnumerable identifiers = await client.GetProcessesWithRetryAsync( + _outputHelper, + new[] { processId }); + // Verify app is no longer reported - IEnumerable identifiers = await client.GetProcessesAsync(); Assert.NotNull(identifiers); - ProcessIdentifier identifier = identifiers.FirstOrDefault(p => p.Pid == processId); - Assert.Null(identifier); + Assert.Empty(identifiers); }, configureApp: runner => { @@ -114,10 +124,6 @@ public async Task MultiProcessIdentificationTest(DiagnosticPortConnectionMode mo IList identifiers; await appRunners.ExecuteAsync(async () => { - // Query for process identifiers - identifiers = (await apiClient.GetProcessesAsync()).ToList(); - Assert.NotNull(identifiers); - // Scope to only the processes that were launched by the test IList unmatchedPids = new List(); foreach (AppRunner runner in appRunners) @@ -125,6 +131,12 @@ await appRunners.ExecuteAsync(async () => unmatchedPids.Add(runner.ProcessId); } + // Query for process identifiers + identifiers = (await apiClient.GetProcessesWithRetryAsync( + _outputHelper, + unmatchedPids.ToArray())).ToList(); + Assert.NotNull(identifiers); + _outputHelper.WriteLine("Start enumerating discovered processes."); foreach (ProcessIdentifier identifier in identifiers.ToList()) { @@ -132,15 +144,7 @@ await appRunners.ExecuteAsync(async () => _outputHelper.WriteLine($" UID: {identifier.Uid}"); _outputHelper.WriteLine($" Name: {identifier.Name}"); - if (!unmatchedPids.Remove(identifier.Pid)) - { - _outputHelper.WriteLine($" State: Ignored"); - identifiers.Remove(identifier); - } - else - { - _outputHelper.WriteLine($" State: Included"); - } + unmatchedPids.Remove(identifier.Pid); } _outputHelper.WriteLine("End enumerating discovered processes"); @@ -157,7 +161,7 @@ await appRunners.ExecuteAsync(async () => List processInfoQueriesCheck1 = new List(); - processInfoQueriesCheck1.Add(await apiClient.GetProcessAsync(pid: pid, uid: null, name: null)); + processInfoQueriesCheck1.Add(await apiClient.GetProcessWithRetryAsync(_outputHelper, pid: pid)); // Only check with uid if it is non-empty; this can happen in connect mode if the ProcessInfo command fails // to respond within the short period of time that is used to get the additional process information. if (uid == Guid.Empty) @@ -166,7 +170,7 @@ await appRunners.ExecuteAsync(async () => } else { - processInfoQueriesCheck1.Add(await apiClient.GetProcessAsync(pid: null, uid: uid, name: null)); + processInfoQueriesCheck1.Add(await apiClient.GetProcessWithRetryAsync(_outputHelper, uid: uid)); } VerifyProcessInfoEquality(processInfoQueriesCheck1); @@ -175,9 +179,9 @@ await appRunners.ExecuteAsync(async () => List processInfoQueriesCheck2 = new List(); - processInfoQueriesCheck2.Add(await apiClient.GetProcessAsync(pid: pid, uid: null, name: null)); - processInfoQueriesCheck2.Add(await apiClient.GetProcessAsync(pid: pid, uid: uid, name: null)); - processInfoQueriesCheck2.Add(await apiClient.GetProcessAsync(pid: pid, uid: uid, name: name)); + processInfoQueriesCheck2.Add(await apiClient.GetProcessWithRetryAsync(_outputHelper, pid: pid)); + processInfoQueriesCheck2.Add(await apiClient.GetProcessWithRetryAsync(_outputHelper, pid: pid, uid: uid)); + processInfoQueriesCheck2.Add(await apiClient.GetProcessWithRetryAsync(_outputHelper, pid: pid, uid: uid, name: name)); VerifyProcessInfoEquality(processInfoQueriesCheck2); @@ -251,7 +255,7 @@ private void VerifyProcessInfoEquality(List processInfos) /// /// Verifies that an invalid Process request throws the correct exception (ValidationProblemDetailsException) and has the correct Status and StatusCode. /// - private static async Task VerifyInvalidRequestException(ApiClient client, int? pid, Guid? uid, string name) + private async Task VerifyInvalidRequestException(ApiClient client, int? pid, Guid? uid, string name) { ValidationProblemDetailsException validationProblemDetailsException = await Assert.ThrowsAsync( () => client.GetProcessAsync(pid: pid, uid: uid, name: name)); @@ -262,19 +266,19 @@ private static async Task VerifyInvalidRequestException(ApiClient client, int? p /// /// Verifies that a process was found in the identifiers list and checks the /process?pid={processKey} route for the same process. /// - private static async Task VerifyProcessAsync(ApiClient client, IEnumerable identifiers, int processId, string expectedEnvVarValue) + private async Task VerifyProcessAsync(ApiClient client, IEnumerable identifiers, int processId, string expectedEnvVarValue) { Assert.NotNull(identifiers); ProcessIdentifier identifier = identifiers.FirstOrDefault(p => p.Pid == processId); Assert.NotNull(identifier); - ProcessInfo info = await client.GetProcessAsync(identifier.Pid); + ProcessInfo info = await client.GetProcessWithRetryAsync(_outputHelper, pid: identifier.Pid); Assert.NotNull(info); Assert.Equal(identifier.Pid, info.Pid); #if NET5_0_OR_GREATER // Currently, the runtime instance identifier is only provided for .NET 5 and higher - info = await client.GetProcessAsync(identifier.Uid); + info = await client.GetProcessWithRetryAsync(_outputHelper, uid: identifier.Uid); Assert.NotNull(info); Assert.Equal(identifier.Pid, info.Pid); Assert.Equal(identifier.Uid, info.Uid); From 994ae173fe874777138cadffe1d4269e34e791a7 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 3 Jul 2021 03:37:37 +0000 Subject: [PATCH 132/185] Update dependencies from https://github.com/dotnet/arcade build 20210701.2 (#525) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- global.json | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 806a9abddcf..dde5e29fd6c 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -14,13 +14,13 @@ - + https://github.com/dotnet/arcade - 26345756f99087811b1fe4d02ff213eb172ec506 + 7f52af24016a4b749a2c1f219105c0f5a7100028 - + https://github.com/dotnet/arcade - 26345756f99087811b1fe4d02ff213eb172ec506 + 7f52af24016a4b749a2c1f219105c0f5a7100028 https://github.com/dotnet/symstore diff --git a/eng/Versions.props b/eng/Versions.props index 194eec3f9a1..c3920162118 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -27,7 +27,7 @@ --> - 6.0.0-beta.21330.2 + 6.0.0-beta.21351.2 6.0.0-preview.7.21351.9 diff --git a/global.json b/global.json index f0613c80d74..bdc549f7fed 100644 --- a/global.json +++ b/global.json @@ -16,6 +16,6 @@ }, "msbuild-sdks": { "Microsoft.Build.NoTargets": "2.0.1", - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21330.2" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21351.2" } } From acdaf685416f641ae8a6a1f60c315158e6c062f1 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 3 Jul 2021 04:02:45 +0000 Subject: [PATCH 133/185] [main] Update dependencies from dotnet/diagnostics (#524) [main] Update dependencies from dotnet/diagnostics - Fix namespace inclusion for *EndpointInfoSource and EndpointInfo types. --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- .../EndpointInfoSourceTests.cs | 1 + 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index dde5e29fd6c..4bfd8042993 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics - 74ee1668d2aba9569a517b6dbd143541283620c3 + 1704288a7df0eaa4c080c382518d06b4a312d638 - + https://github.com/dotnet/diagnostics - 74ee1668d2aba9569a517b6dbd143541283620c3 + 1704288a7df0eaa4c080c382518d06b4a312d638 diff --git a/eng/Versions.props b/eng/Versions.props index c3920162118..7cf28ec05cc 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-preview.7.21351.9 - 5.0.0-preview.21330.1 - 5.0.0-preview.21330.1 + 5.0.0-preview.21351.1 + 5.0.0-preview.21351.1 6.0.0-preview.7.21352.2 diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/EndpointInfoSourceTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/EndpointInfoSourceTests.cs index 3545abb1404..a9a1abad4b0 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/EndpointInfoSourceTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/EndpointInfoSourceTests.cs @@ -4,6 +4,7 @@ using Microsoft.Diagnostics.Monitoring.TestCommon; using Microsoft.Diagnostics.Monitoring.UnitTests.Runners; +using Microsoft.Diagnostics.Monitoring.WebApi; using System; using System.Collections.Generic; using System.Linq; From 5c11414079dc75978c32670559a5a7a3c0581d6a Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 3 Jul 2021 12:47:10 +0000 Subject: [PATCH 134/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210702.7 (#533) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 4bfd8042993..a60f45066e2 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - 640b77f0823f9de872359aa174669efbbd742e72 + 83cc8be71b9e38490898a19b273983d02f569a8e https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 7cf28ec05cc..9b28daeab18 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21351.2 - 6.0.0-preview.7.21351.9 + 6.0.0-preview.7.21352.7 5.0.0-preview.21351.1 5.0.0-preview.21351.1 From 8fce2fe678b68f2ed2d0cd8888eaa39203cb5eab Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sun, 4 Jul 2021 12:42:14 +0000 Subject: [PATCH 135/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210703.3 (#534) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index a60f45066e2..37d5fc106bc 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - 83cc8be71b9e38490898a19b273983d02f569a8e + 1b819d05de41561cc974af066737c38ded877ef7 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 9b28daeab18..2737db635ca 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21351.2 - 6.0.0-preview.7.21352.7 + 6.0.0-preview.7.21353.3 5.0.0-preview.21351.1 5.0.0-preview.21351.1 From 8b6a28b43a8aa7268ccd0489dfc5b94cb886a4a7 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 5 Jul 2021 12:40:01 +0000 Subject: [PATCH 136/185] Update dependencies from https://github.com/dotnet/diagnostics build 20210702.1 (#535) [main] Update dependencies from dotnet/diagnostics --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 37d5fc106bc..b4f57b996e3 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics - 1704288a7df0eaa4c080c382518d06b4a312d638 + 6296c96f20b29f9274be5da8d367815762cc18d1 - + https://github.com/dotnet/diagnostics - 1704288a7df0eaa4c080c382518d06b4a312d638 + 6296c96f20b29f9274be5da8d367815762cc18d1 diff --git a/eng/Versions.props b/eng/Versions.props index 2737db635ca..1450a472e40 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-preview.7.21353.3 - 5.0.0-preview.21351.1 - 5.0.0-preview.21351.1 + 5.0.0-preview.21352.1 + 5.0.0-preview.21352.1 6.0.0-preview.7.21352.2 From af54d0d7ccfe5f13c662743c0fefbb40b8a17ee4 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 5 Jul 2021 12:49:12 +0000 Subject: [PATCH 137/185] [main] Update dependencies from dotnet/runtime (#532) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index b4f57b996e3..e0f535f22b0 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 1b819d05de41561cc974af066737c38ded877ef7 - + https://github.com/dotnet/runtime - 4c92aef2b08f9c4374c520e7e664a44f1ad8ce56 + 5c340e9ade0baf7f3c0aa0a9128bf36b158fe7d6 diff --git a/eng/Versions.props b/eng/Versions.props index 1450a472e40..bb38a41221f 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21352.1 5.0.0-preview.21352.1 - 6.0.0-preview.7.21352.2 + 6.0.0-preview.7.21355.1 1.0.215101 From 3d9996b50220172e4d66e4ef64428579e933267d Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 6 Jul 2021 12:57:04 +0000 Subject: [PATCH 138/185] Update dependencies from https://github.com/dotnet/runtime build 20210706.2 (#538) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index e0f535f22b0..02a5ea8c7a1 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 1b819d05de41561cc974af066737c38ded877ef7 - + https://github.com/dotnet/runtime - 5c340e9ade0baf7f3c0aa0a9128bf36b158fe7d6 + 566b53a66b0afa573f0dae33d07c8de9685aa5c8 diff --git a/eng/Versions.props b/eng/Versions.props index bb38a41221f..2d9a988be8f 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21352.1 5.0.0-preview.21352.1 - 6.0.0-preview.7.21355.1 + 6.0.0-preview.7.21356.2 1.0.215101 From e9c833184767b364b8a318d2d2c0e2ef38e83e04 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 6 Jul 2021 12:57:12 +0000 Subject: [PATCH 139/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210705.4 (#539) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 02a5ea8c7a1..fa8320493be 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - 1b819d05de41561cc974af066737c38ded877ef7 + 60b90db5c5bcc605c23017e6d07844c7d67bdec0 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 2d9a988be8f..346dca7c88a 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21351.2 - 6.0.0-preview.7.21353.3 + 6.0.0-preview.7.21355.4 5.0.0-preview.21352.1 5.0.0-preview.21352.1 From 3fc88768dee3f612db23df086a2e366eefebab26 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 7 Jul 2021 12:43:57 +0000 Subject: [PATCH 140/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210707.1 (#542) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index fa8320493be..6b695f0e17e 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - 60b90db5c5bcc605c23017e6d07844c7d67bdec0 + 1d7ee979fec5a09ac82cfae0db1f039e63fea4dc https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 346dca7c88a..467f6379c0a 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21351.2 - 6.0.0-preview.7.21355.4 + 6.0.0-preview.7.21357.1 5.0.0-preview.21352.1 5.0.0-preview.21352.1 From a9a3fc817ff60da7de5819bff2f4fbe91fdcf22c Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 7 Jul 2021 18:18:21 +0000 Subject: [PATCH 141/185] Update dependencies from https://github.com/dotnet/diagnostics build 20210705.1 (#536) [main] Update dependencies from dotnet/diagnostics --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 6b695f0e17e..c20bb048bda 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics - 6296c96f20b29f9274be5da8d367815762cc18d1 + b9f2ffba9ad0c5b2d6fb7701016ae36292ba29e3 - + https://github.com/dotnet/diagnostics - 6296c96f20b29f9274be5da8d367815762cc18d1 + b9f2ffba9ad0c5b2d6fb7701016ae36292ba29e3 diff --git a/eng/Versions.props b/eng/Versions.props index 467f6379c0a..2612789dbf2 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-preview.7.21357.1 - 5.0.0-preview.21352.1 - 5.0.0-preview.21352.1 + 5.0.0-preview.21355.1 + 5.0.0-preview.21355.1 6.0.0-preview.7.21356.2 From 6ddef905185f52b453cefcf72b665bd255a8d815 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 7 Jul 2021 18:18:47 +0000 Subject: [PATCH 142/185] Update dependencies from https://github.com/dotnet/arcade build 20210705.2 (#537) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- eng/common/SetupNugetSources.ps1 | 6 ++++++ eng/common/SetupNugetSources.sh | 24 ++++++++++++++++++++++++ global.json | 2 +- 5 files changed, 36 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index c20bb048bda..0dc19b758f0 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -14,13 +14,13 @@ - + https://github.com/dotnet/arcade - 7f52af24016a4b749a2c1f219105c0f5a7100028 + 615fbd8c498067deae160a696701eaf33155da56 - + https://github.com/dotnet/arcade - 7f52af24016a4b749a2c1f219105c0f5a7100028 + 615fbd8c498067deae160a696701eaf33155da56 https://github.com/dotnet/symstore diff --git a/eng/Versions.props b/eng/Versions.props index 2612789dbf2..afdd8fe9fdb 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -27,7 +27,7 @@ --> - 6.0.0-beta.21351.2 + 6.0.0-beta.21355.2 6.0.0-preview.7.21357.1 diff --git a/eng/common/SetupNugetSources.ps1 b/eng/common/SetupNugetSources.ps1 index a0b5fc37f43..18823840b11 100644 --- a/eng/common/SetupNugetSources.ps1 +++ b/eng/common/SetupNugetSources.ps1 @@ -158,4 +158,10 @@ if ($dotnet5Source -ne $null) { AddPackageSource -Sources $sources -SourceName "dotnet5-internal-transport" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet5-internal-transport/nuget/v2" -Creds $creds -Username $userName -Password $Password } +$dotnet6Source = $sources.SelectSingleNode("add[@key='dotnet6']") +if ($dotnet6Source -ne $null) { + AddPackageSource -Sources $sources -SourceName "dotnet6-internal" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet6-internal/nuget/v2" -Creds $creds -Username $userName -Password $Password + AddPackageSource -Sources $sources -SourceName "dotnet6-internal-transport" -SourceEndPoint "https://pkgs.dev.azure.com/dnceng/internal/_packaging/dotnet6-internal-transport/nuget/v2" -Creds $creds -Username $userName -Password $Password +} + $doc.Save($filename) diff --git a/eng/common/SetupNugetSources.sh b/eng/common/SetupNugetSources.sh index 2734601c13c..ad3fb74fd2c 100644 --- a/eng/common/SetupNugetSources.sh +++ b/eng/common/SetupNugetSources.sh @@ -129,6 +129,30 @@ if [ "$?" == "0" ]; then PackageSources+=('dotnet5-internal-transport') fi +# Ensure dotnet6-internal and dotnet6-internal-transport are in the packageSources if the public dotnet6 feeds are present +grep -i "" + + sed -i.bak "s|$PackageSourcesNodeFooter|$PackageSourceTemplate${NL}$PackageSourcesNodeFooter|" $ConfigFile + fi + PackageSources+=('dotnet6-internal') + + grep -i "" $ConfigFile + if [ "$?" != "0" ]; then + echo "Adding dotnet6-internal-transport to the packageSources." + PackageSourcesNodeFooter="" + PackageSourceTemplate="${TB}" + + sed -i.bak "s|$PackageSourcesNodeFooter|$PackageSourceTemplate${NL}$PackageSourcesNodeFooter|" $ConfigFile + fi + PackageSources+=('dotnet6-internal-transport') +fi + # I want things split line by line PrevIFS=$IFS IFS=$'\n' diff --git a/global.json b/global.json index bdc549f7fed..7418fe79b49 100644 --- a/global.json +++ b/global.json @@ -16,6 +16,6 @@ }, "msbuild-sdks": { "Microsoft.Build.NoTargets": "2.0.1", - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21351.2" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21355.2" } } From 06afbb4758444347d54566e1f070649c2105e8f6 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 8 Jul 2021 12:48:11 +0000 Subject: [PATCH 143/185] Update dependencies from https://github.com/dotnet/arcade build 20210707.3 (#545) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- global.json | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 0dc19b758f0..223a0440890 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -14,13 +14,13 @@ - + https://github.com/dotnet/arcade - 615fbd8c498067deae160a696701eaf33155da56 + 286d98094b830b8dad769542b2669cb1b75f7097 - + https://github.com/dotnet/arcade - 615fbd8c498067deae160a696701eaf33155da56 + 286d98094b830b8dad769542b2669cb1b75f7097 https://github.com/dotnet/symstore diff --git a/eng/Versions.props b/eng/Versions.props index afdd8fe9fdb..0c7cbea5963 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -27,7 +27,7 @@ --> - 6.0.0-beta.21355.2 + 6.0.0-beta.21357.3 6.0.0-preview.7.21357.1 diff --git a/global.json b/global.json index 7418fe79b49..99caa06cd98 100644 --- a/global.json +++ b/global.json @@ -16,6 +16,6 @@ }, "msbuild-sdks": { "Microsoft.Build.NoTargets": "2.0.1", - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21355.2" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21357.3" } } From 996aefefc3b968e8646dbbebd4ad04cbc18ccfd7 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 8 Jul 2021 16:30:34 +0000 Subject: [PATCH 144/185] Update dependencies from https://github.com/dotnet/diagnostics build 20210707.1 (#544) [main] Update dependencies from dotnet/diagnostics --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 223a0440890..4c1ea028b34 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics - b9f2ffba9ad0c5b2d6fb7701016ae36292ba29e3 + 715a291ab3d73098e6f05fada2f72581da2539f2 - + https://github.com/dotnet/diagnostics - b9f2ffba9ad0c5b2d6fb7701016ae36292ba29e3 + 715a291ab3d73098e6f05fada2f72581da2539f2 diff --git a/eng/Versions.props b/eng/Versions.props index 0c7cbea5963..dcd82facbf1 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-preview.7.21357.1 - 5.0.0-preview.21355.1 - 5.0.0-preview.21355.1 + 5.0.0-preview.21357.1 + 5.0.0-preview.21357.1 6.0.0-preview.7.21356.2 From aaacae57795647bd9b2e8e4459a86210b78767eb Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 8 Jul 2021 16:38:26 +0000 Subject: [PATCH 145/185] Update dependencies from https://github.com/dotnet/runtime build 20210707.1 (#541) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 4c1ea028b34..0ed26236ae5 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 1d7ee979fec5a09ac82cfae0db1f039e63fea4dc - + https://github.com/dotnet/runtime - 566b53a66b0afa573f0dae33d07c8de9685aa5c8 + c6b61fb32627e3eede21ad9d9cf18400084c40a2 diff --git a/eng/Versions.props b/eng/Versions.props index dcd82facbf1..788e40f849b 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21357.1 5.0.0-preview.21357.1 - 6.0.0-preview.7.21356.2 + 6.0.0-preview.7.21357.1 1.0.215101 From c7fd20b6d3ad44390109bc2df0c2bdd41c52c766 Mon Sep 17 00:00:00 2001 From: Wiktor Kopec Date: Thu, 8 Jul 2021 15:10:56 -0700 Subject: [PATCH 146/185] Normalize prometheus metrics (#543) * Normalize prometheus metrics - Also fixup some namespaces * CR Feedback * Additional test for IsLetter/IsDigit --- .../IMetricsStore.cs | 2 +- .../MetricsLogger.cs | 2 +- .../MetricsStore.cs | 36 +----- .../ProcessKey.cs | 2 +- .../PrometheusDataModel.cs | 104 ++++++++++++++++++ .../ScopeState.cs | 2 +- .../MetricsExportTests.cs | 51 +++++++++ 7 files changed, 163 insertions(+), 36 deletions(-) create mode 100644 src/Microsoft.Diagnostics.Monitoring.WebApi/PrometheusDataModel.cs create mode 100644 src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/MetricsExportTests.cs diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/IMetricsStore.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/IMetricsStore.cs index b3c18706f18..e8806d88700 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/IMetricsStore.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/IMetricsStore.cs @@ -10,7 +10,7 @@ using System.Threading; using System.Threading.Tasks; -namespace Microsoft.Diagnostics.Monitoring +namespace Microsoft.Diagnostics.Monitoring.WebApi { /// /// Used to store metrics. A snapshot will be requested periodically. diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/MetricsLogger.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/MetricsLogger.cs index 4aaee3fd8f5..b77f4e71fc6 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/MetricsLogger.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/MetricsLogger.cs @@ -8,7 +8,7 @@ using System.IO; using System.Text; -namespace Microsoft.Diagnostics.Monitoring +namespace Microsoft.Diagnostics.Monitoring.WebApi { internal sealed class MetricsLogger : ICountersLogger { diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/MetricsStore.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/MetricsStore.cs index 32df5695bc0..4ff1ec04259 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/MetricsStore.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/MetricsStore.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using Microsoft.Diagnostics.Monitoring.EventPipe; -using Microsoft.Diagnostics.Monitoring.WebApi; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -14,22 +13,13 @@ using System.Threading; using System.Threading.Tasks; -namespace Microsoft.Diagnostics.Monitoring +namespace Microsoft.Diagnostics.Monitoring.WebApi { /// /// Stores metrics, and produces a snapshot in Prometheus exposition format. /// internal sealed class MetricsStore : IMetricsStore { - private static readonly Dictionary KnownUnits = new Dictionary(StringComparer.OrdinalIgnoreCase) - { - {string.Empty, string.Empty}, - {"count", string.Empty}, - {"B", "_bytes" }, - {"MB", "_bytes" }, - {"%", "_ratio" }, - }; - private sealed class MetricKey { private ICounterPayload _metric; @@ -105,7 +95,9 @@ public async Task SnapshotMetrics(Stream outputStream, CancellationToken token) foreach (var metricGroup in copy) { ICounterPayload metricInfo = metricGroup.Value.First(); - string metricName = GetPrometheusMetric(metricInfo, out string metricValue); + string metricName = PrometheusDataModel.Normalize(metricInfo.Provider, metricInfo.Name, + metricInfo.Unit, metricInfo.Value, out string metricValue); + string metricType = "gauge"; //TODO Some clr metrics claim to be incrementing, but are really gauges. @@ -130,26 +122,6 @@ private static async Task WriteMetricDetails( await writer.WriteLineAsync(FormattableString.Invariant($" {metricValue} {new DateTimeOffset(metric.Timestamp).ToUnixTimeMilliseconds()}")); } - private static string GetPrometheusMetric(ICounterPayload metric, out string metricValue) - { - string unitSuffix = string.Empty; - - if ((metric.Unit != null) && (!KnownUnits.TryGetValue(metric.Unit, out unitSuffix))) - { - //TODO The prometheus data model does not allow certain characters. Units we are not expecting could cause a scrape failure. - unitSuffix = "_" + metric.Unit; - } - - double value = metric.Value; - if (string.Equals(metric.Unit, "MB", StringComparison.OrdinalIgnoreCase)) - { - value *= 1_000_000; //Note that the metric uses MB not MiB - } - - metricValue = value.ToString(CultureInfo.InvariantCulture); - return FormattableString.Invariant($"{metric.Provider.Replace(".", string.Empty).ToLowerInvariant()}_{metric.Name.Replace('-', '_')}{unitSuffix}"); - } - private static bool CompareMetrics(ICounterPayload first, ICounterPayload second) { return string.Equals(first.Name, second.Name); diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/ProcessKey.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/ProcessKey.cs index 10768a1dd51..21ae996dde3 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/ProcessKey.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/ProcessKey.cs @@ -6,7 +6,7 @@ using System.ComponentModel; using System.Globalization; -namespace Microsoft.Diagnostics.Monitoring +namespace Microsoft.Diagnostics.Monitoring.WebApi { [TypeConverter(typeof(ProcessKeyTypeConverter))] internal struct ProcessKey diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/PrometheusDataModel.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/PrometheusDataModel.cs new file mode 100644 index 00000000000..52635082bd2 --- /dev/null +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/PrometheusDataModel.cs @@ -0,0 +1,104 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + + +using Microsoft.Diagnostics.Monitoring.EventPipe; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Microsoft.Diagnostics.Monitoring.WebApi +{ + internal static class PrometheusDataModel + { + private const char SeperatorChar = '_'; + + private static readonly Dictionary KnownUnits = new Dictionary(StringComparer.OrdinalIgnoreCase) + { + {string.Empty, string.Empty}, + {"count", string.Empty}, + {"B", "bytes" }, + {"MB", "bytes" }, + {"%", "ratio" }, + }; + + public static string Normalize(string metricProvider, string metric, string unit, double value, out string metricValue) + { + string baseUnit = null; + if ((unit != null) && (!KnownUnits.TryGetValue(unit, out baseUnit))) + { + baseUnit = unit; + } + if (string.Equals(unit, "MB", StringComparison.OrdinalIgnoreCase)) + { + value *= 1_000_000; //Note that the metric uses MB not MiB + } + metricValue = value.ToString(CultureInfo.InvariantCulture); + + bool hasUnit = !string.IsNullOrEmpty(baseUnit); + + //The +1's account for separators + //CONSIDER Can we optimize with Span/stackalloc here instead of using StringBuilder? + StringBuilder builder = new StringBuilder(metricProvider.Length + metric.Length + (hasUnit ? baseUnit.Length + 1 : 0) + 1); + + NormalizeString(builder, metricProvider, isProvider: true); + builder.Append(SeperatorChar); + NormalizeString(builder, metric, isProvider: false); + if (hasUnit) + { + builder.Append(SeperatorChar); + NormalizeString(builder, baseUnit, isProvider: false); + } + + return builder.ToString(); + } + + private static void NormalizeString(StringBuilder builder, string entity, bool isProvider) + { + //TODO We don't have any labels in the current metrics implementation, but may need to add support for it + //for tags in the new dotnet metrics. Labels have some additional restrictions. + + bool allInvalid = true; + for (int i = 0; i < entity.Length; i++) + { + if (IsValidChar(entity[i], i == 0)) + { + allInvalid = false; + builder.Append(isProvider ? char.ToLowerInvariant(entity[i]) : entity[i]); + } + else if (!isProvider) + { + builder.Append(SeperatorChar); + } + } + + //CONSIDER Completely invalid providers such as '!@#$' will become '_'. Should we have a more obvious value for this? + if (allInvalid && isProvider) + { + builder.Append(SeperatorChar); + } + } + private static bool IsValidChar(char c, bool isFirst) + { + if (c > 'z') + { + return false; + } + + if (c == SeperatorChar) + { + return true; + } + + if (isFirst) + { + return char.IsLetter(c); + } + return char.IsLetterOrDigit(c); + } + } +} diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/ScopeState.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/ScopeState.cs index a8b66033437..c8e6ff1916b 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/ScopeState.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/ScopeState.cs @@ -7,7 +7,7 @@ using System.Collections.Generic; using System.Text; -namespace Microsoft.Diagnostics.Monitoring +namespace Microsoft.Diagnostics.Monitoring.WebApi { internal sealed class ScopeState : IEnumerable>> { diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/MetricsExportTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/MetricsExportTests.cs new file mode 100644 index 00000000000..3b8f544109f --- /dev/null +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.UnitTests/MetricsExportTests.cs @@ -0,0 +1,51 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Diagnostics.Monitoring.EventPipe; +using Microsoft.Diagnostics.Monitoring.WebApi; +using Microsoft.Diagnostics.Monitoring.TestCommon; +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Globalization; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Security.Cryptography; +using System.Threading.Tasks; +using Xunit; + +namespace Microsoft.Diagnostics.Monitoring.UnitTests +{ + public class MetricsExportTests + { + [Fact] + public void TestPrometheusNormalization() + { + string metric = Normalize("Test-Provider", "Test-Metric"); + Assert.Equal("testprovider_Test_Metric_bytes", metric); + + metric = Normalize("!@#", "#@#"); + //__ + //provider becomes '_' + //metric becomes '___' + //unit defaults to bytes + Assert.Equal("______bytes", metric); + + metric = Normalize("Asp-Net-Provider", "Requests!Received", "0$customs"); + Assert.Equal("aspnetprovider_Requests_Received___customs", metric); + + metric = Normalize("a", "b", unit: null); + Assert.Equal("a_b", metric); + + metric = Normalize("UnicodeάήΰLetter", "Unicode\u0befDigit", unit: null); + Assert.Equal("unicodeletter_Unicode_Digit", metric); + } + + private static string Normalize(string provider, string name, string unit = "b") + { + return PrometheusDataModel.Normalize(provider, name, unit, 0.0, out _); + } + } +} From 6195f06fe682c9f67a005355e1654c85ad32d8f9 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 9 Jul 2021 12:39:36 +0000 Subject: [PATCH 147/185] Update dependencies from https://github.com/dotnet/diagnostics build 20210708.1 (#547) [main] Update dependencies from dotnet/diagnostics --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 0ed26236ae5..6a31ad5ae5d 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics - 715a291ab3d73098e6f05fada2f72581da2539f2 + 429f3b7edddeab32ecfe7d18947dbb02d11cde27 - + https://github.com/dotnet/diagnostics - 715a291ab3d73098e6f05fada2f72581da2539f2 + 429f3b7edddeab32ecfe7d18947dbb02d11cde27 diff --git a/eng/Versions.props b/eng/Versions.props index 788e40f849b..5408fe94aaa 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-preview.7.21357.1 - 5.0.0-preview.21357.1 - 5.0.0-preview.21357.1 + 5.0.0-preview.21358.1 + 5.0.0-preview.21358.1 6.0.0-preview.7.21357.1 From be53140025267795ac9ac77fc0e13c974af2e375 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 9 Jul 2021 12:48:27 +0000 Subject: [PATCH 148/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210708.5 (#549) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 6a31ad5ae5d..997fe192814 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - 1d7ee979fec5a09ac82cfae0db1f039e63fea4dc + 0f37ede529d5b16aec856039ce18568d15d223e2 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 5408fe94aaa..1fc71aa6c1a 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21357.3 - 6.0.0-preview.7.21357.1 + 6.0.0-preview.7.21358.5 5.0.0-preview.21358.1 5.0.0-preview.21358.1 From 2077760cf4cf5c33de769a0b51c66c67bfab4065 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 9 Jul 2021 15:50:29 +0000 Subject: [PATCH 149/185] Update dependencies from https://github.com/dotnet/runtime build 20210709.1 (#548) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 997fe192814..3607ea0bff3 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 0f37ede529d5b16aec856039ce18568d15d223e2 - + https://github.com/dotnet/runtime - c6b61fb32627e3eede21ad9d9cf18400084c40a2 + d431d6a15726797965336176efe9ae15aba241fd diff --git a/eng/Versions.props b/eng/Versions.props index 1fc71aa6c1a..05012ff5ca8 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21358.1 5.0.0-preview.21358.1 - 6.0.0-preview.7.21357.1 + 6.0.0-preview.7.21359.1 1.0.215101 From 524c3c2555ef01e7feec731455e4b8db2e931095 Mon Sep 17 00:00:00 2001 From: Justin Anderson Date: Fri, 9 Jul 2021 09:37:45 -0700 Subject: [PATCH 150/185] Refactor egress configuration for better schema documentation and configurability (#515) * Refactor egress configuration for better schema documentation. Add schema documentation for egress and provider options. Rewrite egress to be easily registerable and extendable. Minor localization fixes. * Fix spelling * Rename some parameters and fields. * Use standard change notification for egress options. * PR Feedback --- documentation/configuration.md | 8 +- documentation/schema.json | 112 ++++++++++-- .../OptionsDisplayStrings.Designer.cs | 106 ++++++++++- .../OptionsDisplayStrings.resx | 52 +++++- .../SchemaGenerator.cs | 8 +- ...agnostics.Monitoring.Tool.UnitTests.csproj | 4 + .../dotnet-monitor/ConfigurationJsonWriter.cs | 107 ++++++----- .../AzureBlobEgressPostConfigureOptions.cs | 61 +++++++ .../AzureBlob/AzureBlobEgressProvider.cs | 83 ++++----- ...AzureBlobEgressProviderOptions.Validate.cs | 35 ++++ .../AzureBlobEgressProviderOptions.cs | 81 ++++----- .../Egress/AzureBlobEgressFactory.cs | 166 ------------------ .../EgressConfigurationExtensions.cs | 8 + .../Configuration/EgressConfigureOptions.cs | 115 ------------ .../Egress/Configuration/EgressOptions.cs | 28 --- .../Configuration/EgressOptionsCache.cs | 75 ++++++++ ...ropertiesConfigurationChangeTokenSource.cs | 21 +++ .../EgressPropertiesConfigurationProvider.cs | 23 +++ .../Configuration/EgressPropertiesProvider.cs | 35 ++++ ...sProviderConfigurationChangeTokenSource.cs | 21 +++ .../EgressProviderConfigurationProvider.cs | 32 ++++ .../EgressProviderConfigureNamedOptions.cs | 44 +++++ .../EgressProviderValidateOptions.cs | 44 +++++ .../IEgressPropertiesConfigurationProvider.cs | 19 ++ .../IEgressPropertiesProvider.cs | 17 ++ .../IEgressProviderConfigurationProvider.cs | 39 ++++ .../Egress/ConfiguredEgressProvider.cs | 51 ------ ...amOptions.cs => EgressArtifactSettings.cs} | 18 +- .../dotnet-monitor/Egress/EgressFactory.cs | 45 ----- .../dotnet-monitor/Egress/EgressProvider.cs | 60 +++---- .../Egress/EgressProviderInternal.cs | 86 +++++++++ .../Egress/EgressProviderValidation.cs | 55 ------ .../dotnet-monitor/Egress/EgressService.cs | 138 +++++++++++++-- .../FileSystem/FileSystemEgressProvider.cs | 37 ++-- .../FileSystemEgressProviderOptions.cs | 27 ++- .../FileSystemEgressStreamOptions.cs | 13 -- .../Egress/FileSystemEgressFactory.cs | 86 --------- .../dotnet-monitor/Egress/IEgressProvider.cs | 26 +++ ...ons.cs => IEgressProviderCommonOptions.cs} | 8 +- .../Egress/IEgressProviderInternal.cs | 31 ++++ .../dotnet-monitor}/EgressOptions.cs | 34 ++-- src/Tools/dotnet-monitor/LoggingExtensions.cs | 102 ++--------- .../ServiceCollectionExtensions.cs | 65 ++++++- src/Tools/dotnet-monitor/Strings.Designer.cs | 85 +++------ src/Tools/dotnet-monitor/Strings.resx | 72 +++----- 45 files changed, 1328 insertions(+), 1055 deletions(-) create mode 100644 src/Tools/dotnet-monitor/Egress/AzureBlob/AzureBlobEgressPostConfigureOptions.cs create mode 100644 src/Tools/dotnet-monitor/Egress/AzureBlob/AzureBlobEgressProviderOptions.Validate.cs delete mode 100644 src/Tools/dotnet-monitor/Egress/AzureBlobEgressFactory.cs delete mode 100644 src/Tools/dotnet-monitor/Egress/Configuration/EgressConfigureOptions.cs delete mode 100644 src/Tools/dotnet-monitor/Egress/Configuration/EgressOptions.cs create mode 100644 src/Tools/dotnet-monitor/Egress/Configuration/EgressOptionsCache.cs create mode 100644 src/Tools/dotnet-monitor/Egress/Configuration/EgressPropertiesConfigurationChangeTokenSource.cs create mode 100644 src/Tools/dotnet-monitor/Egress/Configuration/EgressPropertiesConfigurationProvider.cs create mode 100644 src/Tools/dotnet-monitor/Egress/Configuration/EgressPropertiesProvider.cs create mode 100644 src/Tools/dotnet-monitor/Egress/Configuration/EgressProviderConfigurationChangeTokenSource.cs create mode 100644 src/Tools/dotnet-monitor/Egress/Configuration/EgressProviderConfigurationProvider.cs create mode 100644 src/Tools/dotnet-monitor/Egress/Configuration/EgressProviderConfigureNamedOptions.cs create mode 100644 src/Tools/dotnet-monitor/Egress/Configuration/EgressProviderValidateOptions.cs create mode 100644 src/Tools/dotnet-monitor/Egress/Configuration/IEgressPropertiesConfigurationProvider.cs create mode 100644 src/Tools/dotnet-monitor/Egress/Configuration/IEgressPropertiesProvider.cs create mode 100644 src/Tools/dotnet-monitor/Egress/Configuration/IEgressProviderConfigurationProvider.cs delete mode 100644 src/Tools/dotnet-monitor/Egress/ConfiguredEgressProvider.cs rename src/Tools/dotnet-monitor/Egress/{AzureBlob/AzureBlobEgressStreamOptions.cs => EgressArtifactSettings.cs} (58%) delete mode 100644 src/Tools/dotnet-monitor/Egress/EgressFactory.cs create mode 100644 src/Tools/dotnet-monitor/Egress/EgressProviderInternal.cs delete mode 100644 src/Tools/dotnet-monitor/Egress/EgressProviderValidation.cs delete mode 100644 src/Tools/dotnet-monitor/Egress/FileSystem/FileSystemEgressStreamOptions.cs delete mode 100644 src/Tools/dotnet-monitor/Egress/FileSystemEgressFactory.cs create mode 100644 src/Tools/dotnet-monitor/Egress/IEgressProvider.cs rename src/Tools/dotnet-monitor/Egress/{EgressProviderOptions.cs => IEgressProviderCommonOptions.cs} (76%) create mode 100644 src/Tools/dotnet-monitor/Egress/IEgressProviderInternal.cs rename src/{Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Options => Tools/dotnet-monitor}/EgressOptions.cs (50%) diff --git a/documentation/configuration.md b/documentation/configuration.md index 44cb2bb2039..6e829e90d3c 100644 --- a/documentation/configuration.md +++ b/documentation/configuration.md @@ -343,7 +343,6 @@ In addition to enabling custom providers, `dotnet monitor` also allows you to di | Name | Type | Description | |---|---|---| -| type | string | Must be 'azureBlobStorage'.| | accountUri | string | The URI of the Azure blob storage account.| | containerName | string | The name of the container to which the blob will be egressed. If egressing to the root container, use the "$root" sentinel value.| | blobPrefix | string | Optional path prefix for the artifacts to egress.| @@ -358,9 +357,8 @@ In addition to enabling custom providers, `dotnet monitor` also allows you to di ```json { "Egress": { - "Providers": { + "AzureBlobStorage": { "monitorBlob": { - "type": "azureBlobStorage", "accountUri": "https://exampleaccount.blob.core.windows.net", "containerName": "dotnet-monitor", "blobPrefix": "artifacts", @@ -378,7 +376,6 @@ In addition to enabling custom providers, `dotnet monitor` also allows you to di | Name | Type | Description | |---|---|---| -| type | string | Must be 'fileSystem'| | directoryPath | string | The directory path to which the stream data will be egressed.| | intermediateDirectoryPath | string | The directory path to which the stream data will initially be written, if specified; the file will then be moved/renamed to the directory specified in 'directoryPath'.| @@ -387,9 +384,8 @@ In addition to enabling custom providers, `dotnet monitor` also allows you to di ```json { "Egress": { - "Providers": { + "FileSystem": { "monitorFile": { - "type": "fileSystem", "directoryPath": "/artifacts", "intermediateDirectoryPath": "/intermediateArtifacts" } diff --git a/documentation/schema.json b/documentation/schema.json index cbc885b2384..a2990e09fa6 100644 --- a/documentation/schema.json +++ b/documentation/schema.json @@ -168,15 +168,26 @@ "type": "object", "additionalProperties": false, "properties": { - "Providers": { + "AzureBlobStorage": { + "type": [ + "null", + "object" + ], + "description": "Mapping of Azure blob storage egress provider names to their options.", + "default": {}, + "additionalProperties": { + "$ref": "#/definitions/AzureBlobEgressProviderOptions" + } + }, + "FileSystem": { "type": [ "null", "object" ], - "description": "Named providers for egress. The names can be referenced when requesting artifacts, such as dumps or traces.", + "description": "Mapping of file system egress provider names to their options.", "default": {}, "additionalProperties": { - "$ref": "#/definitions/EgressProvider" + "$ref": "#/definitions/FileSystemEgressProviderOptions" } }, "Properties": { @@ -192,21 +203,96 @@ } } }, - "EgressProvider": { + "AzureBlobEgressProviderOptions": { + "type": "object", + "additionalProperties": false, + "required": [ + "AccountUri", + "ContainerName" + ], + "properties": { + "AccountUri": { + "type": "string", + "description": "The URI of the Azure blob storage account.", + "format": "uri", + "minLength": 1 + }, + "AccountKey": { + "type": [ + "null", + "string" + ], + "description": "The account key used to access the Azure blob storage account." + }, + "AccountKeyName": { + "type": [ + "null", + "string" + ], + "description": "The name of the account key used to look up the value from the Egress options Properties map." + }, + "SharedAccessSignature": { + "type": [ + "null", + "string" + ], + "description": "The shared access signature (SAS) used to access the azure blob storage account." + }, + "SharedAccessSignatureName": { + "type": [ + "null", + "string" + ], + "description": "The name of the shared access signature (SAS) used to look up the value from the Egress options Properties map." + }, + "ContainerName": { + "type": "string", + "description": "The name of the container to which the blob will be egressed. If egressing to the root container, use the \"$root\" sentinel value.", + "minLength": 1 + }, + "BlobPrefix": { + "type": [ + "null", + "string" + ], + "description": "The prefix to prepend to the blob name." + }, + "CopyBufferSize": { + "type": [ + "integer", + "null" + ], + "description": "Buffer size used when copying data from an egress callback returning a stream to the egress callback that is provided a stream to which data is written.", + "format": "int32" + } + } + }, + "FileSystemEgressProviderOptions": { "type": "object", - "additionalProperties": { - "type": [ - "null", - "string" - ] - }, + "additionalProperties": false, "required": [ - "type" + "DirectoryPath" ], "properties": { - "type": { + "DirectoryPath": { "type": "string", - "description": "The type of provider. Currently this supports 'fileSystem' and 'azureBlobStorage'." + "description": "The directory path to which the stream data will be egressed.", + "minLength": 1 + }, + "IntermediateDirectoryPath": { + "type": [ + "null", + "string" + ], + "description": "The directory path to which the stream data will initially be written, if specified; the file will then be moved/renamed to the directory specified in DirectoryPath." + }, + "CopyBufferSize": { + "type": [ + "integer", + "null" + ], + "description": "Buffer size used when copying data from an egress callback returning a stream to the egress callback that is provided a stream to which data is written.", + "format": "int32" } } }, diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/OptionsDisplayStrings.Designer.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/OptionsDisplayStrings.Designer.cs index e6ed34c77b4..d6a99d1d3f5 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/OptionsDisplayStrings.Designer.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/OptionsDisplayStrings.Designer.cs @@ -19,7 +19,7 @@ namespace Microsoft.Diagnostics.Monitoring.WebApi { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] public class OptionsDisplayStrings { @@ -78,6 +78,79 @@ public static string DisplayAttributeDescription_ApiAuthenticationOptions_ApiKey } } + /// + /// Looks up a localized string similar to The account key used to access the Azure blob storage account.. + /// + public static string DisplayAttributeDescription_AzureBlobEgressProviderOptions_AccountKey { + get { + return ResourceManager.GetString("DisplayAttributeDescription_AzureBlobEgressProviderOptions_AccountKey", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The name of the account key used to look up the value from the Egress options Properties map.. + /// + public static string DisplayAttributeDescription_AzureBlobEgressProviderOptions_AccountKeyName { + get { + return ResourceManager.GetString("DisplayAttributeDescription_AzureBlobEgressProviderOptions_AccountKeyName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The URI of the Azure blob storage account.. + /// + public static string DisplayAttributeDescription_AzureBlobEgressProviderOptions_AccountUri { + get { + return ResourceManager.GetString("DisplayAttributeDescription_AzureBlobEgressProviderOptions_AccountUri", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The prefix to prepend to the blob name.. + /// + public static string DisplayAttributeDescription_AzureBlobEgressProviderOptions_BlobPrefix { + get { + return ResourceManager.GetString("DisplayAttributeDescription_AzureBlobEgressProviderOptions_BlobPrefix", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The name of the container to which the blob will be egressed. If egressing to the root container, use the "$root" sentinel value.. + /// + public static string DisplayAttributeDescription_AzureBlobEgressProviderOptions_ContainerName { + get { + return ResourceManager.GetString("DisplayAttributeDescription_AzureBlobEgressProviderOptions_ContainerName", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The shared access signature (SAS) used to access the azure blob storage account.. + /// + public static string DisplayAttributeDescription_AzureBlobEgressProviderOptions_SharedAccessSignature { + get { + return ResourceManager.GetString("DisplayAttributeDescription_AzureBlobEgressProviderOptions_SharedAccessSignature", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to The name of the shared access signature (SAS) used to look up the value from the Egress options Properties map.. + /// + public static string DisplayAttributeDescription_AzureBlobEgressProviderOptions_SharedAccessSignatureName { + get { + return ResourceManager.GetString("DisplayAttributeDescription_AzureBlobEgressProviderOptions_SharedAccessSignatureN" + + "ame", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Buffer size used when copying data from an egress callback returning a stream to the egress callback that is provided a stream to which data is written.. + /// + public static string DisplayAttributeDescription_CommonEgressProviderOptions_CopyBufferSize { + get { + return ResourceManager.GetString("DisplayAttributeDescription_CommonEgressProviderOptions_CopyBufferSize", resourceCulture); + } + } + /// /// Looks up a localized string similar to List of allowed CORS origins, separated by semicolons.. /// @@ -114,6 +187,24 @@ public static string DisplayAttributeDescription_DiagnosticPortOptions_MaxConnec } } + /// + /// Looks up a localized string similar to Mapping of Azure blob storage egress provider names to their options.. + /// + public static string DisplayAttributeDescription_EgressOptions_AzureBlobStorage { + get { + return ResourceManager.GetString("DisplayAttributeDescription_EgressOptions_AzureBlobStorage", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Mapping of file system egress provider names to their options.. + /// + public static string DisplayAttributeDescription_EgressOptions_FileSystem { + get { + return ResourceManager.GetString("DisplayAttributeDescription_EgressOptions_FileSystem", resourceCulture); + } + } + /// /// Looks up a localized string similar to Additional properties, such as secrets, that can be referenced by the provider definitions.. /// @@ -124,20 +215,21 @@ public static string DisplayAttributeDescription_EgressOptions_Properties { } /// - /// Looks up a localized string similar to Named providers for egress. The names can be referenced when requesting artifacts, such as dumps or traces.. + /// Looks up a localized string similar to The directory path to which the stream data will be egressed.. /// - public static string DisplayAttributeDescription_EgressOptions_Providers { + public static string DisplayAttributeDescription_FileSystemEgressProviderOptions_DirectoryPath { get { - return ResourceManager.GetString("DisplayAttributeDescription_EgressOptions_Providers", resourceCulture); + return ResourceManager.GetString("DisplayAttributeDescription_FileSystemEgressProviderOptions_DirectoryPath", resourceCulture); } } /// - /// Looks up a localized string similar to The type of provider. Currently this supports 'fileSystem' and 'azureBlobStorage'.. + /// Looks up a localized string similar to The directory path to which the stream data will initially be written, if specified; the file will then be moved/renamed to the directory specified in DirectoryPath.. /// - public static string DisplayAttributeDescription_EgressProvider_EgressType { + public static string DisplayAttributeDescription_FileSystemEgressProviderOptions_IntermediateDirectoryPath { get { - return ResourceManager.GetString("DisplayAttributeDescription_EgressProvider_EgressType", resourceCulture); + return ResourceManager.GetString("DisplayAttributeDescription_FileSystemEgressProviderOptions_IntermediateDirectory" + + "Path", resourceCulture); } } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/OptionsDisplayStrings.resx b/src/Microsoft.Diagnostics.Monitoring.WebApi/OptionsDisplayStrings.resx index 7d8fbd34c8a..aa836e9700a 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/OptionsDisplayStrings.resx +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/OptionsDisplayStrings.resx @@ -125,6 +125,38 @@ Hash algorithm used to compute ApiKeyHash, typically 'SHA256'. 'SHA1' and 'MD5' are not allowed. The description provided for the ApiKeyHashType parameter on ApiAuthenticationOptions. + + The account key used to access the Azure blob storage account. + The description provided for the AccountKey parameter on AzureBlobEgressProviderOptions. + + + The name of the account key used to look up the value from the Egress options Properties map. + The description provided for the AccountKeyName parameter on AzureBlobEgressProviderOptions. + + + The URI of the Azure blob storage account. + The description provided for the AccountUri parameter on AzureBlobEgressProviderOptions. + + + The prefix to prepend to the blob name. + The description provided for the BlobPrefix parameter on AzureBlobEgressProviderOptions. + + + The name of the container to which the blob will be egressed. If egressing to the root container, use the "$root" sentinel value. + The description provided for the ContainerName parameter on AzureBlobEgressProviderOptions. + + + The shared access signature (SAS) used to access the azure blob storage account. + The description provided for the SharedAccessSignature parameter on AzureBlobEgressProviderOptions. + + + The name of the shared access signature (SAS) used to look up the value from the Egress options Properties map. + The description provided for the SharedAccessSignatureName parameter on AzureBlobEgressProviderOptions. + + + Buffer size used when copying data from an egress callback returning a stream to the egress callback that is provided a stream to which data is written. + The description provided for the CopyBufferSize parameter on all egress provider options. + List of allowed CORS origins, separated by semicolons. The description provided for the AllowedOrigins parameter on CorsConfiguration. @@ -141,17 +173,25 @@ In 'Listen' mode, the maximum amount of connections to accept. The description provided for the MaxConnections parameter on DiagnosticPortOptions. + + Mapping of Azure blob storage egress provider names to their options. + The description provided for the AzureBlobStorage parameter on EgressOptions. + + + Mapping of file system egress provider names to their options. + The description provided for the FileSystem parameter on EgressOptions. + Additional properties, such as secrets, that can be referenced by the provider definitions. The description provided for the Properties parameter on EgressOptions. - - Named providers for egress. The names can be referenced when requesting artifacts, such as dumps or traces. - The description provided for the Providers parameter on EgressOptions. + + The directory path to which the stream data will be egressed. + The description provided for the DirectoryPath parameter on FileSystemEgressProviderOptions. - - The type of provider. Currently this supports 'fileSystem' and 'azureBlobStorage'. - The description provided for the EgressType parameter on EgressProvider. + + The directory path to which the stream data will initially be written, if specified; the file will then be moved/renamed to the directory specified in DirectoryPath. + The description provided for the IntermediateDirectoryPath parameter on FileSystemEgressProviderOptions. Name of custom metrics counters. diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.ConfigurationSchema/SchemaGenerator.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.ConfigurationSchema/SchemaGenerator.cs index cbd199e81f0..44a988a1af3 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.ConfigurationSchema/SchemaGenerator.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.ConfigurationSchema/SchemaGenerator.cs @@ -19,13 +19,9 @@ public string GenerateSchema() //Allow other properties in the schema. schema.AdditionalPropertiesSchema = JsonSchema.CreateAnySchema(); - //HACK Even though Properties is defined as JsonDataExtension, it still emits a property - //called 'Properties' into the schema, instead of just specifying additionalProperties. - //There is likely a more elegant way to fix this. - schema.Definitions[nameof(EgressProvider)].Properties.Remove(nameof(EgressProvider.Properties)); - //TODO Figure out a better way to add object defaults - schema.Definitions[nameof(EgressOptions)].Properties[nameof(EgressOptions.Providers)].Default = JsonSchema.CreateAnySchema(); + schema.Definitions[nameof(EgressOptions)].Properties[nameof(EgressOptions.AzureBlobStorage)].Default = JsonSchema.CreateAnySchema(); + schema.Definitions[nameof(EgressOptions)].Properties[nameof(EgressOptions.FileSystem)].Default = JsonSchema.CreateAnySchema(); schema.Definitions[nameof(EgressOptions)].Properties[nameof(EgressOptions.Properties)].Default = JsonSchema.CreateAnySchema(); //Make the default for each property and empty object. diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj index 4c549cb6a52..78e5ae123a5 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj @@ -22,6 +22,10 @@ + + + + diff --git a/src/Tools/dotnet-monitor/ConfigurationJsonWriter.cs b/src/Tools/dotnet-monitor/ConfigurationJsonWriter.cs index d59d211e456..7c2eb8485a0 100644 --- a/src/Tools/dotnet-monitor/ConfigurationJsonWriter.cs +++ b/src/Tools/dotnet-monitor/ConfigurationJsonWriter.cs @@ -3,18 +3,14 @@ // See the LICENSE file in the project root for more information. using Microsoft.AspNetCore.Hosting; -using Microsoft.Diagnostics.Tools.Monitor.Egress; -using Microsoft.Diagnostics.Tools.Monitor.Egress.AzureStorage; -using Microsoft.Diagnostics.Tools.Monitor.Egress.Configuration; +using Microsoft.Diagnostics.Tools.Monitor.Egress.AzureBlob; using Microsoft.Diagnostics.Tools.Monitor.Egress.FileSystem; using Microsoft.Extensions.Configuration; using System; using System.Collections.Generic; using System.IO; using System.Linq; -using System.Text; using System.Text.Json; -using System.Threading.Tasks; namespace Microsoft.Diagnostics.Tools.Monitor { @@ -90,74 +86,73 @@ public void Write(IConfiguration configuration, bool full) if (egress != null) { _writer.WriteStartObject(); - //Redact all the properties since they could include secrets such as storage keys - ProcessChildSection(egress, nameof(EgressOptions.Properties), includeChildSections: true, redact: true); - WriteProviders(egress); + ProcessEgressSection(egress); _writer.WriteEndObject(); } } _writer.WriteEndObject(); } - private void WriteProviders(IConfiguration egress) + private void ProcessEgressSection(IConfiguration egress) { - IConfigurationSection providers = ProcessChildSection(egress, nameof(EgressOptions.Providers), includeChildSections: false); - if (providers != null) + IList processedSectionPaths = new List(); + + // Redact all the properties since they could include secrets such as storage keys + IConfigurationSection propertiesSection = ProcessChildSection(egress, nameof(EgressOptions.Properties), includeChildSections: true, redact: true); + if (null != propertiesSection) + { + processedSectionPaths.Add(propertiesSection.Path); + } + + IConfigurationSection azureBlobProviderSection = ProcessChildSection(egress, nameof(EgressOptions.AzureBlobStorage), includeChildSections: false); + if (azureBlobProviderSection != null) { - Func matchesProvider = (configSection, providerName) => - configSection.Exists() && - string.Equals(configSection.Key, nameof(EgressConfigureOptions.CommonEgressProviderOptions.Type), StringComparison.OrdinalIgnoreCase) && - string.Equals(configSection.Value, providerName, StringComparison.OrdinalIgnoreCase); + processedSectionPaths.Add(azureBlobProviderSection.Path); _writer.WriteStartObject(); - foreach (IConfigurationSection provider in providers.GetChildren()) + foreach (IConfigurationSection optionsSection in azureBlobProviderSection.GetChildren()) { - string egressName = provider.Key; - IEnumerable egressProperties = provider.GetChildren(); + _writer.WritePropertyName(optionsSection.Key); + _writer.WriteStartObject(); + ProcessChildSection(optionsSection, nameof(AzureBlobEgressProviderOptions.AccountUri), includeChildSections: false); + ProcessChildSection(optionsSection, nameof(AzureBlobEgressProviderOptions.BlobPrefix), includeChildSections: false); + ProcessChildSection(optionsSection, nameof(AzureBlobEgressProviderOptions.ContainerName), includeChildSections: false); + ProcessChildSection(optionsSection, nameof(AzureBlobEgressProviderOptions.CopyBufferSize), includeChildSections: false); + ProcessChildSection(optionsSection, nameof(AzureBlobEgressProviderOptions.SharedAccessSignature), includeChildSections: false, redact: true); + ProcessChildSection(optionsSection, nameof(AzureBlobEgressProviderOptions.AccountKey), includeChildSections: false, redact: true); + ProcessChildSection(optionsSection, nameof(AzureBlobEgressProviderOptions.SharedAccessSignatureName), includeChildSections: false, redact: false); + ProcessChildSection(optionsSection, nameof(AzureBlobEgressProviderOptions.AccountKeyName), includeChildSections: false, redact: false); + _writer.WriteEndObject(); + } + _writer.WriteEndObject(); + } + + IConfigurationSection fileSystemProviderSection = ProcessChildSection(egress, nameof(EgressOptions.FileSystem), includeChildSections: false); + if (fileSystemProviderSection != null) + { + processedSectionPaths.Add(fileSystemProviderSection.Path); - _writer.WritePropertyName(egressName); + _writer.WriteStartObject(); + foreach (IConfigurationSection optionsSection in fileSystemProviderSection.GetChildren()) + { + _writer.WritePropertyName(optionsSection.Key); _writer.WriteStartObject(); - //matches azure blob storage provider type. - //Emit well known properties. - if (egressProperties.Any(child => matchesProvider(child, EgressProviderTypes.AzureBlobStorage))) - { - ProcessChildSection(provider, nameof(EgressConfigureOptions.CommonEgressProviderOptions.Type), includeChildSections: false); - ProcessChildSection(provider, nameof(AzureBlobEgressProviderOptions.AccountUri), includeChildSections: false); - ProcessChildSection(provider, nameof(AzureBlobEgressProviderOptions.BlobPrefix), includeChildSections: false); - ProcessChildSection(provider, nameof(AzureBlobEgressProviderOptions.ContainerName), includeChildSections: false); - ProcessChildSection(provider, nameof(AzureBlobEgressProviderOptions.CopyBufferSize), includeChildSections: false); - ProcessChildSection(provider, nameof(AzureBlobEgressProviderOptions.SharedAccessSignature), includeChildSections: false, redact: true); - ProcessChildSection(provider, nameof(AzureBlobEgressProviderOptions.AccountKey), includeChildSections: false, redact: true); - ProcessChildSection(provider, nameof(AzureBlobEgressFactory.ConfigurationOptions.SharedAccessSignatureName), includeChildSections: false, redact: false); - ProcessChildSection(provider, nameof(AzureBlobEgressFactory.ConfigurationOptions.AccountKeyName), includeChildSections: false, redact: false); - } - //Matches filesystem provider type. - else if (egressProperties.Any(child => matchesProvider(child, EgressProviderTypes.FileSystem))) - { - ProcessChildSection(provider, nameof(EgressConfigureOptions.CommonEgressProviderOptions.Type), includeChildSections: false); - ProcessChildSection(provider, nameof(FileSystemEgressProviderOptions.DirectoryPath), includeChildSections: false); - ProcessChildSection(provider, nameof(FileSystemEgressProviderOptions.IntermediateDirectoryPath), includeChildSections: false); - ProcessChildSection(provider, nameof(FileSystemEgressProviderOptions.CopyBufferSize), includeChildSections: false); - } - else - { - //Emit other egress entries, with redaction - foreach (IConfigurationSection providerProperty in egressProperties) - { - if (string.Equals(providerProperty.Key, nameof(EgressConfigureOptions.CommonEgressProviderOptions.Type), StringComparison.OrdinalIgnoreCase)) - { - ProcessSection(providerProperty, includeChildSections: false, redact: false); - } - else - { - ProcessSection(providerProperty, includeChildSections: true, redact: true); - } - } - } + ProcessChildSection(optionsSection, nameof(FileSystemEgressProviderOptions.DirectoryPath), includeChildSections: false); + ProcessChildSection(optionsSection, nameof(FileSystemEgressProviderOptions.IntermediateDirectoryPath), includeChildSections: false); + ProcessChildSection(optionsSection, nameof(FileSystemEgressProviderOptions.CopyBufferSize), includeChildSections: false); _writer.WriteEndObject(); } _writer.WriteEndObject(); } + + //Emit other egress entries, with redaction + foreach (IConfigurationSection childSection in egress.GetChildren()) + { + if (!processedSectionPaths.Contains(childSection.Path)) + { + ProcessChildSection(egress, childSection.Key, includeChildSections: true, redact: true); + } + } } private IConfigurationSection ProcessChildSection(IConfiguration parentSection, string key, bool includeChildSections = true, bool redact = false) diff --git a/src/Tools/dotnet-monitor/Egress/AzureBlob/AzureBlobEgressPostConfigureOptions.cs b/src/Tools/dotnet-monitor/Egress/AzureBlob/AzureBlobEgressPostConfigureOptions.cs new file mode 100644 index 00000000000..2badf323861 --- /dev/null +++ b/src/Tools/dotnet-monitor/Egress/AzureBlob/AzureBlobEgressPostConfigureOptions.cs @@ -0,0 +1,61 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Diagnostics.Tools.Monitor.Egress.Configuration; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; + +namespace Microsoft.Diagnostics.Tools.Monitor.Egress.AzureBlob +{ + /// + /// Fills AccountKey and SharedAccessSignature from Egress:Properties if they do not have values. + /// + internal sealed class AzureBlobEgressPostConfigureOptions : + IPostConfigureOptions + { + private readonly ILogger _logger; + private readonly IEgressPropertiesProvider _provider; + + public AzureBlobEgressPostConfigureOptions( + ILogger logger, + IEgressPropertiesProvider provider) + { + _logger = logger; + _provider = provider; + } + + public void PostConfigure(string name, AzureBlobEgressProviderOptions options) + { + // If account key was not provided but the name was provided, + // lookup the account key property value from EgressOptions.Properties + if (string.IsNullOrEmpty(options.AccountKey) && + !string.IsNullOrEmpty(options.AccountKeyName)) + { + if (_provider.TryGetPropertyValue(options.AccountKeyName, out string key)) + { + options.AccountKey = key; + } + else + { + _logger.EgressProviderUnableToFindPropertyKey(name, options.AccountKeyName); + } + } + + // If shared access signature (SAS) was not provided but the name was provided, + // lookup the SAS property value from EgressOptions.Properties + if (string.IsNullOrEmpty(options.SharedAccessSignature) && + !string.IsNullOrEmpty(options.SharedAccessSignatureName)) + { + if (_provider.TryGetPropertyValue(options.SharedAccessSignatureName, out string signature)) + { + options.SharedAccessSignature = signature; + } + else + { + _logger.EgressProviderUnableToFindPropertyKey(name, options.SharedAccessSignatureName); + } + } + } + } +} diff --git a/src/Tools/dotnet-monitor/Egress/AzureBlob/AzureBlobEgressProvider.cs b/src/Tools/dotnet-monitor/Egress/AzureBlob/AzureBlobEgressProvider.cs index ff1087bf48d..19df1b403ae 100644 --- a/src/Tools/dotnet-monitor/Egress/AzureBlob/AzureBlobEgressProvider.cs +++ b/src/Tools/dotnet-monitor/Egress/AzureBlob/AzureBlobEgressProvider.cs @@ -14,7 +14,7 @@ using System.Threading; using System.Threading.Tasks; -namespace Microsoft.Diagnostics.Tools.Monitor.Egress.AzureStorage +namespace Microsoft.Diagnostics.Tools.Monitor.Egress.AzureBlob { /// /// Egress provider for egressing stream data to an Azure blob storage account. @@ -23,32 +23,30 @@ namespace Microsoft.Diagnostics.Tools.Monitor.Egress.AzureStorage /// Blobs created through this provider will overwrite existing blobs if they have the same blob name. /// internal class AzureBlobEgressProvider : - EgressProvider + EgressProvider { - public AzureBlobEgressProvider(AzureBlobEgressProviderOptions options, ILogger logger = null) - : base(options, logger) + public AzureBlobEgressProvider(ILogger logger) + : base(logger) { } public override async Task EgressAsync( + AzureBlobEgressProviderOptions options, Func> action, - string name, - AzureBlobEgressStreamOptions streamOptions, + EgressArtifactSettings artifactSettings, CancellationToken token) { - LogAndValidateOptions(streamOptions, name); - try { - var containerClient = await GetBlobContainerClientAsync(token); + var containerClient = await GetBlobContainerClientAsync(options, token); - BlobClient blobClient = containerClient.GetBlobClient(GetBlobName(name)); + BlobClient blobClient = containerClient.GetBlobClient(GetBlobName(options, artifactSettings)); Logger?.EgressProviderInvokeStreamAction(EgressProviderTypes.AzureBlobStorage); using var stream = await action(token); // Write blob content, headers, and metadata - await blobClient.UploadAsync(stream, CreateHttpHeaders(streamOptions), streamOptions.Metadata, cancellationToken: token); + await blobClient.UploadAsync(stream, CreateHttpHeaders(artifactSettings), artifactSettings.Metadata, cancellationToken: token); string blobUriString = GetBlobUri(blobClient); Logger?.EgressProviderSavedStream(EgressProviderTypes.AzureBlobStorage, blobUriString); @@ -65,18 +63,16 @@ public override async Task EgressAsync( } public override async Task EgressAsync( + AzureBlobEgressProviderOptions options, Func action, - string name, - AzureBlobEgressStreamOptions streamOptions, + EgressArtifactSettings artifactSettings, CancellationToken token) { - LogAndValidateOptions(streamOptions, name); - try { - var containerClient = await GetBlobContainerClientAsync(token); + var containerClient = await GetBlobContainerClientAsync(options, token); - BlockBlobClient blobClient = containerClient.GetBlockBlobClient(GetBlobName(name)); + BlockBlobClient blobClient = containerClient.GetBlockBlobClient(GetBlobName(options, artifactSettings)); // Write blob content using (Stream blobStream = await blobClient.OpenWriteAsync(overwrite: true, cancellationToken: token)) @@ -88,10 +84,10 @@ public override async Task EgressAsync( } // Write blob headers - await blobClient.SetHttpHeadersAsync(CreateHttpHeaders(streamOptions), cancellationToken: token); + await blobClient.SetHttpHeadersAsync(CreateHttpHeaders(artifactSettings), cancellationToken: token); // Write blob metadata - await blobClient.SetMetadataAsync(streamOptions.Metadata, cancellationToken: token); + await blobClient.SetMetadataAsync(artifactSettings.Metadata, cancellationToken: token); string blobUriString = GetBlobUri(blobClient); Logger?.EgressProviderSavedStream(EgressProviderTypes.AzureBlobStorage, blobUriString); @@ -107,24 +103,9 @@ public override async Task EgressAsync( } } - private void LogAndValidateOptions(AzureBlobEgressStreamOptions streamOptions, string fileName) - { - Logger?.EgressProviderOptionValue(EgressProviderTypes.AzureBlobStorage, nameof(Options.AccountKey), Options.AccountKey, redact: true); - Logger?.EgressProviderOptionValue(EgressProviderTypes.AzureBlobStorage, nameof(Options.AccountUri), GetAccountUri(out _)); - Logger?.EgressProviderOptionValue(EgressProviderTypes.AzureBlobStorage, nameof(Options.BlobPrefix), Options.BlobPrefix); - Logger?.EgressProviderOptionValue(EgressProviderTypes.AzureBlobStorage, nameof(Options.ContainerName), Options.ContainerName); - Logger?.EgressProviderOptionValue(EgressProviderTypes.AzureBlobStorage, nameof(Options.SharedAccessSignature), Options.SharedAccessSignature, redact: true); - Logger?.EgressStreamOptionValue(EgressProviderTypes.AzureBlobStorage, nameof(streamOptions.ContentEncoding), streamOptions.ContentEncoding); - Logger?.EgressStreamOptionValue(EgressProviderTypes.AzureBlobStorage, nameof(streamOptions.ContentType), streamOptions.ContentType); - Logger?.EgressStreamOptionValue(EgressProviderTypes.AzureBlobStorage, nameof(streamOptions.Metadata), "[" + string.Join(", ", streamOptions.Metadata.Keys) + "]"); - Logger?.EgressProviderFileName(EgressProviderTypes.AzureBlobStorage, fileName); - - ValidateOptions(); - } - - private Uri GetAccountUri(out string accountName) + private Uri GetAccountUri(AzureBlobEgressProviderOptions options, out string accountName) { - var blobUriBuilder = new BlobUriBuilder(Options.AccountUri); + var blobUriBuilder = new BlobUriBuilder(options.AccountUri); blobUriBuilder.Query = null; blobUriBuilder.BlobName = null; blobUriBuilder.BlobContainerName = null; @@ -134,26 +115,26 @@ private Uri GetAccountUri(out string accountName) return blobUriBuilder.ToUri(); } - private async Task GetBlobContainerClientAsync(CancellationToken token) + private async Task GetBlobContainerClientAsync(AzureBlobEgressProviderOptions options, CancellationToken token) { BlobServiceClient serviceClient; - if (!string.IsNullOrWhiteSpace(Options.SharedAccessSignature)) + if (!string.IsNullOrWhiteSpace(options.SharedAccessSignature)) { - var serviceUriBuilder = new UriBuilder(Options.AccountUri) + var serviceUriBuilder = new UriBuilder(options.AccountUri) { - Query = Options.SharedAccessSignature + Query = options.SharedAccessSignature }; serviceClient = new BlobServiceClient(serviceUriBuilder.Uri); } - else if (!string.IsNullOrEmpty(Options.AccountKey)) + else if (!string.IsNullOrEmpty(options.AccountKey)) { // Remove Query in case SAS token was specified - Uri accountUri = GetAccountUri(out string accountName); + Uri accountUri = GetAccountUri(options, out string accountName); StorageSharedKeyCredential credential = new StorageSharedKeyCredential( accountName, - Options.AccountKey); + options.AccountKey); serviceClient = new BlobServiceClient(accountUri, credential); } @@ -162,29 +143,29 @@ private async Task GetBlobContainerClientAsync(Cancellation throw CreateException(Strings.ErrorMessage_EgressMissingSasOrKey); } - BlobContainerClient containerClient = serviceClient.GetBlobContainerClient(Options.ContainerName); + BlobContainerClient containerClient = serviceClient.GetBlobContainerClient(options.ContainerName); await containerClient.CreateIfNotExistsAsync(cancellationToken: token); return containerClient; } - private string GetBlobName(string fileName) + private string GetBlobName(AzureBlobEgressProviderOptions options, EgressArtifactSettings artifactSettings) { - if (string.IsNullOrEmpty(Options.BlobPrefix)) + if (string.IsNullOrEmpty(options.BlobPrefix)) { - return fileName; + return artifactSettings.Name; } else { - return string.Concat(Options.BlobPrefix, "/", fileName); + return string.Concat(options.BlobPrefix, "/", artifactSettings.Name); } } - private BlobHttpHeaders CreateHttpHeaders(AzureBlobEgressStreamOptions streamOptions) + private BlobHttpHeaders CreateHttpHeaders(EgressArtifactSettings artifactSettings) { BlobHttpHeaders headers = new BlobHttpHeaders(); - headers.ContentEncoding = streamOptions.ContentEncoding; - headers.ContentType = streamOptions.ContentType; + headers.ContentEncoding = artifactSettings.ContentEncoding; + headers.ContentType = artifactSettings.ContentType; return headers; } diff --git a/src/Tools/dotnet-monitor/Egress/AzureBlob/AzureBlobEgressProviderOptions.Validate.cs b/src/Tools/dotnet-monitor/Egress/AzureBlob/AzureBlobEgressProviderOptions.Validate.cs new file mode 100644 index 00000000000..5217effeab3 --- /dev/null +++ b/src/Tools/dotnet-monitor/Egress/AzureBlob/AzureBlobEgressProviderOptions.Validate.cs @@ -0,0 +1,35 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace Microsoft.Diagnostics.Tools.Monitor.Egress.AzureBlob +{ + internal sealed partial class AzureBlobEgressProviderOptions : + IValidatableObject + { + /// + /// Provides extra validation to ensure that either the + /// or the have been set. + /// + IEnumerable IValidatableObject.Validate(ValidationContext validationContext) + { + IList results = new List(); + + // One of the authentication keys/tokens is required + if (string.IsNullOrEmpty(AccountKey) && string.IsNullOrEmpty(SharedAccessSignature)) + { + results.Add( + new ValidationResult( + string.Format( + Strings.ErrorMessage_TwoFieldsMissing, + nameof(AccountKey), + nameof(SharedAccessSignature)))); + } + + return results; + } + } +} diff --git a/src/Tools/dotnet-monitor/Egress/AzureBlob/AzureBlobEgressProviderOptions.cs b/src/Tools/dotnet-monitor/Egress/AzureBlob/AzureBlobEgressProviderOptions.cs index f99c19b3da2..755c8e063ed 100644 --- a/src/Tools/dotnet-monitor/Egress/AzureBlob/AzureBlobEgressProviderOptions.cs +++ b/src/Tools/dotnet-monitor/Egress/AzureBlob/AzureBlobEgressProviderOptions.cs @@ -2,69 +2,62 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using Microsoft.Diagnostics.Monitoring.WebApi; using System; -using System.Collections.Generic; using System.ComponentModel.DataAnnotations; -namespace Microsoft.Diagnostics.Tools.Monitor.Egress.AzureStorage +#if UNITTEST +namespace Microsoft.Diagnostics.Monitoring.UnitTests.Options +#else +namespace Microsoft.Diagnostics.Tools.Monitor.Egress.AzureBlob +#endif { /// /// Egress provider options for Azure blob storage. /// - internal class AzureBlobEgressProviderOptions : - EgressProviderOptions, - IValidatableObject + internal sealed partial class AzureBlobEgressProviderOptions : + IEgressProviderCommonOptions { - /// - /// The URI of the Azure blob storage account. - /// + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_AzureBlobEgressProviderOptions_AccountUri))] [Required] public Uri AccountUri { get; set; } - /// - /// The account key used to access the Azure blob storage account. - /// - /// - /// If not provided, must be specified. - /// + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_AzureBlobEgressProviderOptions_AccountKey))] public string AccountKey { get; set; } - /// - /// The shared access signature (SAS) used to access the azure blob storage account. - /// - /// - /// If not provided, must be specified. - /// + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_AzureBlobEgressProviderOptions_AccountKeyName))] + public string AccountKeyName { get; set; } + + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_AzureBlobEgressProviderOptions_SharedAccessSignature))] public string SharedAccessSignature { get; set; } - /// - /// The name of the container to which the blob will be egressed. If egressing to the root container, - /// use the "$root" sentinel value. - /// + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_AzureBlobEgressProviderOptions_SharedAccessSignatureName))] + public string SharedAccessSignatureName { get; set; } + + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_AzureBlobEgressProviderOptions_ContainerName))] [Required] public string ContainerName { get; set; } - /// - /// The prefix to prepend to the blob name. - /// + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_AzureBlobEgressProviderOptions_BlobPrefix))] public string BlobPrefix { get; set; } - IEnumerable IValidatableObject.Validate(ValidationContext validationContext) - { - IList results = new List(); - - // One of the authentication keys/tokens is required - if (string.IsNullOrEmpty(AccountKey) && string.IsNullOrEmpty(SharedAccessSignature)) - { - results.Add( - new ValidationResult( - string.Format( - Strings.ErrorMessage_TwoFieldsMissing, - nameof(AccountKey), - nameof(SharedAccessSignature)))); - } - - return results; - } + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_CommonEgressProviderOptions_CopyBufferSize))] + public int? CopyBufferSize { get; set; } } } diff --git a/src/Tools/dotnet-monitor/Egress/AzureBlobEgressFactory.cs b/src/Tools/dotnet-monitor/Egress/AzureBlobEgressFactory.cs deleted file mode 100644 index c5a4d45bece..00000000000 --- a/src/Tools/dotnet-monitor/Egress/AzureBlobEgressFactory.cs +++ /dev/null @@ -1,166 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.Diagnostics.Monitoring.WebApi; -using Microsoft.Diagnostics.Tools.Monitor.Egress.AzureStorage; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging; -using System; -using System.Collections.Generic; -using System.Diagnostics; -using System.Globalization; -using System.IO; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.Diagnostics.Tools.Monitor.Egress -{ - /// - /// Creates for Azure blob storage egress. - /// - internal class AzureBlobEgressFactory : EgressFactory - { - private readonly ILoggerFactory _loggerFactory; - - public AzureBlobEgressFactory(ILoggerFactory loggerFactory) - : base(loggerFactory.CreateLogger()) - { - _loggerFactory = loggerFactory; - } - - public override bool TryCreate( - string providerName, - IConfigurationSection providerSection, - Dictionary egressProperties, - out ConfiguredEgressProvider provider) - { - var options = providerSection.Get(); - - // If account key was not provided but the name was provided, - // lookup the account key property value from EgressOptions.Properties - if (string.IsNullOrEmpty(options.AccountKey) && - !string.IsNullOrEmpty(options.AccountKeyName)) - { - if (TryGetPropertyValue(providerName, egressProperties, options.AccountKeyName, out string key)) - { - options.AccountKey = key; - } - } - - // If shared access signature (SAS) was not provided but the name was provided, - // lookup the SAS property value from EgressOptions.Properties - if (string.IsNullOrEmpty(options.SharedAccessSignature) && - !string.IsNullOrEmpty(options.SharedAccessSignatureName)) - { - if (TryGetPropertyValue(providerName, egressProperties, options.SharedAccessSignatureName, out string signature)) - { - options.SharedAccessSignature = signature; - } - } - - if (!TryValidateOptions(options, providerName)) - { - provider = null; - return false; - } - - provider = new Provider(options, _loggerFactory); - return true; - } - - private bool TryGetPropertyValue(string providerName, IDictionary egressProperties, string propertyName, out string value) - { - if (!egressProperties.TryGetValue(propertyName, out value)) - { - Logger.EgressProviderUnableToFindPropertyKey(providerName, propertyName); - return false; - } - return true; - } - - private class Provider : ConfiguredEgressProvider - { - private readonly AzureBlobEgressProvider _provider; - - public Provider(AzureBlobEgressProviderOptions options, ILoggerFactory loggerFactory) - { - _provider = new AzureBlobEgressProvider(options, loggerFactory.CreateLogger()); - } - - public override async Task EgressAsync( - Func> action, - string fileName, - string contentType, - IEndpointInfo source, - CancellationToken token) - { - var streamOptions = new AzureBlobEgressStreamOptions(); - streamOptions.ContentType = contentType; - FillBlobMetadata(streamOptions.Metadata, source); - - string blobUri = await _provider.EgressAsync(action, fileName, streamOptions, token); - - return new EgressResult("uri", blobUri); - } - - public override async Task EgressAsync( - Func action, - string fileName, - string contentType, - IEndpointInfo source, - CancellationToken token) - { - var streamOptions = new AzureBlobEgressStreamOptions(); - streamOptions.ContentType = contentType; - FillBlobMetadata(streamOptions.Metadata, source); - - string blobUri = await _provider.EgressAsync(action, fileName, streamOptions, token); - - return new EgressResult("uri", blobUri); - } - - private static void FillBlobMetadata(IDictionary metadata, IEndpointInfo source) - { - // Activity metadata - Activity activity = Activity.Current; - if (null != activity) - { - metadata.Add( - ActivityMetadataNames.ParentId, - activity.GetParentId()); - metadata.Add( - ActivityMetadataNames.SpanId, - activity.GetSpanId()); - metadata.Add( - ActivityMetadataNames.TraceId, - activity.GetTraceId()); - } - - // Artifact metadata - metadata.Add( - ArtifactMetadataNames.ArtifactSource.ProcessId, - source.ProcessId.ToString(CultureInfo.InvariantCulture)); - metadata.Add( - ArtifactMetadataNames.ArtifactSource.RuntimeInstanceCookie, - source.RuntimeInstanceCookie.ToString("N")); - } - } - - /// - /// Egress provider options for Azure blob storage with additional options. - /// - internal class ConfigurationOptions : AzureBlobEgressProviderOptions - { - /// - /// The name of the account key used to look up the value from the map. - /// - public string AccountKeyName { get; set; } - - /// - /// The name of the shared access signature (SAS) used to look up the value from the map. - /// - public string SharedAccessSignatureName { get; set; } - } - } -} diff --git a/src/Tools/dotnet-monitor/Egress/Configuration/EgressConfigurationExtensions.cs b/src/Tools/dotnet-monitor/Egress/Configuration/EgressConfigurationExtensions.cs index c05c31b2cc8..627713bb276 100644 --- a/src/Tools/dotnet-monitor/Egress/Configuration/EgressConfigurationExtensions.cs +++ b/src/Tools/dotnet-monitor/Egress/Configuration/EgressConfigurationExtensions.cs @@ -15,5 +15,13 @@ public static IConfigurationSection GetEgressSection(this IConfiguration configu { return configuration.GetSection(ConfigurationKeys.Egress); } + + /// + /// Get the Egress:Properties configuration section from the specified configuration. + /// + public static IConfigurationSection GetEgressPropertiesSection(this IConfiguration configuration) + { + return configuration.GetEgressSection().GetSection(nameof(EgressOptions.Properties)); + } } } diff --git a/src/Tools/dotnet-monitor/Egress/Configuration/EgressConfigureOptions.cs b/src/Tools/dotnet-monitor/Egress/Configuration/EgressConfigureOptions.cs deleted file mode 100644 index 44e2ab7e9f6..00000000000 --- a/src/Tools/dotnet-monitor/Egress/Configuration/EgressConfigureOptions.cs +++ /dev/null @@ -1,115 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.Diagnostics.Monitoring.WebApi; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging; -using Microsoft.Extensions.Options; -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; - -namespace Microsoft.Diagnostics.Tools.Monitor.Egress.Configuration -{ - /* - * == Egress Configuration Design == - * - Each type of egress is called an egress type. The following are the defined egress types: - * - AzureBlobStorage: Allows egressing stream data to a blob in Azure blob storage. - * - FileSystem: Allows egressing stream data to the file system. - * - An egress type in combination with its well defined set of options is called a egress provider. - * Each egress provider is named in the egress configuration in order to identify individual providers. - * - All egress configuration information is found in the root Egress configuration section. This section - * has two immediate subsections: - * - Providers: a mapping of egress provider names to egress provider options + the egress type. - * - Each provider must have a 'type' field, which must have a value that is one of the egress types. - * This field informs the egress configuration the type of egress provider that should be constructed - * with the remaining options. - * - If a provider's options fail validation, the failure is reported and the provider will not be - * available to be used as a means of egress. - * - Properties: a mapping of named values, typically for storing secrets (account keys, SAS, etc) by name. - */ - - /// - /// Binds egress configuration information to an instance. - /// - internal class EgressConfigureOptions : IConfigureOptions - { - private readonly IConfiguration _configuration; - private readonly ILogger _logger; - private readonly IDictionary _factories - = new Dictionary(StringComparer.OrdinalIgnoreCase); - - public EgressConfigureOptions( - ILoggerFactory loggerFactory, - IConfiguration configuration) - { - _configuration = configuration; - _logger = loggerFactory.CreateLogger(); - - // Register egress providers - _factories.Add(EgressProviderTypes.AzureBlobStorage, new AzureBlobEgressFactory(loggerFactory)); - _factories.Add(EgressProviderTypes.FileSystem, new FileSystemEgressFactory(loggerFactory)); - } - - public void Configure(EgressOptions options) - { - IConfigurationSection egressSection = _configuration.GetEgressSection(); - - IConfigurationSection propertiesSection = egressSection.GetSection(nameof(EgressOptions.Properties)); - propertiesSection.Bind(options.Properties); - - IConfigurationSection providersSection = egressSection.GetSection(nameof(EgressOptions.Providers)); - foreach (var providerSection in providersSection.GetChildren()) - { - string providerName = providerSection.Key; - - KeyValueLogScope providerNameScope = new KeyValueLogScope(); - providerNameScope.Values.Add("EgressProviderName", providerName); - using var providerNameRegistration = _logger.BeginScope(providerNameScope); - - CommonEgressProviderOptions commonOptions = new CommonEgressProviderOptions(); - providerSection.Bind(commonOptions); - - EgressProviderValidation validation = new EgressProviderValidation(providerName, _logger); - if (!validation.TryValidate(commonOptions)) - { - _logger.EgressProviderInvalidOptions(providerName); - } - - string providerType = commonOptions.Type; - KeyValueLogScope providerTypeScope = new KeyValueLogScope(); - providerTypeScope.Values.Add("EgressProviderType", providerType); - using var providerTypeRegistration = _logger.BeginScope(providerTypeScope); - - if (!_factories.TryGetValue(providerType, out EgressFactory factory)) - { - _logger.EgressProviderInvalidType(providerName, providerType); - continue; - } - - if (!factory.TryCreate(providerName, providerSection, options.Properties, out ConfiguredEgressProvider provider)) - { - _logger.EgressProviderInvalidOptions(providerName); - continue; - } - - options.Providers.Add(providerName, provider); - - _logger.EgressProviderAdded(providerName); - } - } - - /// - /// Configuration options to all egress providers. - /// - internal class CommonEgressProviderOptions - { - /// - /// The type of the egress provider. - /// - [Required] - public string Type { get; set; } - } - } -} diff --git a/src/Tools/dotnet-monitor/Egress/Configuration/EgressOptions.cs b/src/Tools/dotnet-monitor/Egress/Configuration/EgressOptions.cs deleted file mode 100644 index a705092e812..00000000000 --- a/src/Tools/dotnet-monitor/Egress/Configuration/EgressOptions.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Collections.Generic; - -namespace Microsoft.Diagnostics.Tools.Monitor.Egress.Configuration -{ - /// - /// Configuration options for specifying egress providers. - /// - internal class EgressOptions - { - /// - /// Mapping of egress provider names to egress provider implementations. - /// - public Dictionary Providers { get; } - = new Dictionary(StringComparer.OrdinalIgnoreCase); - - /// - /// Mapping of keyed values, typically used for naming a secret such as a storage account - /// key or shared access signature rather than embedding values directly in the egress provider options. - /// - public Dictionary Properties { get; } - = new Dictionary(StringComparer.OrdinalIgnoreCase); - } -} diff --git a/src/Tools/dotnet-monitor/Egress/Configuration/EgressOptionsCache.cs b/src/Tools/dotnet-monitor/Egress/Configuration/EgressOptionsCache.cs new file mode 100644 index 00000000000..9663d61ef38 --- /dev/null +++ b/src/Tools/dotnet-monitor/Egress/Configuration/EgressOptionsCache.cs @@ -0,0 +1,75 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Extensions.Options; +using System; +using System.Diagnostics; + +namespace Microsoft.Diagnostics.Tools.Monitor.Egress.Configuration +{ + /// + /// Custom to override behavior + /// for the default named options. + /// + /// + /// This cache implementation handles the default name as an indication for performing an operation + /// on all of the names in the cache (e.g. on the default name signals + /// that all of the named options should be cleared. + /// + internal sealed class EgressOptionsCache : + OptionsCache + where TOptions : class + { + public override TOptions GetOrAdd(string name, Func createOptions) + { + // The IOptionsChangeTokenSource implementations will notify when the TOptions need + // to be recomputed, however the registrations of these sources will only notify for the default + // named option instance (because the names are not known at serivce configuration time). Nothing, + // except for OptionsMonitor change notification, should be attempting to create/cache + // options for the default name. In this case, just return the default value (because there is no + // way to get a valid set of options for the default name and the value isn't used by anything). + if (IsDefaultName(name)) + { + return default; + } + + return base.GetOrAdd(name, createOptions); + } + + public override bool TryAdd(string name, TOptions options) + { + // The IOptionsChangeTokenSource implementations will notify when the TOptions need + // to be recomputed, however the registrations of these sources will only notify for the default + // named option instance (because the names are not known at serivce configuration time). Nothing + // should be calling into this method, but handle the default name just in case. + if (IsDefaultName(name)) + { + Debug.Fail("Did not expect anything to attempt to cache a value for the default name."); + return false; + } + + return base.TryAdd(name, options); + } + + public override bool TryRemove(string name) + { + // The IOptionsChangeTokenSource implementations will notify when the TOptions need + // to be recomputed, however the registrations of these sources will only notify for the default + // named option instance (because the names are not known at serivce configuration time). Thus, + // interpret a removal of the default named option as a removal of all of the options instances. + if (IsDefaultName(name)) + { + Clear(); + return false; + } + + return base.TryRemove(name); + } + + private bool IsDefaultName(string name) + { + return string.Equals(name, Options.DefaultName, StringComparison.Ordinal); + } + } +} diff --git a/src/Tools/dotnet-monitor/Egress/Configuration/EgressPropertiesConfigurationChangeTokenSource.cs b/src/Tools/dotnet-monitor/Egress/Configuration/EgressPropertiesConfigurationChangeTokenSource.cs new file mode 100644 index 00000000000..0d973045114 --- /dev/null +++ b/src/Tools/dotnet-monitor/Egress/Configuration/EgressPropertiesConfigurationChangeTokenSource.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Extensions.Options; + +namespace Microsoft.Diagnostics.Tools.Monitor.Egress.Configuration +{ + /// + /// Raises a notification that the + /// may have changed when the Egress:Properties section changes. + /// + internal sealed class EgressPropertiesConfigurationChangeTokenSource : + ConfigurationChangeTokenSource + { + public EgressPropertiesConfigurationChangeTokenSource(IEgressPropertiesConfigurationProvider provider) + : base(provider.Configuration) + { + } + } +} diff --git a/src/Tools/dotnet-monitor/Egress/Configuration/EgressPropertiesConfigurationProvider.cs b/src/Tools/dotnet-monitor/Egress/Configuration/EgressPropertiesConfigurationProvider.cs new file mode 100644 index 00000000000..71c6dee0c5f --- /dev/null +++ b/src/Tools/dotnet-monitor/Egress/Configuration/EgressPropertiesConfigurationProvider.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Extensions.Configuration; + +namespace Microsoft.Diagnostics.Tools.Monitor.Egress.Configuration +{ + /// + /// Provides access to the Egress:Properties section of the configuration. + /// + internal class EgressPropertiesConfigurationProvider : + IEgressPropertiesConfigurationProvider + { + public EgressPropertiesConfigurationProvider(IConfiguration configuration) + { + Configuration = configuration.GetEgressPropertiesSection(); + } + + /// + public IConfiguration Configuration { get; } + } +} diff --git a/src/Tools/dotnet-monitor/Egress/Configuration/EgressPropertiesProvider.cs b/src/Tools/dotnet-monitor/Egress/Configuration/EgressPropertiesProvider.cs new file mode 100644 index 00000000000..967116b4eea --- /dev/null +++ b/src/Tools/dotnet-monitor/Egress/Configuration/EgressPropertiesProvider.cs @@ -0,0 +1,35 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Extensions.Configuration; + +namespace Microsoft.Diagnostics.Tools.Monitor.Egress.Configuration +{ + /// + /// Provides strongly-typed access to the values described in the Egress:Properties section. + /// + internal sealed class EgressPropertiesProvider : + IEgressPropertiesProvider + { + private readonly IEgressPropertiesConfigurationProvider _provider; + + public EgressPropertiesProvider(IEgressPropertiesConfigurationProvider provider) + { + _provider = provider; + } + + /// + public bool TryGetPropertyValue(string key, out string value) + { + IConfigurationSection section = _provider.Configuration.GetSection(key); + if (!section.Exists()) + { + value = null; + return false; + } + value = section.Value; + return true; + } + } +} diff --git a/src/Tools/dotnet-monitor/Egress/Configuration/EgressProviderConfigurationChangeTokenSource.cs b/src/Tools/dotnet-monitor/Egress/Configuration/EgressProviderConfigurationChangeTokenSource.cs new file mode 100644 index 00000000000..007882149a4 --- /dev/null +++ b/src/Tools/dotnet-monitor/Egress/Configuration/EgressProviderConfigurationChangeTokenSource.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Extensions.Options; + +namespace Microsoft.Diagnostics.Tools.Monitor.Egress.Configuration +{ + /// + /// Raises a notification that the + /// may have changed when the Egress:{ProviderType} section changes. + /// + internal sealed class EgressProviderConfigurationChangeTokenSource : + ConfigurationChangeTokenSource + { + public EgressProviderConfigurationChangeTokenSource(IEgressProviderConfigurationProvider provider) + : base(provider.Configuration) + { + } + } +} diff --git a/src/Tools/dotnet-monitor/Egress/Configuration/EgressProviderConfigurationProvider.cs b/src/Tools/dotnet-monitor/Egress/Configuration/EgressProviderConfigurationProvider.cs new file mode 100644 index 00000000000..12b0ca58389 --- /dev/null +++ b/src/Tools/dotnet-monitor/Egress/Configuration/EgressProviderConfigurationProvider.cs @@ -0,0 +1,32 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Extensions.Configuration; +using System; + +namespace Microsoft.Diagnostics.Tools.Monitor.Egress.Configuration +{ + /// + /// Provides access to the Egress:{ProviderType} section of the configuration that is + /// associated with the type. + /// + internal sealed class EgressProviderConfigurationProvider : + IEgressProviderConfigurationProvider + { + public EgressProviderConfigurationProvider(IConfiguration configuration, string providerType) + { + ProviderType = providerType; + Configuration = configuration.GetEgressSection().GetSection(providerType); + } + + /// + public IConfiguration Configuration { get; } + + /// + public string ProviderType { get; } + + /// + public Type OptionsType => typeof(TOptions); + } +} diff --git a/src/Tools/dotnet-monitor/Egress/Configuration/EgressProviderConfigureNamedOptions.cs b/src/Tools/dotnet-monitor/Egress/Configuration/EgressProviderConfigureNamedOptions.cs new file mode 100644 index 00000000000..68e8c4d2ab7 --- /dev/null +++ b/src/Tools/dotnet-monitor/Egress/Configuration/EgressProviderConfigureNamedOptions.cs @@ -0,0 +1,44 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.Options; +using System; +using System.Diagnostics; + +namespace Microsoft.Diagnostics.Tools.Monitor.Egress.Configuration +{ + /// + /// Configure an by binding to + /// its associated Egress:{ProviderType}:{Name} section in the configuration. + /// + /// + /// Only named options are support for egress providers. + /// + internal sealed class EgressProviderConfigureNamedOptions : + IConfigureNamedOptions where TOptions : class + { + private readonly IEgressProviderConfigurationProvider _provider; + + public EgressProviderConfigureNamedOptions(IEgressProviderConfigurationProvider provider) + { + _provider = provider; + } + + public void Configure(string name, TOptions options) + { + IConfigurationSection section = _provider.Configuration.GetSection(name); + Debug.Assert(section.Exists()); + if (section.Exists()) + { + section.Bind(options); + } + } + + public void Configure(TOptions options) + { + throw new NotSupportedException(); + } + } +} diff --git a/src/Tools/dotnet-monitor/Egress/Configuration/EgressProviderValidateOptions.cs b/src/Tools/dotnet-monitor/Egress/Configuration/EgressProviderValidateOptions.cs new file mode 100644 index 00000000000..9972d2f5bbd --- /dev/null +++ b/src/Tools/dotnet-monitor/Egress/Configuration/EgressProviderValidateOptions.cs @@ -0,0 +1,44 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel.DataAnnotations; + +namespace Microsoft.Diagnostics.Tools.Monitor.Egress.Configuration +{ + /// + /// Validates the settings within a instance + /// using data annotation validation. + /// + internal sealed class EgressProviderValidateOptions : + IValidateOptions where TOptions : class + { + public ValidateOptionsResult Validate(string name, TOptions options) + { + ValidationContext validationContext = new ValidationContext(options); + ICollection results = new Collection(); + if (!Validator.TryValidateObject(options, validationContext, results, validateAllProperties: true)) + { + IList failures = new List(); + foreach (ValidationResult result in results) + { + if (ValidationResult.Success != result) + { + failures.Add(result.ErrorMessage); + } + } + + if (failures.Count > 0) + { + return ValidateOptionsResult.Fail(failures); + } + } + + return ValidateOptionsResult.Success; + } + } +} diff --git a/src/Tools/dotnet-monitor/Egress/Configuration/IEgressPropertiesConfigurationProvider.cs b/src/Tools/dotnet-monitor/Egress/Configuration/IEgressPropertiesConfigurationProvider.cs new file mode 100644 index 00000000000..795e4aadbe5 --- /dev/null +++ b/src/Tools/dotnet-monitor/Egress/Configuration/IEgressPropertiesConfigurationProvider.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Extensions.Configuration; + +namespace Microsoft.Diagnostics.Tools.Monitor.Egress.Configuration +{ + /// + /// Provides access to the Egress:Properties section of the configuration. + /// + internal interface IEgressPropertiesConfigurationProvider + { + /// + /// The configuration section associated with the egress properties. + /// + IConfiguration Configuration { get; } + } +} diff --git a/src/Tools/dotnet-monitor/Egress/Configuration/IEgressPropertiesProvider.cs b/src/Tools/dotnet-monitor/Egress/Configuration/IEgressPropertiesProvider.cs new file mode 100644 index 00000000000..d3fc73309c6 --- /dev/null +++ b/src/Tools/dotnet-monitor/Egress/Configuration/IEgressPropertiesProvider.cs @@ -0,0 +1,17 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +namespace Microsoft.Diagnostics.Tools.Monitor.Egress.Configuration +{ + /// + /// Provides strongly-typed access to the values described in the Egress:Properties section. + /// + internal interface IEgressPropertiesProvider + { + /// + /// Attempts to get the value associated with the specified key from the Egress:Properties section. + /// + bool TryGetPropertyValue(string key, out string value); + } +} diff --git a/src/Tools/dotnet-monitor/Egress/Configuration/IEgressProviderConfigurationProvider.cs b/src/Tools/dotnet-monitor/Egress/Configuration/IEgressProviderConfigurationProvider.cs new file mode 100644 index 00000000000..0fe56a32a86 --- /dev/null +++ b/src/Tools/dotnet-monitor/Egress/Configuration/IEgressProviderConfigurationProvider.cs @@ -0,0 +1,39 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Extensions.Configuration; +using System; + +namespace Microsoft.Diagnostics.Tools.Monitor.Egress.Configuration +{ + /// + /// Provides access to an Egress:{ProviderType} section of the configuration. + /// + internal interface IEgressProviderConfigurationProvider + { + /// + /// The configuration section associated with the egress provider. + /// + IConfiguration Configuration { get; } + + /// + /// The type of the egress provider. + /// + string ProviderType { get; } + + /// + /// The type of the options class associated with the egress provider. + /// + Type OptionsType { get; } + } + + /// + /// Provides access to the Egress:{ProviderType} section of the configuration that is + /// associated with the type. + /// + internal interface IEgressProviderConfigurationProvider : + IEgressProviderConfigurationProvider + { + } +} diff --git a/src/Tools/dotnet-monitor/Egress/ConfiguredEgressProvider.cs b/src/Tools/dotnet-monitor/Egress/ConfiguredEgressProvider.cs deleted file mode 100644 index bbdd5ba466e..00000000000 --- a/src/Tools/dotnet-monitor/Egress/ConfiguredEgressProvider.cs +++ /dev/null @@ -1,51 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.Diagnostics.Monitoring.WebApi; -using System; -using System.IO; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.Diagnostics.Tools.Monitor.Egress -{ - /// - /// Base class for configured egress providers. A configured egress provider is an egress provider instance - /// that does not require any additional configuration beyond information about the stream that will be egressed. - /// - internal abstract class ConfiguredEgressProvider - { - /// - /// Egress a stream via a callback by returning the stream from the callback. - /// - /// Callback that is invoked in order to get the stream to be egressed. - /// The name of the stream data, typically used as the file name. - /// The type of content contained by the stream. - /// The source of the egress artifact; for for interrogation purposed to fill out additional stream option data. - /// The token to monitor for cancellation requests. - /// A task that completes with an describing the completion of the egress operation. - public abstract Task EgressAsync( - Func> action, - string fileName, - string contentType, - IEndpointInfo source, - CancellationToken token); - - /// - /// Egress a stream via a callback by writing to the provided stream. - /// - /// Callback that is invoked in order to write data to the provided stream. - /// The name of the stream data, typically used as the file name. - /// The type of content contained by the stream. - /// The source of the egress artifact; for for interrogation purposed to fill out additional stream option data. - /// The token to monitor for cancellation requests. - /// A task that completes with an describing the completion of the egress operation. - public abstract Task EgressAsync( - Func action, - string fileName, - string contentType, - IEndpointInfo source, - CancellationToken token); - } -} diff --git a/src/Tools/dotnet-monitor/Egress/AzureBlob/AzureBlobEgressStreamOptions.cs b/src/Tools/dotnet-monitor/Egress/EgressArtifactSettings.cs similarity index 58% rename from src/Tools/dotnet-monitor/Egress/AzureBlob/AzureBlobEgressStreamOptions.cs rename to src/Tools/dotnet-monitor/Egress/EgressArtifactSettings.cs index 65ef036c716..47b9adb9827 100644 --- a/src/Tools/dotnet-monitor/Egress/AzureBlob/AzureBlobEgressStreamOptions.cs +++ b/src/Tools/dotnet-monitor/Egress/EgressArtifactSettings.cs @@ -1,16 +1,9 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; +using System; using System.Collections.Generic; -namespace Microsoft.Diagnostics.Tools.Monitor.Egress.AzureStorage +namespace Microsoft.Diagnostics.Tools.Monitor.Egress { - /// - /// Egress stream options for Azure blob storage. - /// - internal class AzureBlobEgressStreamOptions + internal sealed class EgressArtifactSettings { /// /// The content encoding of the blob to be created. @@ -27,5 +20,10 @@ internal class AzureBlobEgressStreamOptions /// public Dictionary Metadata { get; } = new Dictionary(StringComparer.Ordinal); + + /// + /// The name of the artifact. + /// + public string Name { get; set; } } } diff --git a/src/Tools/dotnet-monitor/Egress/EgressFactory.cs b/src/Tools/dotnet-monitor/Egress/EgressFactory.cs deleted file mode 100644 index 00a2a0f87c1..00000000000 --- a/src/Tools/dotnet-monitor/Egress/EgressFactory.cs +++ /dev/null @@ -1,45 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging; -using System.Collections.Generic; - -namespace Microsoft.Diagnostics.Tools.Monitor.Egress -{ - /// - /// Base class for creating configured egress providers. - /// - internal abstract class EgressFactory - { - public EgressFactory(ILogger logger) - { - Logger = logger; - } - - /// - /// Attempts to create a from the provided - /// and . - /// - /// The name of the egress provider. - /// The configuration section containing the provider options. - /// The mapping of egress properties. - /// The created . - /// True if the provider was created; otherwise, false. - public abstract bool TryCreate( - string providerName, - IConfigurationSection providerSection, - Dictionary egressProperties, - out ConfiguredEgressProvider provider); - - protected bool TryValidateOptions(object value, string providerName) - { - Logger.EgressProviderValidatingOptions(providerName); - EgressProviderValidation validation = new EgressProviderValidation(providerName, Logger); - return validation.TryValidate(value); - } - - protected ILogger Logger { get; } - } -} diff --git a/src/Tools/dotnet-monitor/Egress/EgressProvider.cs b/src/Tools/dotnet-monitor/Egress/EgressProvider.cs index cb4f2438b0b..1decf208d95 100644 --- a/src/Tools/dotnet-monitor/Egress/EgressProvider.cs +++ b/src/Tools/dotnet-monitor/Egress/EgressProvider.cs @@ -13,15 +13,16 @@ namespace Microsoft.Diagnostics.Tools.Monitor.Egress { /* * == Egress Provider Design == - * - Each type of egress is implemented as an EgressProvider. The following are the built-in providers: + * - Each type of egress is implemented as an EgressProvider. The following are the built-in providers: * - AzureBlobEgressProvider: Allows egressing stream data to a blob in Azure blob storage. * - FileSystemEgressProvider: Allows egressing stream data to the file system. - * - When constructing an egress provider, the options of the provider must be passed via the constructor. - * These options are typically use for describing to where stream data is to be egressed. - * - When invoking an egress provider, an action for acquiring the stream data, a file name, and stream options - * are required. The acquisition action can either provide the stream or allow the provider to provision the - * stream, which is passed into the action. The stream options represent additional data about the storage - * of the stream. + * The egress provider options are typically use for describing to where stream data is to be egressed. + * - When invoking an egress provider, the following are required: + * - an options instance describing to where the artifact should be egressed + * - an action for acquiring the stream data. + * - a settings instance describing aspects of the artifact, such as its file name and content type. + * The acquisition action can either provide the stream or allow the provider to provision the + * stream, which is passed into the action. * - When an egress provider finishes egressing stream data, it will return a value that identifies the location * of where the stream data was egressed. */ @@ -29,46 +30,43 @@ namespace Microsoft.Diagnostics.Tools.Monitor.Egress /// /// Base class for all egress implementations. /// - /// Type of provider options class. - /// Type of stream options class. + /// Type of provider options class. /// - /// The type is typically used for providing information + /// The type is typically used for providing information /// about to where a stream is egressed (e.g. directory path, blob storage account, etc). - /// The type is typically used for providing information - /// about the storage of the stream itself (e.g. file system permissions, file metadata, etc). /// Egress providers should throw when operational error occurs /// (e.g. unable to write out stream data). Nearly all other exceptions are treats as programming /// errors with the exception of and . - internal abstract class EgressProvider - where TProviderOptions : EgressProviderOptions + internal abstract class EgressProvider : + IEgressProvider + where TOptions : IEgressProviderCommonOptions { - protected EgressProvider(TProviderOptions options, ILogger logger = null) + protected EgressProvider(ILogger logger) { Logger = logger; - Options = options; } /// /// Egress a stream via a callback by returning the stream from the callback. /// + /// Described to where stream data should be egressed. /// Callback that is invoked in order to get the stream to be egressed. - /// The name of the stream, typically used as a file name. - /// Additional information to apply to the storage of the stream data. + /// Describes data about the artifact, such as file name and content type. /// The token to monitor for cancellation requests. /// A task that completes with a value of the identifier of the egress result. Typically, /// this is a path to access the stream without any information indicating whether any particular /// user has access to it (e.g. no file system permissions or SAS tokens). public virtual Task EgressAsync( + TOptions options, Func> action, - string name, - TStreamOptions streamOptions, + EgressArtifactSettings artifactSettings, CancellationToken token) { Func wrappingAction = async (targetStream, token) => { using var sourceStream = await action(token); - int copyBufferSize = Options.CopyBufferSize.GetValueOrDefault(0x100000); + int copyBufferSize = options.CopyBufferSize.GetValueOrDefault(0x100000); Logger?.EgressCopyActionStreamToEgressStream(copyBufferSize); @@ -79,36 +77,28 @@ await sourceStream.CopyToAsync( }; return EgressAsync( + options, wrappingAction, - name, - streamOptions, + artifactSettings, token); } /// /// Egress a stream via a callback by writing to the provided stream. /// + /// Described to where stream data should be egressed. /// Callback that is invoked in order to write data to the provided stream. - /// The name of the stream, typically used as a file name. - /// Additional information to apply to the storage of the stream data. + /// Describes data about the artifact, such as file name and content type. /// The token to monitor for cancellation requests. /// A task that completes with a value of the identifier of the egress result. Typically, /// this is a path to access the stream without any information indicating whether any particular /// user has access to it (e.g. no file system permissions or SAS tokens). public abstract Task EgressAsync( + TOptions options, Func action, - string name, - TStreamOptions streamOptions, + EgressArtifactSettings artifactSettings, CancellationToken token); - protected void ValidateOptions() - { - ValidationContext context = new ValidationContext(Options); - Validator.ValidateObject(Options, context, validateAllProperties: true); - } - protected ILogger Logger { get; } - - protected TProviderOptions Options { get; } } } diff --git a/src/Tools/dotnet-monitor/Egress/EgressProviderInternal.cs b/src/Tools/dotnet-monitor/Egress/EgressProviderInternal.cs new file mode 100644 index 00000000000..0b4f4e75450 --- /dev/null +++ b/src/Tools/dotnet-monitor/Egress/EgressProviderInternal.cs @@ -0,0 +1,86 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.Diagnostics.Tools.Monitor.Egress +{ + /// + /// A wrapper implementation that takes an egress provider name, gets the egress provider options + /// based on that name, and invokes the corresponding implementation + /// to perform the egress action. + /// + internal class EgressProviderInternal : + IEgressProviderInternal + where TOptions : class + { + private readonly ILogger> _logger; + private readonly IEgressProvider _provider; + private readonly IOptionsMonitor _monitor; + + public EgressProviderInternal( + ILogger> logger, + IEgressProvider provider, + IOptionsMonitor monitor) + { + _logger = logger; + _provider = provider; + _monitor = monitor; + } + + /// + public Task EgressAsync( + string providerName, + Func> action, + EgressArtifactSettings artifactSettings, + CancellationToken token) + { + return _provider.EgressAsync( + GetOptions(providerName), + action, + artifactSettings, + token); + } + + /// + public Task EgressAsync( + string providerName, + Func action, + EgressArtifactSettings artifactSettings, + CancellationToken token) + { + return _provider.EgressAsync( + GetOptions(providerName), + action, + artifactSettings, + token); + } + + private TOptions GetOptions(string providerName) + { + try + { + return _monitor.Get(providerName); + } + catch (OptionsValidationException ex) + { + foreach (string failure in ex.Failures) + { + _logger.EgressProviderOptionsValidationFailure(providerName, failure); + } + + _logger.EgressProviderInvalidOptions(providerName); + + throw new EgressException(string.Format(CultureInfo.CurrentCulture, Strings.ErrorMessage_EgressProviderDoesNotExist, providerName)); + } + } + } +} diff --git a/src/Tools/dotnet-monitor/Egress/EgressProviderValidation.cs b/src/Tools/dotnet-monitor/Egress/EgressProviderValidation.cs deleted file mode 100644 index 87dd35616b6..00000000000 --- a/src/Tools/dotnet-monitor/Egress/EgressProviderValidation.cs +++ /dev/null @@ -1,55 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.Extensions.Logging; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.ComponentModel.DataAnnotations; - -namespace Microsoft.Diagnostics.Tools.Monitor.Egress -{ - /// - /// Helper class for validating egress options. - /// - internal class EgressProviderValidation - { - private readonly ILogger _logger; - private readonly string _providerName; - - public EgressProviderValidation(string providerName, ILogger logger = null) - { - _logger = logger; - _providerName = providerName; - } - - /// - /// Validates that the egress options pass the self-described validation. - /// - /// The instance of the options object. - /// True if the options object is valid; otherwise, false. - /// - /// Validation errors are logged as warnings. - /// - public bool TryValidate(object value) - { - ValidationContext validationContext = new ValidationContext(value); - ICollection results = new Collection(); - if (!Validator.TryValidateObject(value, validationContext, results, validateAllProperties: true)) - { - if (null != _logger) - { - foreach (ValidationResult result in results) - { - if (ValidationResult.Success != result) - { - _logger.EgressProviderOptionsValidationWarning(_providerName, result.ErrorMessage); - } - } - } - return false; - } - return true; - } - } -} diff --git a/src/Tools/dotnet-monitor/Egress/EgressService.cs b/src/Tools/dotnet-monitor/Egress/EgressService.cs index b3a77f86454..3b59c9d7c20 100644 --- a/src/Tools/dotnet-monitor/Egress/EgressService.cs +++ b/src/Tools/dotnet-monitor/Egress/EgressService.cs @@ -4,8 +4,14 @@ using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Diagnostics.Tools.Monitor.Egress.Configuration; -using Microsoft.Extensions.Options; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Primitives; using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; using System.Globalization; using System.IO; using System.Threading; @@ -16,31 +22,137 @@ namespace Microsoft.Diagnostics.Tools.Monitor.Egress /// /// Egress service implementation required by the REST server. /// - internal class EgressService : IEgressService + internal class EgressService : IEgressService, IDisposable { - private readonly IOptionsMonitor _egressOptions; + private readonly IDisposable _changeRegistration; + private readonly ILogger _logger; + private readonly IEnumerable _providers; + private readonly IDictionary _providerTypeMap; + private readonly IDictionary _optionsTypeMap; + private readonly IServiceProvider _serviceProvider; - public EgressService(IOptionsMonitor egressOptions) + public EgressService( + IServiceProvider serviceProvider, + ILogger logger, + IConfiguration configuration, + IEnumerable providers) { - _egressOptions = egressOptions; + _logger = logger; + _providers = providers; + _providerTypeMap = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + _optionsTypeMap = new ConcurrentDictionary(StringComparer.OrdinalIgnoreCase); + _serviceProvider = serviceProvider; + + _changeRegistration = ChangeToken.OnChange( + () => configuration.GetEgressSection().GetReloadToken(), + Reload); + + Reload(); + } + + public void Dispose() + { + _changeRegistration.Dispose(); + } + + public async Task EgressAsync(string providerName, Func> action, string fileName, string contentType, IEndpointInfo source, CancellationToken token) + { + string value = await GetProvider(providerName).EgressAsync( + providerName, + action, + CreateSettings(source, fileName, contentType), + token); + + return new EgressResult("name", value); } - public Task EgressAsync(string providerName, Func> action, string fileName, string contentType, IEndpointInfo source, CancellationToken token) + public async Task EgressAsync(string providerName, Func action, string fileName, string contentType, IEndpointInfo source, CancellationToken token) { - if (_egressOptions.CurrentValue.Providers.TryGetValue(providerName, out ConfiguredEgressProvider provider)) + string value = await GetProvider(providerName).EgressAsync( + providerName, + action, + CreateSettings(source, fileName, contentType), + token); + + return new EgressResult("name", value); + } + + private IEgressProviderInternal GetProvider(string providerName) + { + if (!_providerTypeMap.TryGetValue(providerName, out string providerType)) { - return provider.EgressAsync(action, fileName, contentType, source, token); + throw new EgressException(string.Format(CultureInfo.CurrentCulture, Strings.ErrorMessage_EgressProviderDoesNotExist, providerName)); } - throw new EgressException(string.Format(CultureInfo.CurrentCulture, Strings.ErrorMessage_EgressProviderDoesNotExist, providerName)); + + if (!_optionsTypeMap.TryGetValue(providerType, out Type optionsType)) + { + throw new EgressException(string.Format(CultureInfo.CurrentCulture, Strings.ErrorMessage_EgressProviderTypeNotRegistered, providerName)); + } + + // Get the egress provider that matches the options type and return the weaker-typed + // interface in order to allow egressing from the service without having to use reflection + // to invoke it. + return (IEgressProviderInternal)_serviceProvider.GetRequiredService( + typeof(IEgressProviderInternal<>).MakeGenericType(optionsType)); } - public Task EgressAsync(string providerName, Func action, string fileName, string contentType, IEndpointInfo source, CancellationToken token) + private static EgressArtifactSettings CreateSettings(IEndpointInfo source, string fileName, string contentType) { - if (_egressOptions.CurrentValue.Providers.TryGetValue(providerName, out ConfiguredEgressProvider provider)) + EgressArtifactSettings settings = new(); + settings.Name = fileName; + settings.ContentType = contentType; + + // Activity metadata + Activity activity = Activity.Current; + if (null != activity) { - return provider.EgressAsync(action, fileName, contentType, source, token); + settings.Metadata.Add( + ActivityMetadataNames.ParentId, + activity.GetParentId()); + settings.Metadata.Add( + ActivityMetadataNames.SpanId, + activity.GetSpanId()); + settings.Metadata.Add( + ActivityMetadataNames.TraceId, + activity.GetTraceId()); + } + + // Artifact metadata + settings.Metadata.Add( + ArtifactMetadataNames.ArtifactSource.ProcessId, + source.ProcessId.ToString(CultureInfo.InvariantCulture)); + settings.Metadata.Add( + ArtifactMetadataNames.ArtifactSource.RuntimeInstanceCookie, + source.RuntimeInstanceCookie.ToString("N")); + + return settings; + } + + private void Reload() + { + _providerTypeMap.Clear(); + _optionsTypeMap.Clear(); + + // Deliberately fill the maps in the reverse order of how they are accessed + // by the GetProvider method to avoid indeterminate accessing of the option + // information. + foreach (IEgressProviderConfigurationProvider provider in _providers) + { + _optionsTypeMap.Add(provider.ProviderType, provider.OptionsType); + + foreach (IConfigurationSection optionsSection in provider.Configuration.GetChildren()) + { + string providerName = optionsSection.Key; + if (_providerTypeMap.TryGetValue(providerName, out string existingProviderType)) + { + _logger.DuplicateEgressProviderIgnored(providerName, provider.ProviderType, existingProviderType); + } + else + { + _providerTypeMap.Add(providerName, provider.ProviderType); + } + } } - throw new EgressException(string.Format(CultureInfo.CurrentCulture, Strings.ErrorMessage_EgressProviderDoesNotExist, providerName)); } } } diff --git a/src/Tools/dotnet-monitor/Egress/FileSystem/FileSystemEgressProvider.cs b/src/Tools/dotnet-monitor/Egress/FileSystem/FileSystemEgressProvider.cs index 40e668154d1..11d8b37d9ac 100644 --- a/src/Tools/dotnet-monitor/Egress/FileSystem/FileSystemEgressProvider.cs +++ b/src/Tools/dotnet-monitor/Egress/FileSystem/FileSystemEgressProvider.cs @@ -16,33 +16,31 @@ namespace Microsoft.Diagnostics.Tools.Monitor.Egress.FileSystem /// Egress provider for egressing stream data to the file system. /// internal class FileSystemEgressProvider : - EgressProvider + EgressProvider { - public FileSystemEgressProvider(FileSystemEgressProviderOptions options, ILogger logger = null) - : base(options, logger) + public FileSystemEgressProvider(ILogger logger) + : base(logger) { } public override async Task EgressAsync( + FileSystemEgressProviderOptions options, Func action, - string name, - FileSystemEgressStreamOptions streamOptions, + EgressArtifactSettings artifactSettings, CancellationToken token) { - LogAndValidateOptions(name); - - if (!Directory.Exists(Options.DirectoryPath)) + if (!Directory.Exists(options.DirectoryPath)) { - WrapException(() => Directory.CreateDirectory(Options.DirectoryPath)); + WrapException(() => Directory.CreateDirectory(options.DirectoryPath)); } - string targetPath = Path.Combine(Options.DirectoryPath, name); + string targetPath = Path.Combine(options.DirectoryPath, artifactSettings.Name); - if (!string.IsNullOrEmpty(Options.IntermediateDirectoryPath)) + if (!string.IsNullOrEmpty(options.IntermediateDirectoryPath)) { - if (!Directory.Exists(Options.IntermediateDirectoryPath)) + if (!Directory.Exists(options.IntermediateDirectoryPath)) { - WrapException(() => Directory.CreateDirectory(Options.IntermediateDirectoryPath)); + WrapException(() => Directory.CreateDirectory(options.IntermediateDirectoryPath)); } string intermediateFilePath = null; @@ -52,7 +50,7 @@ public override async Task EgressAsync( bool intermediatePathExists; do { - intermediateFilePath = Path.Combine(Options.IntermediateDirectoryPath, Path.GetRandomFileName()); + intermediateFilePath = Path.Combine(options.IntermediateDirectoryPath, Path.GetRandomFileName()); intermediatePathExists = File.Exists(intermediateFilePath); remainingAttempts--; } @@ -60,7 +58,7 @@ public override async Task EgressAsync( if (intermediatePathExists) { - throw CreateException($"Unable to create unique intermediate file in '{Options.IntermediateDirectoryPath}' directory."); + throw CreateException(string.Format(CultureInfo.CurrentCulture, Strings.ErrorMessage_EgressUnableToCreateIntermediateFile, options.IntermediateDirectoryPath)); } await WriteFileAsync(action, intermediateFilePath, token); @@ -91,15 +89,6 @@ public override async Task EgressAsync( return targetPath; } - private void LogAndValidateOptions(string fileName) - { - Logger?.EgressProviderOptionValue(EgressProviderTypes.FileSystem, nameof(Options.DirectoryPath), Options.DirectoryPath); - Logger?.EgressProviderOptionValue(EgressProviderTypes.FileSystem, nameof(Options.IntermediateDirectoryPath), Options.IntermediateDirectoryPath); - Logger?.EgressProviderFileName(EgressProviderTypes.FileSystem, fileName); - - ValidateOptions(); - } - private async Task WriteFileAsync(Func action, string filePath, CancellationToken token) { using Stream fileStream = WrapException( diff --git a/src/Tools/dotnet-monitor/Egress/FileSystem/FileSystemEgressProviderOptions.cs b/src/Tools/dotnet-monitor/Egress/FileSystem/FileSystemEgressProviderOptions.cs index e3156e66d85..b66926ccdeb 100644 --- a/src/Tools/dotnet-monitor/Egress/FileSystem/FileSystemEgressProviderOptions.cs +++ b/src/Tools/dotnet-monitor/Egress/FileSystem/FileSystemEgressProviderOptions.cs @@ -2,26 +2,35 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using Microsoft.Diagnostics.Monitoring.WebApi; using System.ComponentModel.DataAnnotations; +#if UNITTEST +namespace Microsoft.Diagnostics.Monitoring.UnitTests.Options +#else namespace Microsoft.Diagnostics.Tools.Monitor.Egress.FileSystem +#endif { /// /// Egress provider options for file system egress. /// - internal class FileSystemEgressProviderOptions : - EgressProviderOptions + internal sealed class FileSystemEgressProviderOptions : + IEgressProviderCommonOptions { - /// - /// The directory path to which the stream data will be egressed. - /// + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_FileSystemEgressProviderOptions_DirectoryPath))] [Required] public string DirectoryPath { get; set; } - /// - /// The directory path to which the stream data will initially be written, if specified; the file will then - /// be moved/renamed to the directory specified in . - /// + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_FileSystemEgressProviderOptions_IntermediateDirectoryPath))] public string IntermediateDirectoryPath { get; set; } + + [Display( + ResourceType = typeof(OptionsDisplayStrings), + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_CommonEgressProviderOptions_CopyBufferSize))] + public int? CopyBufferSize { get; set; } } } diff --git a/src/Tools/dotnet-monitor/Egress/FileSystem/FileSystemEgressStreamOptions.cs b/src/Tools/dotnet-monitor/Egress/FileSystem/FileSystemEgressStreamOptions.cs deleted file mode 100644 index a3a19fddacc..00000000000 --- a/src/Tools/dotnet-monitor/Egress/FileSystem/FileSystemEgressStreamOptions.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -namespace Microsoft.Diagnostics.Tools.Monitor.Egress.FileSystem -{ - /// - /// Egress stream options for file system egress. - /// - internal class FileSystemEgressStreamOptions - { - } -} diff --git a/src/Tools/dotnet-monitor/Egress/FileSystemEgressFactory.cs b/src/Tools/dotnet-monitor/Egress/FileSystemEgressFactory.cs deleted file mode 100644 index 0137f5a7d96..00000000000 --- a/src/Tools/dotnet-monitor/Egress/FileSystemEgressFactory.cs +++ /dev/null @@ -1,86 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using Microsoft.Diagnostics.Monitoring.WebApi; -using Microsoft.Diagnostics.Tools.Monitor.Egress.FileSystem; -using Microsoft.Extensions.Configuration; -using Microsoft.Extensions.Logging; -using System; -using System.Collections.Generic; -using System.IO; -using System.Threading; -using System.Threading.Tasks; - -namespace Microsoft.Diagnostics.Tools.Monitor.Egress -{ - /// - /// Creates for file system egress. - /// - internal class FileSystemEgressFactory : EgressFactory - { - private ILoggerFactory _loggerFactory; - - public FileSystemEgressFactory(ILoggerFactory loggerFactory) - : base(loggerFactory.CreateLogger()) - { - _loggerFactory = loggerFactory; - } - - public override bool TryCreate( - string providerName, - IConfigurationSection providerSection, - Dictionary egressProperties, - out ConfiguredEgressProvider provider) - { - var options = providerSection.Get(); - - if (!TryValidateOptions(options, providerName)) - { - provider = null; - return false; - } - - provider = new Provider(options, _loggerFactory); - return true; - } - - private class Provider : ConfiguredEgressProvider - { - private readonly FileSystemEgressProvider _provider; - - public Provider(FileSystemEgressProviderOptions options, ILoggerFactory loggerFactory) - { - _provider = new FileSystemEgressProvider(options, loggerFactory.CreateLogger()); - } - - public override async Task EgressAsync( - Func> action, - string fileName, - string contentType, - IEndpointInfo source, - CancellationToken token) - { - var streamOptions = new FileSystemEgressStreamOptions(); - - string filepath = await _provider.EgressAsync(action, fileName, streamOptions, token); - - return new EgressResult("path", filepath); - } - - public override async Task EgressAsync( - Func action, - string fileName, - string contentType, - IEndpointInfo source, - CancellationToken token) - { - var streamOptions = new FileSystemEgressStreamOptions(); - - string filepath = await _provider.EgressAsync(action, fileName, streamOptions, token); - - return new EgressResult("path", filepath); - } - } - } -} diff --git a/src/Tools/dotnet-monitor/Egress/IEgressProvider.cs b/src/Tools/dotnet-monitor/Egress/IEgressProvider.cs new file mode 100644 index 00000000000..f15158c203b --- /dev/null +++ b/src/Tools/dotnet-monitor/Egress/IEgressProvider.cs @@ -0,0 +1,26 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.Diagnostics.Tools.Monitor.Egress +{ + internal interface IEgressProvider + { + Task EgressAsync( + TOptions options, + Func> action, + EgressArtifactSettings artifactSettings, + CancellationToken token); + + Task EgressAsync( + TOptions options, + Func action, + EgressArtifactSettings artifactSettings, + CancellationToken token); + } +} diff --git a/src/Tools/dotnet-monitor/Egress/EgressProviderOptions.cs b/src/Tools/dotnet-monitor/Egress/IEgressProviderCommonOptions.cs similarity index 76% rename from src/Tools/dotnet-monitor/Egress/EgressProviderOptions.cs rename to src/Tools/dotnet-monitor/Egress/IEgressProviderCommonOptions.cs index d96131b3c32..4bba5320e81 100644 --- a/src/Tools/dotnet-monitor/Egress/EgressProviderOptions.cs +++ b/src/Tools/dotnet-monitor/Egress/IEgressProviderCommonOptions.cs @@ -2,17 +2,21 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#if UNITTEST +namespace Microsoft.Diagnostics.Monitoring.UnitTests.Options +#else namespace Microsoft.Diagnostics.Tools.Monitor.Egress +#endif { /// /// Egress provider options common to all egress providers. /// - internal abstract class EgressProviderOptions + internal interface IEgressProviderCommonOptions { /// /// Buffer size used when copying data from an egress callback returning a stream /// to the egress callback that is provided a stream to which data is written. /// - public int? CopyBufferSize { get; set; } + public int? CopyBufferSize { get; } } } diff --git a/src/Tools/dotnet-monitor/Egress/IEgressProviderInternal.cs b/src/Tools/dotnet-monitor/Egress/IEgressProviderInternal.cs new file mode 100644 index 00000000000..b7f50be40fc --- /dev/null +++ b/src/Tools/dotnet-monitor/Egress/IEgressProviderInternal.cs @@ -0,0 +1,31 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.IO; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.Diagnostics.Tools.Monitor.Egress +{ + internal interface IEgressProviderInternal + { + Task EgressAsync( + string providerName, + Func> action, + EgressArtifactSettings artifactSettings, + CancellationToken token); + + Task EgressAsync( + string providerName, + Func action, + EgressArtifactSettings artifactSettings, + CancellationToken token); + } + + internal interface IEgressProviderInternal : + IEgressProviderInternal + { + } +} diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Options/EgressOptions.cs b/src/Tools/dotnet-monitor/EgressOptions.cs similarity index 50% rename from src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Options/EgressOptions.cs rename to src/Tools/dotnet-monitor/EgressOptions.cs index 37a6780d059..5833f2ba7f6 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Options/EgressOptions.cs +++ b/src/Tools/dotnet-monitor/EgressOptions.cs @@ -3,38 +3,34 @@ // See the LICENSE file in the project root for more information. using Microsoft.Diagnostics.Monitoring.WebApi; -using System; +#if !UNITTEST +using Microsoft.Diagnostics.Tools.Monitor.Egress.AzureBlob; +using Microsoft.Diagnostics.Tools.Monitor.Egress.FileSystem; +#endif using System.Collections.Generic; using System.ComponentModel.DataAnnotations; -using System.Text.Json.Serialization; +#if UNITTEST namespace Microsoft.Diagnostics.Monitoring.UnitTests.Options +#else +namespace Microsoft.Diagnostics.Tools.Monitor +#endif { - internal class EgressOptions + internal sealed class EgressOptions { [Display( ResourceType = typeof(OptionsDisplayStrings), - Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_EgressOptions_Providers))] - public Dictionary Providers { get; set; } - = new(StringComparer.OrdinalIgnoreCase); + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_EgressOptions_AzureBlobStorage))] + public IDictionary AzureBlobStorage { get; set; } [Display( ResourceType = typeof(OptionsDisplayStrings), - Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_EgressOptions_Properties))] - public Dictionary Properties { get; set; } - = new(StringComparer.OrdinalIgnoreCase); - } + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_EgressOptions_FileSystem))] + public IDictionary FileSystem { get; set; } - internal class EgressProvider - { [Display( ResourceType = typeof(OptionsDisplayStrings), - Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_EgressProvider_EgressType))] - //TODO This should honor DataMember, but only seems to work with JsonProperty - [Newtonsoft.Json.JsonProperty("type", Required = Newtonsoft.Json.Required.Always)] - public string EgressType { get; set; } - - [JsonExtensionData] - public IDictionary Properties { get; } = new Dictionary(StringComparer.OrdinalIgnoreCase); + Description = nameof(OptionsDisplayStrings.DisplayAttributeDescription_EgressOptions_Properties))] + public IDictionary Properties { get; set; } } } diff --git a/src/Tools/dotnet-monitor/LoggingExtensions.cs b/src/Tools/dotnet-monitor/LoggingExtensions.cs index 07db455a067..8d4f8e9e859 100644 --- a/src/Tools/dotnet-monitor/LoggingExtensions.cs +++ b/src/Tools/dotnet-monitor/LoggingExtensions.cs @@ -13,11 +13,7 @@ namespace Microsoft.Diagnostics.Tools.Monitor { internal static class LoggingExtensions { - private static readonly Action _egressProviderAdded = - LoggerMessage.Define( - eventId: new EventId(1, "EgressProviderAdded"), - logLevel: LogLevel.Debug, - formatString: Strings.LogFormatString_EgressProviderAdded); + // 1:EgressProviderAdded private static readonly Action _egressProviderInvalidOptions = LoggerMessage.Define( @@ -25,17 +21,9 @@ internal static class LoggingExtensions logLevel: LogLevel.Error, formatString: Strings.LogFormatString_EgressProviderInvalidOptions); - private static readonly Action _egressProviderInvalidType = - LoggerMessage.Define( - eventId: new EventId(3, "EgressProviderInvalidType"), - logLevel: LogLevel.Error, - formatString: Strings.LogFormatString_EgressProviderInvalidType); + // 3:EgressProviderInvalidType - private static readonly Action _egressProviderValidatingOptions = - LoggerMessage.Define( - eventId: new EventId(4, "EgressProviderValidatingOptions"), - logLevel: LogLevel.Debug, - formatString: Strings.LogFormatString_EgressProviderValidatingOptions); + // 4:EgressProviderValidatingOptions private static readonly Action _egressCopyActionStreamToEgressStream = LoggerMessage.Define( @@ -43,29 +31,17 @@ internal static class LoggingExtensions logLevel: LogLevel.Debug, formatString: Strings.LogFormatString_EgressCopyActionStreamToEgressStream); - private static readonly Action _egressProviderOptionsValidationWarning = + private static readonly Action _egressProviderOptionsValidationFailure = LoggerMessage.Define( - eventId: new EventId(6, "EgressProviderOptionsValidationWarning"), - logLevel: LogLevel.Warning, - formatString: Strings.LogFormatString_EgressProviderOptionsValidationWarning); + eventId: new EventId(6, "EgressProviderOptionsValidationFailure"), + logLevel: LogLevel.Error, + formatString: Strings.LogFormatString_EgressProviderOptionsValidationError); - private static readonly Action _egressProviderOptionValue = - LoggerMessage.Define( - eventId: new EventId(7, "EgressProviderOptionValue"), - logLevel: LogLevel.Debug, - formatString: Strings.LogFormatString_EgressProviderOptionValue); + // 7:EgressProviderOptionValue - private static readonly Action _egressStreamOptionValue = - LoggerMessage.Define( - eventId: new EventId(8, "EgressStreamOptionValue"), - logLevel: LogLevel.Debug, - formatString: Strings.LogFormatString_EgressStreamOptionValue); + // 8:EgressStreamOptionValue - private static readonly Action _egressProviderFileName = - LoggerMessage.Define( - eventId: new EventId(9, "EgressProviderFileName"), - logLevel: LogLevel.Debug, - formatString: Strings.LogFormatString_EgressProviderFileName); + // 9:EgressProviderFileName private static readonly Action _egressProviderUnableToFindPropertyKey = LoggerMessage.Define( @@ -151,64 +127,24 @@ internal static class LoggingExtensions logLevel: LogLevel.Warning, formatString: Strings.LogFormatString_LogTempApiKey); - public static void EgressProviderAdded(this ILogger logger, string providerName) - { - _egressProviderAdded(logger, providerName, null); - } + private static readonly Action _duplicateEgressProviderIgnored = + LoggerMessage.Define( + eventId: new EventId(24, "DuplicateEgressProviderIgnored"), + logLevel: LogLevel.Warning, + formatString: Strings.LogFormatString_DuplicateEgressProviderIgnored); public static void EgressProviderInvalidOptions(this ILogger logger, string providerName) { _egressProviderInvalidOptions(logger, providerName, null); } - - public static void EgressProviderInvalidType(this ILogger logger, string providerName, string providerType) - { - _egressProviderInvalidType(logger, providerName, providerType, null); - } - - public static void EgressProviderValidatingOptions(this ILogger logger, string providerName) - { - _egressProviderValidatingOptions(logger, providerName, null); - } - public static void EgressCopyActionStreamToEgressStream(this ILogger logger, int bufferSize) { _egressCopyActionStreamToEgressStream(logger, bufferSize, null); } - public static void EgressProviderOptionsValidationWarning(this ILogger logger, string providerName, string validationWarning) - { - _egressProviderOptionsValidationWarning(logger, providerName, validationWarning, null); - } - - public static void EgressProviderOptionValue(this ILogger logger, string providerName, string optionName, Uri optionValue) - { - logger.EgressProviderOptionValue(providerName, optionName, optionValue?.ToString()); - } - - public static void EgressProviderOptionValue(this ILogger logger, string providerName, string optionName, string optionValue, bool redact = false) - { - if (redact) - { - optionValue = Redact(optionValue); - } - - _egressProviderOptionValue(logger, providerName, optionName, optionValue, null); - } - - public static void EgressStreamOptionValue(this ILogger logger, string providerName, string optionName, string optionValue, bool redact = false) - { - if (redact) - { - optionValue = Redact(optionValue); - } - - _egressStreamOptionValue(logger, providerName, optionName, optionValue, null); - } - - public static void EgressProviderFileName(this ILogger logger, string providerName, string fileName) + public static void EgressProviderOptionsValidationFailure(this ILogger logger, string providerName, string failureMessage) { - _egressProviderFileName(logger, providerName, fileName, null); + _egressProviderOptionsValidationFailure(logger, providerName, failureMessage, null); } public static void EgressProviderUnableToFindPropertyKey(this ILogger logger, string providerName, string keyName) @@ -285,9 +221,9 @@ public static void LogTempKey(this ILogger logger, string monitorApiKey) _logTempKey(logger, Environment.NewLine, HeaderNames.Authorization, Monitoring.WebApi.AuthConstants.ApiKeySchema, monitorApiKey, null); } - private static string Redact(string value) + public static void DuplicateEgressProviderIgnored(this ILogger logger, string providerName, string providerType, string existingProviderType) { - return string.IsNullOrEmpty(value) ? value : ""; + _duplicateEgressProviderIgnored(logger, providerName, providerType, existingProviderType, null); } } } diff --git a/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs b/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs index cde226dbcee..d44058a28ab 100644 --- a/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs +++ b/src/Tools/dotnet-monitor/ServiceCollectionExtensions.cs @@ -4,10 +4,14 @@ using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Diagnostics.Tools.Monitor.Egress; +using Microsoft.Diagnostics.Tools.Monitor.Egress.AzureBlob; using Microsoft.Diagnostics.Tools.Monitor.Egress.Configuration; +using Microsoft.Diagnostics.Tools.Monitor.Egress.FileSystem; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.Options; +using System; namespace Microsoft.Diagnostics.Tools.Monitor { @@ -44,20 +48,63 @@ private static IServiceCollection ConfigureOptions(IServiceCollection service public static IServiceCollection ConfigureEgress(this IServiceCollection services, IConfiguration configuration) { - // Register change token for EgressOptions binding - services.AddSingleton>(new ConfigurationChangeTokenSource(configuration.GetEgressSection())); - - // Configure EgressOptions to bind to the Egress configuration key. - // The options are manually created due to how the Providers property - // holds concrete implementations that are based on the 'type' property - // for each provider entry. - services.AddSingleton, EgressConfigureOptions>(); - // Register IEgressService implementation that provides egressing // of artifacts for the REST server. services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(); + + // Register regress providers + services.RegisterProvider(EgressProviderTypes.AzureBlobStorage); + services.RegisterProvider(EgressProviderTypes.FileSystem); + + // Extra registrations for provider specific behavior + services.AddSingleton, AzureBlobEgressPostConfigureOptions>(); + return services; } + + private static IServiceCollection RegisterProvider(this IServiceCollection services, string name) + where TProvider : class, IEgressProvider + where TOptions : class + { + // Add services to provide raw configuration for the options type + services.AddSingleton(sp => new EgressProviderConfigurationProvider(sp.GetRequiredService(), name)); + services.AddSingletonForwarder, EgressProviderConfigurationProvider>(); + services.TryAddSingletonEnumerableForwarder>(); + + // Add options services for configuring the options type + services.AddSingleton, EgressProviderConfigureNamedOptions>(); + services.AddSingleton, EgressProviderValidateOptions>(); + + // Register change sources for the options type + services.AddSingleton, EgressPropertiesConfigurationChangeTokenSource>(); + services.AddSingleton, EgressProviderConfigurationChangeTokenSource>(); + + // Add custom options cache to override behavior of default named options + services.AddSingleton, EgressOptionsCache>(); + + // Add egress provider and internal provider wrapper + services.AddSingleton, TProvider>(); + services.AddSingleton, EgressProviderInternal>(); + + return services; + } + + private static void AddSingletonForwarder(this IServiceCollection services) where TImplementation : class, TService where TService : class + { + services.AddSingleton(sp => sp.GetRequiredService()); + } + + private static void TryAddSingletonEnumerableForwarder(this IServiceCollection services) where TImplementation : class, TService where TService : class + { + services.TryAddSingletonEnumerable(sp => sp.GetRequiredService()); + } + + private static void TryAddSingletonEnumerable(this IServiceCollection services, Func func) where TImplementation : class, TService where TService : class + { + services.TryAddEnumerable(ServiceDescriptor.Singleton(func)); + } } } diff --git a/src/Tools/dotnet-monitor/Strings.Designer.cs b/src/Tools/dotnet-monitor/Strings.Designer.cs index 386de6c1355..22f3d0bd5eb 100644 --- a/src/Tools/dotnet-monitor/Strings.Designer.cs +++ b/src/Tools/dotnet-monitor/Strings.Designer.cs @@ -19,7 +19,7 @@ namespace Microsoft.Diagnostics.Tools.Monitor { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class Strings { @@ -132,6 +132,24 @@ internal static string ErrorMessage_EgressProviderDoesNotExist { } } + /// + /// Looks up a localized string similar to Egress provider type '{0}' was not registered.. + /// + internal static string ErrorMessage_EgressProviderTypeNotRegistered { + get { + return ResourceManager.GetString("ErrorMessage_EgressProviderTypeNotRegistered", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unable to create unique intermediate file in '{0}' directory.. + /// + internal static string ErrorMessage_EgressUnableToCreateIntermediateFile { + get { + return ResourceManager.GetString("ErrorMessage_EgressUnableToCreateIntermediateFile", resourceCulture); + } + } + /// /// Looks up a localized string similar to The {0} field value '{1}' is not allowed.. /// @@ -394,34 +412,25 @@ internal static string LogFormatString_DisabledNegotiateWhileElevated { } /// - /// Looks up a localized string similar to Copying action stream to egress stream with buffer size {bufferSize}. - /// - internal static string LogFormatString_EgressCopyActionStreamToEgressStream { - get { - return ResourceManager.GetString("LogFormatString_EgressCopyActionStreamToEgressStream", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Provider '{providerName}': Added.. + /// Looks up a localized string similar to New provider '{providerName}' under type '{providerType}' was already registered with type '{existingProviderType}' and will be ignored.. /// - internal static string LogFormatString_EgressProviderAdded { + internal static string LogFormatString_DuplicateEgressProviderIgnored { get { - return ResourceManager.GetString("LogFormatString_EgressProviderAdded", resourceCulture); + return ResourceManager.GetString("LogFormatString_DuplicateEgressProviderIgnored", resourceCulture); } } /// - /// Looks up a localized string similar to Provider {providerType}: File name = {fileName}. + /// Looks up a localized string similar to Copying action stream to egress stream with buffer size {bufferSize}. /// - internal static string LogFormatString_EgressProviderFileName { + internal static string LogFormatString_EgressCopyActionStreamToEgressStream { get { - return ResourceManager.GetString("LogFormatString_EgressProviderFileName", resourceCulture); + return ResourceManager.GetString("LogFormatString_EgressCopyActionStreamToEgressStream", resourceCulture); } } /// - /// Looks up a localized string similar to Provider '{providerName}': Invalid options.. + /// Looks up a localized string similar to Provider '{providerName}': The options are invalid. The provider will not be available for use.. /// internal static string LogFormatString_EgressProviderInvalidOptions { get { @@ -429,15 +438,6 @@ internal static string LogFormatString_EgressProviderInvalidOptions { } } - /// - /// Looks up a localized string similar to Provider '{providerName}': Type '{providerType}' is not supported.. - /// - internal static string LogFormatString_EgressProviderInvalidType { - get { - return ResourceManager.GetString("LogFormatString_EgressProviderInvalidType", resourceCulture); - } - } - /// /// Looks up a localized string similar to Provider {providerType}: Invoking stream action.. /// @@ -448,20 +448,11 @@ internal static string LogFormatString_EgressProviderInvokeStreamAction { } /// - /// Looks up a localized string similar to Provider '{providerName}': {validationWarning}. - /// - internal static string LogFormatString_EgressProviderOptionsValidationWarning { - get { - return ResourceManager.GetString("LogFormatString_EgressProviderOptionsValidationWarning", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Provider {providerType}: Provider option {optionName} = {optionValue}. + /// Looks up a localized string similar to Provider '{providerName}': {failureMessage}. /// - internal static string LogFormatString_EgressProviderOptionValue { + internal static string LogFormatString_EgressProviderOptionsValidationError { get { - return ResourceManager.GetString("LogFormatString_EgressProviderOptionValue", resourceCulture); + return ResourceManager.GetString("LogFormatString_EgressProviderOptionsValidationError", resourceCulture); } } @@ -474,15 +465,6 @@ internal static string LogFormatString_EgressProviderSavedStream { } } - /// - /// Looks up a localized string similar to Provider '{providerName}': Validating options.. - /// - internal static string LogFormatString_EgressProviderValidatingOptions { - get { - return ResourceManager.GetString("LogFormatString_EgressProviderValidatingOptions", resourceCulture); - } - } - /// /// Looks up a localized string similar to Provider {providerType}: Unable to find '{keyName}' key in egress properties. /// @@ -492,15 +474,6 @@ internal static string LogFormatString_EgressProvideUnableToFindPropertyKey { } } - /// - /// Looks up a localized string similar to Provider {providerType}: Stream option {optionName} = {optionValue}. - /// - internal static string LogFormatString_EgressStreamOptionValue { - get { - return ResourceManager.GetString("LogFormatString_EgressStreamOptionValue", resourceCulture); - } - } - /// /// Looks up a localized string similar to WARNING: Authentication is enabled over insecure http transport. This can pose a security risk and is not intended for production environments.. /// diff --git a/src/Tools/dotnet-monitor/Strings.resx b/src/Tools/dotnet-monitor/Strings.resx index 6448e190ef2..f6ea170d6e8 100644 --- a/src/Tools/dotnet-monitor/Strings.resx +++ b/src/Tools/dotnet-monitor/Strings.resx @@ -154,6 +154,18 @@ Gets the format string for egress provider failure due to missing provider. 1 Format Parameter: 0. providerName: The name of the provider that could not be found. + + + Egress provider type '{0}' was not registered. + Gets the format string for egress provider type failure due to missing provider type. +1 Format Parameter: +0. providerType: The type of the provider that could not be found. + + + Unable to create unique intermediate file in '{0}' directory. + Gets the format string for file system egress provider failure due to inability to create an intermediate file. +1 Format Parameter: +0. intermediateFileDirectory: The directory where the intermediate file was attempted to be created. The {0} field value '{1}' is not allowed. @@ -300,38 +312,26 @@ Negotiate, Kerberos, and NTLM authentication are not enabled when running with elevated permissions. Gets the format string that is printed in the 20:DisabledNegotiateWhileElevated event. 0 Format Parameters + + + New provider '{providerName}' under type '{providerType}' was already registered with type '{existingProviderType}' and will be ignored. + Gets the format string that is printed in the 24:DuplicateEgressProviderIgnored event. +3 Format Parameter: +1. providerName: Name of the provider that was already registered +2. providerType: The type of provider that the new provider was attempting to be registered. +3. existingProviderType: The type of provider that the new provider name was already registered. Copying action stream to egress stream with buffer size {bufferSize} Gets the format string that is printed in the 5:EgressCopyActionStreamToEgressStream event. 1 Format Parameter: 1. bufferSize: Size of the buffer - - - Provider '{providerName}': Added. - Gets the format string that is printed in the 1:EgressProviderAdded event. -1 Format Parameter: -1. providerName: Name of the provider that was added - - - Provider {providerType}: File name = {fileName} - Gets the format string that is printed in the 9:EgressProviderFileName event. -2 Format Parameters: -1. providerType: Type of the provider -2. fileName: Name of the file being egressed - Provider '{providerName}': Invalid options. + Provider '{providerName}': The options are invalid. The provider will not be available for use. Gets the format string that is printed in the 2:EgressProviderInvalidOptions event. 1 Format Parameter: 1. providerName: Name of the provider that was not valid - - - Provider '{providerName}': Type '{providerType}' is not supported. - Gets the format string that is printed in the 3:EgressProviderInvalidType event. -2 Format Parameters: -1. providerName: Name of the provider that was not valid -2. providerType: Type of the provider that is not a valid type Provider {providerType}: Invoking stream action. @@ -339,20 +339,12 @@ 1 Format Parameter: 1. providerType: Type of the provider that was invoked - - Provider '{providerName}': {validationWarning} - Gets the format string that is printed in the 6:EgressProviderOptionsValidationWarning event. + + Provider '{providerName}': {failureMessage} + Gets the format string that is printed in the 6:EgressProviderOptionsValidationError event. 2 Format Parameters: 1. providerName: Name of the provider with a warning -2. validationWarning: The warning message - - - Provider {providerType}: Provider option {optionName} = {optionValue} - Gets the format string that is printed in the 7:EgressProviderOptionValue event. -3 Format Parameters: -1. providerType: Type of the provider -2. optionName: Name of the provider option on this provider -3. optionValue: Value of the option specified by OptionName +2. failureMessage: The failure message Provider {providerType}: Saved stream to {path} @@ -360,12 +352,6 @@ 2 Format Parameters: 1. providerType: Type of the provider 2. path: path where provider saved the stream - - - Provider '{providerName}': Validating options. - Gets the format string that is printed in the 4:EgressProviderValidatingOptions event. -1 Format Parameter: -1. providerName: Name of the provider that is being validated Provider {providerType}: Unable to find '{keyName}' key in egress properties @@ -373,14 +359,6 @@ 2 Format Parameters: 1. providerType: Type of the provider 2. keyName: Name of the property that could not be found - - - Provider {providerType}: Stream option {optionName} = {optionValue} - Gets the format string that is printed in the 8:EgressStreamOptionValue event. -3 Format Parameters: -1. providerType: Type of the provider -2. optionName: Name of the stream option on this provider -3. optionValue: Value of the option specified by OptionName WARNING: Authentication is enabled over insecure http transport. This can pose a security risk and is not intended for production environments. From 4a6712d48f3e7be12a7299c47817ac88a380199f Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 10 Jul 2021 12:40:36 +0000 Subject: [PATCH 151/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210709.15 (#553) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 3607ea0bff3..6e23e824d24 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - 0f37ede529d5b16aec856039ce18568d15d223e2 + 885cbe3ff7c844407404cf4e017275bcb59006df https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 05012ff5ca8..01fa38a9cc7 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21357.3 - 6.0.0-preview.7.21358.5 + 6.0.0-preview.7.21359.15 5.0.0-preview.21358.1 5.0.0-preview.21358.1 From c4a11c7aa2369d6133caca0da2a3527b6b27a3d5 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 10 Jul 2021 12:45:33 +0000 Subject: [PATCH 152/185] Update dependencies from https://github.com/dotnet/runtime build 20210710.1 (#552) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 6e23e824d24..19ce54b0d80 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 885cbe3ff7c844407404cf4e017275bcb59006df - + https://github.com/dotnet/runtime - d431d6a15726797965336176efe9ae15aba241fd + 739218439bb6d3b224e240c012f37c516ccd29c9 diff --git a/eng/Versions.props b/eng/Versions.props index 01fa38a9cc7..a30263da489 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21358.1 5.0.0-preview.21358.1 - 6.0.0-preview.7.21359.1 + 6.0.0-preview.7.21360.1 1.0.215101 From 8086fbc6a23baba8367c7a6f5bb7db8985d17e8b Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sun, 11 Jul 2021 12:41:04 +0000 Subject: [PATCH 153/185] Update dependencies from https://github.com/dotnet/runtime build 20210710.10 (#554) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 19ce54b0d80..501be3d48de 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 885cbe3ff7c844407404cf4e017275bcb59006df - + https://github.com/dotnet/runtime - 739218439bb6d3b224e240c012f37c516ccd29c9 + 83a4d3cc02fb04fce17b24fc09b3cdf77a12ba51 diff --git a/eng/Versions.props b/eng/Versions.props index a30263da489..a7253dc7ec8 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21358.1 5.0.0-preview.21358.1 - 6.0.0-preview.7.21360.1 + 6.0.0-preview.7.21360.10 1.0.215101 From 3405773d76fa5b21045dec9334834307541d5fed Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sun, 11 Jul 2021 12:41:12 +0000 Subject: [PATCH 154/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210710.2 (#555) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 501be3d48de..f167cf397f7 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - 885cbe3ff7c844407404cf4e017275bcb59006df + 223d6e527cc98ce13fe45e4e14911013dd5ad807 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index a7253dc7ec8..e803ba2eeb5 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21357.3 - 6.0.0-preview.7.21359.15 + 6.0.0-preview.7.21360.2 5.0.0-preview.21358.1 5.0.0-preview.21358.1 From 8f7d19f96a5558df8bafdda48b13b64eb34cdd06 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 12 Jul 2021 12:39:14 +0000 Subject: [PATCH 155/185] Update dependencies from https://github.com/dotnet/diagnostics build 20210709.1 (#556) [main] Update dependencies from dotnet/diagnostics --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index f167cf397f7..b8c21d9129d 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics - 429f3b7edddeab32ecfe7d18947dbb02d11cde27 + 06456894925c35a82f5be6d078a5a2bcd055806b - + https://github.com/dotnet/diagnostics - 429f3b7edddeab32ecfe7d18947dbb02d11cde27 + 06456894925c35a82f5be6d078a5a2bcd055806b diff --git a/eng/Versions.props b/eng/Versions.props index e803ba2eeb5..fa28c82a634 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-preview.7.21360.2 - 5.0.0-preview.21358.1 - 5.0.0-preview.21358.1 + 5.0.0-preview.21359.1 + 5.0.0-preview.21359.1 6.0.0-preview.7.21360.10 From 41baf940f238574fe06a8c6780a850ff5e950275 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 12 Jul 2021 12:49:37 +0000 Subject: [PATCH 156/185] Update dependencies from https://github.com/dotnet/runtime build 20210711.10 (#557) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index b8c21d9129d..c2820472a33 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 223d6e527cc98ce13fe45e4e14911013dd5ad807 - + https://github.com/dotnet/runtime - 83a4d3cc02fb04fce17b24fc09b3cdf77a12ba51 + 98b7ed1a3b0543a31b5a0f9069cf44cb70c9230c diff --git a/eng/Versions.props b/eng/Versions.props index fa28c82a634..8134a48c363 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21359.1 5.0.0-preview.21359.1 - 6.0.0-preview.7.21360.10 + 6.0.0-preview.7.21361.10 1.0.215101 From 0e98bbf0c977d29c2675ad2dc05a6d6071653d3b Mon Sep 17 00:00:00 2001 From: kkeirstead <85592574+kkeirstead@users.noreply.github.com> Date: Mon, 12 Jul 2021 12:31:19 -0700 Subject: [PATCH 157/185] Indefinite Trace Documentation (#550) --- documentation/api/trace-custom.md | 4 ++++ documentation/api/trace-get.md | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/documentation/api/trace-custom.md b/documentation/api/trace-custom.md index cf1cb706341..f4fe7c98e25 100644 --- a/documentation/api/trace-custom.md +++ b/documentation/api/trace-custom.md @@ -126,3 +126,7 @@ See [Process ID `pid` vs Unique ID `uid`](pidvsuid.md) for clarification on when On Windows, `.nettrace` files can be viewed in [PerfView](https://github.com/microsoft/perfview) for analysis or in Visual Studio. A `.nettrace` files can be converted to another format (e.g. SpeedScope or Chromium) using the [dotnet-trace](https://docs.microsoft.com/dotnet/core/diagnostics/dotnet-trace) tool. + +### Indefinite traces are inaccessible + +When setting `durationSeconds` to `-1` (indefinite duration), there is currently no way to terminate the trace operation that preserves the `.nettrace` file in an accessible format. This also applies when prematurely terminating a trace operation that uses a finite value for `durationSeconds`. diff --git a/documentation/api/trace-get.md b/documentation/api/trace-get.md index 14cc0d73c49..3af999c4eae 100644 --- a/documentation/api/trace-get.md +++ b/documentation/api/trace-get.md @@ -96,3 +96,7 @@ See [Process ID `pid` vs Unique ID `uid`](pidvsuid.md) for clarification on when On Windows, `.nettrace` files can be viewed in [PerfView](https://github.com/microsoft/perfview) for analysis or in Visual Studio. A `.nettrace` files can be converted to another format (e.g. SpeedScope or Chromium) using the [dotnet-trace](https://docs.microsoft.com/dotnet/core/diagnostics/dotnet-trace) tool. + +### Indefinite traces are inaccessible + +When setting `durationSeconds` to `-1` (indefinite duration), there is currently no way to terminate the trace operation that preserves the `.nettrace` file in an accessible format. This also applies when prematurely terminating a trace operation that uses a finite value for `durationSeconds`. From f29d43f4dbfd9fbea3acc4f548230d6fa72bec06 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 13 Jul 2021 12:41:47 +0000 Subject: [PATCH 158/185] Update dependencies from https://github.com/dotnet/diagnostics build 20210712.1 (#558) [main] Update dependencies from dotnet/diagnostics --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index c2820472a33..929bbd2cfb6 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics - 06456894925c35a82f5be6d078a5a2bcd055806b + a01d3e90f4ccbc1157d6e1d7ea3b940f3c1b31ce - + https://github.com/dotnet/diagnostics - 06456894925c35a82f5be6d078a5a2bcd055806b + a01d3e90f4ccbc1157d6e1d7ea3b940f3c1b31ce diff --git a/eng/Versions.props b/eng/Versions.props index 8134a48c363..dfb034dd52d 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-preview.7.21360.2 - 5.0.0-preview.21359.1 - 5.0.0-preview.21359.1 + 5.0.0-preview.21362.1 + 5.0.0-preview.21362.1 6.0.0-preview.7.21361.10 From adf24aeecac4ffa406f05c5c63d194be7ed9094c Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 13 Jul 2021 12:42:08 +0000 Subject: [PATCH 159/185] Update dependencies from https://github.com/dotnet/arcade build 20210709.3 (#559) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- eng/common/tools.ps1 | 4 ++-- eng/common/tools.sh | 4 ++-- global.json | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 929bbd2cfb6..87b5dba2691 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -14,13 +14,13 @@ - + https://github.com/dotnet/arcade - 286d98094b830b8dad769542b2669cb1b75f7097 + 55262f114b0c1b82f0b081bca0d919b657ba24c5 - + https://github.com/dotnet/arcade - 286d98094b830b8dad769542b2669cb1b75f7097 + 55262f114b0c1b82f0b081bca0d919b657ba24c5 https://github.com/dotnet/symstore diff --git a/eng/Versions.props b/eng/Versions.props index dfb034dd52d..a6f82cf37e1 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -27,7 +27,7 @@ --> - 6.0.0-beta.21357.3 + 6.0.0-beta.21359.3 6.0.0-preview.7.21360.2 diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1 index 4b255203249..2df0909937d 100644 --- a/eng/common/tools.ps1 +++ b/eng/common/tools.ps1 @@ -42,7 +42,7 @@ [bool]$useInstalledDotNetCli = if (Test-Path variable:useInstalledDotNetCli) { $useInstalledDotNetCli } else { $true } # Enable repos to use a particular version of the on-line dotnet-install scripts. -# default URL: https://dot.net/v1/dotnet-install.ps1 +# default URL: https://dotnet.microsoft.com/download/dotnet/scripts/v1/dotnet-install.ps1 [string]$dotnetInstallScriptVersion = if (Test-Path variable:dotnetInstallScriptVersion) { $dotnetInstallScriptVersion } else { 'v1' } # True to use global NuGet cache instead of restoring packages to repository-local directory. @@ -223,7 +223,7 @@ function GetDotNetInstallScript([string] $dotnetRoot) { if (!(Test-Path $installScript)) { Create-Directory $dotnetRoot $ProgressPreference = 'SilentlyContinue' # Don't display the console progress UI - it's a huge perf hit - $uri = "https://dot.net/$dotnetInstallScriptVersion/dotnet-install.ps1" + $uri = "https://dotnet.microsoft.com/download/dotnet/scripts/$dotnetInstallScriptVersion/dotnet-install.ps1" Retry({ Write-Host "GET $uri" diff --git a/eng/common/tools.sh b/eng/common/tools.sh index 05ca99c6b28..828119be411 100644 --- a/eng/common/tools.sh +++ b/eng/common/tools.sh @@ -54,7 +54,7 @@ warn_as_error=${warn_as_error:-true} use_installed_dotnet_cli=${use_installed_dotnet_cli:-true} # Enable repos to use a particular version of the on-line dotnet-install scripts. -# default URL: https://dot.net/v1/dotnet-install.sh +# default URL: https://dotnet.microsoft.com/download/dotnet/scripts/v1/dotnet-install.sh dotnetInstallScriptVersion=${dotnetInstallScriptVersion:-'v1'} # True to use global NuGet cache instead of restoring packages to repository-local directory. @@ -262,7 +262,7 @@ function with_retries { function GetDotNetInstallScript { local root=$1 local install_script="$root/dotnet-install.sh" - local install_script_url="https://dot.net/$dotnetInstallScriptVersion/dotnet-install.sh" + local install_script_url="https://dotnet.microsoft.com/download/dotnet/scripts/$dotnetInstallScriptVersion/dotnet-install.sh" if [[ ! -a "$install_script" ]]; then mkdir -p "$root" diff --git a/global.json b/global.json index 99caa06cd98..e5a99e958b3 100644 --- a/global.json +++ b/global.json @@ -16,6 +16,6 @@ }, "msbuild-sdks": { "Microsoft.Build.NoTargets": "2.0.1", - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21357.3" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21359.3" } } From 57a82b1583250b4b1bd4d72f83c169f333effb6f Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 13 Jul 2021 13:00:26 +0000 Subject: [PATCH 160/185] Update dependencies from https://github.com/dotnet/runtime build 20210713.1 (#560) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 87b5dba2691..2e5b0c24b57 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 223d6e527cc98ce13fe45e4e14911013dd5ad807 - + https://github.com/dotnet/runtime - 98b7ed1a3b0543a31b5a0f9069cf44cb70c9230c + b72548e53115d1913f218a1275944fc2d01eaf18 diff --git a/eng/Versions.props b/eng/Versions.props index a6f82cf37e1..eeb4de33d98 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21362.1 5.0.0-preview.21362.1 - 6.0.0-preview.7.21361.10 + 6.0.0-preview.7.21363.1 1.0.215101 From 400718bd35327dc6ecae4e57e264fcb0a93664a9 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 13 Jul 2021 13:00:34 +0000 Subject: [PATCH 161/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210713.1 (#561) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 2e5b0c24b57..65162015aff 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - 223d6e527cc98ce13fe45e4e14911013dd5ad807 + 5753bafdec5206846edafab8494dc4a0c23992e9 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index eeb4de33d98..e6440aa2119 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21359.3 - 6.0.0-preview.7.21360.2 + 6.0.0-preview.7.21363.1 5.0.0-preview.21362.1 5.0.0-preview.21362.1 From de73361ef7c1467c4d77eed576a8c6e59e3f3a1b Mon Sep 17 00:00:00 2001 From: Sourabh Shirhatti Date: Tue, 13 Jul 2021 16:06:16 -0700 Subject: [PATCH 162/185] etc -> /etc (#562) --- documentation/configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/configuration.md b/documentation/configuration.md index 6e829e90d3c..01e352a5b06 100644 --- a/documentation/configuration.md +++ b/documentation/configuration.md @@ -13,7 +13,7 @@ - If `$XDG_CONFIG_HOME` isn't defined, we fall back to ` $HOME/.config/dotnet-monitor/settings.json` - [Key-per-file](https://docs.microsoft.com/aspnet/core/fundamentals/configuration/#key-per-file-configuration-provider) in the shared settings path - On Windows, `%ProgramData%\dotnet-monitor` - - On \*nix, `etc/dotnet-monitor` + - On \*nix, `/etc/dotnet-monitor` - Environment variables From 225a70c8d6195c641481fa3bf56cf02ac9b283ae Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 14 Jul 2021 12:42:58 +0000 Subject: [PATCH 163/185] Update dependencies from https://github.com/dotnet/diagnostics build 20210713.1 (#563) [main] Update dependencies from dotnet/diagnostics --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 65162015aff..67e216f57fe 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics - a01d3e90f4ccbc1157d6e1d7ea3b940f3c1b31ce + 4d3906d24d2aed094e0366f85481167fd883561a - + https://github.com/dotnet/diagnostics - a01d3e90f4ccbc1157d6e1d7ea3b940f3c1b31ce + 4d3906d24d2aed094e0366f85481167fd883561a diff --git a/eng/Versions.props b/eng/Versions.props index e6440aa2119..9b6fa3c5fbd 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-preview.7.21363.1 - 5.0.0-preview.21362.1 - 5.0.0-preview.21362.1 + 5.0.0-preview.21363.1 + 5.0.0-preview.21363.1 6.0.0-preview.7.21363.1 From c87ed04f922f0e155fbc23edc4124822a2167207 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 14 Jul 2021 12:43:17 +0000 Subject: [PATCH 164/185] Update dependencies from https://github.com/dotnet/arcade build 20210713.2 (#564) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- eng/common/cross/build-rootfs.sh | 6 +++++- global.json | 2 +- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 67e216f57fe..a17965b9906 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -14,13 +14,13 @@ - + https://github.com/dotnet/arcade - 55262f114b0c1b82f0b081bca0d919b657ba24c5 + 1b053babb8a542e3ab20f93b3d0aedc732b7e0c7 - + https://github.com/dotnet/arcade - 55262f114b0c1b82f0b081bca0d919b657ba24c5 + 1b053babb8a542e3ab20f93b3d0aedc732b7e0c7 https://github.com/dotnet/symstore diff --git a/eng/Versions.props b/eng/Versions.props index 9b6fa3c5fbd..20861309e29 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -27,7 +27,7 @@ --> - 6.0.0-beta.21359.3 + 6.0.0-beta.21363.2 6.0.0-preview.7.21363.1 diff --git a/eng/common/cross/build-rootfs.sh b/eng/common/cross/build-rootfs.sh index 591d8666a84..735a4c82838 100644 --- a/eng/common/cross/build-rootfs.sh +++ b/eng/common/cross/build-rootfs.sh @@ -33,7 +33,6 @@ __AlpinePackages="alpine-base" __AlpinePackages+=" build-base" __AlpinePackages+=" linux-headers" __AlpinePackagesEdgeCommunity=" lldb-dev" -__AlpinePackagesEdgeMain=" llvm10-libs" __AlpinePackagesEdgeMain+=" python3" __AlpinePackagesEdgeMain+=" libedit" @@ -115,6 +114,8 @@ while :; do __UbuntuArch=s390x __UbuntuRepo="http://ports.ubuntu.com/ubuntu-ports/" __UbuntuPackages=$(echo ${__UbuntuPackages} | sed 's/ libunwind8-dev//') + __UbuntuPackages=$(echo ${__UbuntuPackages} | sed 's/ libomp-dev//') + __UbuntuPackages=$(echo ${__UbuntuPackages} | sed 's/ libomp5//') unset __LLDB_Package ;; x86) @@ -191,6 +192,8 @@ while :; do __CodeName=alpine __UbuntuRepo= __AlpineVersion=3.9 + __AlpinePackagesEdgeMain+=" llvm11-libs" + __AlpinePackagesEdgeMain+=" clang-libs" ;; alpine3.13) __CodeName=alpine @@ -201,6 +204,7 @@ while :; do __AlpinePackagesEdgeCommunity= __AlpinePackages+=$__AlpinePackagesEdgeMain __AlpinePackagesEdgeMain= + __AlpinePackages+=" llvm10-libs" ;; freebsd11) __FreeBSDBase="11.3-RELEASE" diff --git a/global.json b/global.json index e5a99e958b3..efde5cc8a08 100644 --- a/global.json +++ b/global.json @@ -16,6 +16,6 @@ }, "msbuild-sdks": { "Microsoft.Build.NoTargets": "2.0.1", - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21359.3" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21363.2" } } From 88faacf41f12877a6b45956c366a4336abc33adb Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 14 Jul 2021 12:56:55 +0000 Subject: [PATCH 165/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210713.17 (#566) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index a17965b9906..47657e53c56 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - 5753bafdec5206846edafab8494dc4a0c23992e9 + 837b17847c427be12d69623cf32223c10a4ddba5 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 20861309e29..7e28213ef1b 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21363.2 - 6.0.0-preview.7.21363.1 + 6.0.0-preview.7.21363.17 5.0.0-preview.21363.1 5.0.0-preview.21363.1 From f2be1ca27cd8c117eb8c348382d5276c764a9995 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Wed, 14 Jul 2021 13:01:55 +0000 Subject: [PATCH 166/185] Update dependencies from https://github.com/dotnet/runtime build 20210713.9 (#565) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 47657e53c56..6798c13d4fb 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 837b17847c427be12d69623cf32223c10a4ddba5 - + https://github.com/dotnet/runtime - b72548e53115d1913f218a1275944fc2d01eaf18 + 3150bfa50618cc98f546ffae7652b12c17cea702 diff --git a/eng/Versions.props b/eng/Versions.props index 7e28213ef1b..7e13112c6ce 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21363.1 5.0.0-preview.21363.1 - 6.0.0-preview.7.21363.1 + 6.0.0-preview.7.21363.9 1.0.215101 From e012be4a8791dfdae9a0c86cf81a6a0cb82c0acf Mon Sep 17 00:00:00 2001 From: kkeirstead <85592574+kkeirstead@users.noreply.github.com> Date: Wed, 14 Jul 2021 10:07:02 -0700 Subject: [PATCH 167/185] Documentation Fixes (Switching Paths To Queries) (#567) --- documentation/api/defaultprocess.md | 4 ++-- documentation/api/dump.md | 6 +++--- documentation/api/gcdump.md | 6 +++--- documentation/api/logs-custom.md | 6 +++--- documentation/api/logs-get.md | 6 +++--- documentation/api/process-env.md | 8 ++++---- documentation/api/process-get.md | 8 ++++---- documentation/api/trace-custom.md | 6 +++--- documentation/api/trace-get.md | 6 +++--- documentation/authentication.md | 6 +++--- documentation/egress.md | 4 ++-- 11 files changed, 33 insertions(+), 33 deletions(-) diff --git a/documentation/api/defaultprocess.md b/documentation/api/defaultprocess.md index 6c424dd067a..cc68869b815 100644 --- a/documentation/api/defaultprocess.md +++ b/documentation/api/defaultprocess.md @@ -1,5 +1,5 @@ # Default Process -When using APIs to capture diagnostic artifacts, typically a `pid`, `uid`, or `name` is provided to perform the operation on a specific process. However, these parameters may be omitted if dotnet-monitor is able to resolve a default process. +When using APIs to capture diagnostic artifacts, typically a `pid`, `uid`, or `name` is provided to perform the operation on a specific process. However, these parameters may be omitted if `dotnet monitor` is able to resolve a default process. -The tool is able to resolve a default process if there is one and only one observable process. If there are no processes or there are more that one process, any API that allows operating on the default process will fail when invoked. \ No newline at end of file +The tool is able to resolve a default process if there is one and only one observable process. If there are no processes or there are more that one process, any API that allows operating on the default process will fail when invoked. diff --git a/documentation/api/dump.md b/documentation/api/dump.md index 836cfb554f6..79cc49381f6 100644 --- a/documentation/api/dump.md +++ b/documentation/api/dump.md @@ -20,9 +20,9 @@ The default host address for these routes is `https://localhost:52323`. This rou | Name | In | Required | Type | Description | |---|---|---|---|---| -| `pid` | path | false | int | The ID of the process. | -| `uid` | path | false | guid | A value that uniquely identifies a runtime instance within a process. | -| `name` | path | false | string | The name of the process. | +| `pid` | query | false | int | The ID of the process. | +| `uid` | query | false | guid | A value that uniquely identifies a runtime instance within a process. | +| `name` | query | false | string | The name of the process. | | `type` | query | false | [DumpType](definitions.md#DumpType) | The type of dump to capture. Default value is `WithHeap` | | `egressProvider` | query | false | string | If specified, uses the named egress provider for egressing the collected dump. When not specified, the dump is written to the HTTP response stream. See [Egress Providers](../egress.md) for more details. | diff --git a/documentation/api/gcdump.md b/documentation/api/gcdump.md index db66747a4f7..df983e33ebb 100644 --- a/documentation/api/gcdump.md +++ b/documentation/api/gcdump.md @@ -24,9 +24,9 @@ The default host address for these routes is `https://localhost:52323`. This rou | Name | In | Required | Type | Description | |---|---|---|---|---| -| `pid` | path | false | int | The ID of the process. | -| `uid` | path | false | guid | A value that uniquely identifies a runtime instance within a process. | -| `name` | path | false | string | The name of the process. | +| `pid` | query | false | int | The ID of the process. | +| `uid` | query | false | guid | A value that uniquely identifies a runtime instance within a process. | +| `name` | query | false | string | The name of the process. | | `egressProvider` | query | false | string | If specified, uses the named egress provider for egressing the collected GC dump. When not specified, the GC dump is written to the HTTP response stream. See [Egress Providers](../egress.md) for more details. | See [ProcessIdentifier](definitions.md#ProcessIdentifier) for more details about the `pid`, `uid`, and `name` parameters. diff --git a/documentation/api/logs-custom.md b/documentation/api/logs-custom.md index 3e220843585..d8d21efc716 100644 --- a/documentation/api/logs-custom.md +++ b/documentation/api/logs-custom.md @@ -20,9 +20,9 @@ The default host address for these routes is `https://localhost:52323`. This rou | Name | In | Required | Type | Description | |---|---|---|---|---| -| `pid` | path | false | int | The ID of the process. | -| `uid` | path | false | guid | A value that uniquely identifies a runtime instance within a process. | -| `name` | path | false | string | The name of the process. | +| `pid` | query | false | int | The ID of the process. | +| `uid` | query | false | guid | A value that uniquely identifies a runtime instance within a process. | +| `name` | query | false | string | The name of the process. | | `durationSeconds` | query | false | int | The duration of the log collection operation in seconds. Default is `30`. Min is `-1` (indefinite duration). Max is `2147483647`. | | `egressProvider` | query | false | string | If specified, uses the named egress provider for egressing the collected logs. When not specified, the logs are written to the HTTP response stream. See [Egress Providers](../egress.md) for more details. | diff --git a/documentation/api/logs-get.md b/documentation/api/logs-get.md index d442a26f714..00b3c8a17dc 100644 --- a/documentation/api/logs-get.md +++ b/documentation/api/logs-get.md @@ -20,9 +20,9 @@ The default host address for these routes is `https://localhost:52323`. This rou | Name | In | Required | Type | Description | |---|---|---|---|---| -| `pid` | path | false | int | The ID of the process. | -| `uid` | path | false | guid | A value that uniquely identifies a runtime instance within a process. | -| `name` | path | false | string | The name of the process. | +| `pid` | query | false | int | The ID of the process. | +| `uid` | query | false | guid | A value that uniquely identifies a runtime instance within a process. | +| `name` | query | false | string | The name of the process. | | `level` | query | false | [LogLevel](definitions.md#LogLevel) | The name of the log level at which log events are collected. If not specified, logs are collected levels as specified by the [application-defined configuration](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/#configure-logging). | | `durationSeconds` | query | false | int | The duration of the log collection operation in seconds. Default is `30`. Min is `-1` (indefinite duration). Max is `2147483647`. | | `egressProvider` | query | false | string | If specified, uses the named egress provider for egressing the collected logs. When not specified, the logs are written to the HTTP response stream. See [Egress Providers](../egress.md) for more details. | diff --git a/documentation/api/process-env.md b/documentation/api/process-env.md index bfc3ba33690..6d3bafee558 100644 --- a/documentation/api/process-env.md +++ b/documentation/api/process-env.md @@ -18,13 +18,13 @@ The default host address for these routes is `https://localhost:52323`. This rou | Name | In | Required | Type | Description | |---|---|---|---|---| -| `pid` | path | true | int | The ID of the process. | -| `uid` | path | true | guid | A value that uniquely identifies a runtime instance within a process. | -| `name` | path | true | string | The name of the process. | +| `pid` | query | false | int | The ID of the process. | +| `uid` | query | false | guid | A value that uniquely identifies a runtime instance within a process. | +| `name` | query | false | string | The name of the process. | See [ProcessIdentifier](definitions.md#ProcessIdentifier) for more details about the `pid`, `uid`, and `name` parameters. -One of `pid`, `uid`, or `name` are required, but not all. +If none of `pid`, `uid`, or `name` are specified, the environment block of the [default process](defaultprocess.md) will be provided. Attempting to get the environment block of the default process when the default process cannot be resolved will fail. ## Authentication diff --git a/documentation/api/process-get.md b/documentation/api/process-get.md index 8db8809c8b9..b0c5640c62c 100644 --- a/documentation/api/process-get.md +++ b/documentation/api/process-get.md @@ -18,13 +18,13 @@ The default host address for these routes is `https://localhost:52323`. This rou | Name | In | Required | Type | Description | |---|---|---|---|---| -| `pid` | path | true | int | The ID of the process. | -| `uid` | path | true | guid | A value that uniquely identifies a runtime instance within a process. | -| `name` | path | true | string | The name of the process. | +| `pid` | query | false | int | The ID of the process. | +| `uid` | query | false | guid | A value that uniquely identifies a runtime instance within a process. | +| `name` | query | false | string | The name of the process. | See [ProcessIdentifier](definitions.md#ProcessIdentifier) for more details about the `pid`, `uid`, and `name` parameters. -One of `pid`, `uid`, or `name` are required, but not all. +If none of `pid`, `uid`, or `name` are specified, information about the [default process](defaultprocess.md) will be provided. Attempting to get information from the default process when the default process cannot be resolved will fail. ## Authentication diff --git a/documentation/api/trace-custom.md b/documentation/api/trace-custom.md index f4fe7c98e25..ac77821d1c5 100644 --- a/documentation/api/trace-custom.md +++ b/documentation/api/trace-custom.md @@ -18,9 +18,9 @@ The default host address for these routes is `https://localhost:52323`. This rou | Name | In | Required | Type | Description | |---|---|---|---|---| -| `pid` | path | false | int | The ID of the process. | -| `uid` | path | false | guid | A value that uniquely identifies a runtime instance within a process. | -| `name` | path | false | string | The name of the process. | +| `pid` | query | false | int | The ID of the process. | +| `uid` | query | false | guid | A value that uniquely identifies a runtime instance within a process. | +| `name` | query | false | string | The name of the process. | | `durationSeconds` | query | false | int | The duration of the trace operation in seconds. Default is `30`. Min is `-1` (indefinite duration). Max is `2147483647`. | | `egressProvider` | query | false | string | If specified, uses the named egress provider for egressing the collected trace. When not specified, the trace is written to the HTTP response stream. See [Egress Providers](../egress.md) for more details. | diff --git a/documentation/api/trace-get.md b/documentation/api/trace-get.md index 3af999c4eae..71734eecb29 100644 --- a/documentation/api/trace-get.md +++ b/documentation/api/trace-get.md @@ -18,9 +18,9 @@ The default host address for these routes is `https://localhost:52323`. This rou | Name | In | Required | Type | Description | |---|---|---|---|---| -| `pid` | path | false | int | The ID of the process. | -| `uid` | path | false | guid | A value that uniquely identifies a runtime instance within a process. | -| `name` | path | false | string | The name of the process. | +| `pid` | query | false | int | The ID of the process. | +| `uid` | query | false | guid | A value that uniquely identifies a runtime instance within a process. | +| `name` | query | false | string | The name of the process. | | `profile` | query | false | [TraceProfile](definitions.md#TraceProfile) | The name of the profile(s) used to collect events. See [TraceProfile](definitions.md#TraceProfile) for details on the list of event providers, levels, and keywords each profile represents. Multiple profiles may be specified by separating them with commas. Default is `Cpu,Http,Metrics` | | `durationSeconds` | query | false | int | The duration of the trace operation in seconds. Default is `30`. Min is `-1` (indefinite duration). Max is `2147483647`. | | `metricsIntervalSeconds` | query | false | int | The interval (in seconds) at which metrics are collected. Only applicable for the `Metrics` profile. Default is `1`. Min is `1`. Max is `2147483647`. | diff --git a/documentation/authentication.md b/documentation/authentication.md index edfa582f7cd..a030d4ba821 100644 --- a/documentation/authentication.md +++ b/documentation/authentication.md @@ -9,7 +9,7 @@ The recommended configuration for `dotnet monitor` is to use [API Key Authentica ## Windows Authentication We only recommend using Windows Authentication if you're running `dotnet monitor` as a local development tool on Windows; for all other environments using an [API Key](#api-key-authentication) is recommended. -Windows authentication doesn't require explicit configuration and is enabled automatically when running `dotnet monitor` on Windows. When available, dotnet-monitor will authorize any user authenticated as the same user that started the `dotnet monitor` process. It is not possible to disable Windows authentication. +Windows authentication doesn't require explicit configuration and is enabled automatically when running `dotnet monitor` on Windows. When available, `dotnet monitor` will authorize any user authenticated as the same user that started the `dotnet monitor` process. It is not possible to disable Windows authentication. > **NOTE:** Windows authentication will not be attempted if you are running `dotnet monitor` as an Administrator @@ -23,7 +23,7 @@ An API Key is the recommended authentication mechanism for `dotnet monitor`. To The API Key you use to secure `dotnet monitor` should be a 32-byte cryptographically random secret. You can generate a key either using `dotnet monitor` or via your shell. To generate an API Key with `dotnet monitor`, simply invoke the `generatekey` command: ```powershell -dotnet-monitor generatekey +dotnet monitor generatekey ``` The output from this command will display the API Key formatted as an authentication header along with its hash and associated hashing algorithm. You will need to store the `ApiKeyHash` and `ApiKeyHashType` in the configuration for `dotnet monitor` and use the authorization header value when making requests to the `dotnet monitor` HTTPS endpoint. @@ -147,5 +147,5 @@ Disabling authentication could enable lower privileged processes to exfiltrate s Authentication can be turned off by specifying the `--no-auth` option to `dotnet monitor` at startup: ```powershell -dotnet-monitor collect --no-auth +dotnet monitor collect --no-auth ``` diff --git a/documentation/egress.md b/documentation/egress.md index 1ef56c61b77..84514bdb6fd 100644 --- a/documentation/egress.md +++ b/documentation/egress.md @@ -1,8 +1,8 @@ # Egress Providers -Dotnet-monitor supports configuration of [egress providers](./configuration.md#egress-configuration) that can be used to egress artifacts externally, instead of to the client. This is supported for dumps, gcdumps, traces, and logs. Currently supported providers are Azure blob storage and filesystem. +`dotnet monitor` supports configuration of [egress providers](./configuration.md#egress-configuration) that can be used to egress artifacts externally, instead of to the client. This is supported for dumps, gcdumps, traces, and logs. Currently supported providers are Azure blob storage and filesystem. -Egress providers must first be named and configured in dotnet-monitor configuration. They can then be referenced from a request, and will cause an egress based on the provider configuration, rather than directly back to the client. +Egress providers must first be named and configured in `dotnet monitor` configuration. They can then be referenced from a request, and will cause an egress based on the provider configuration, rather than directly back to the client. > **NOTE:** The filesystem provider can be used to egress to [kubernetes volumes](https://kubernetes.io/docs/concepts/storage/volumes/). From 9437a93dfd5f02423af2bd0ed2908d1d46a1f6fc Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 15 Jul 2021 14:32:04 +0000 Subject: [PATCH 168/185] Update dependencies from https://github.com/dotnet/runtime build 20210715.2 (#572) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 6798c13d4fb..63754997d0d 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 837b17847c427be12d69623cf32223c10a4ddba5 - + https://github.com/dotnet/runtime - 3150bfa50618cc98f546ffae7652b12c17cea702 + 90b8ddd7a6b28e57aebed7d478547ce07b9b60a6 diff --git a/eng/Versions.props b/eng/Versions.props index 7e13112c6ce..021d4cdde01 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21363.1 5.0.0-preview.21363.1 - 6.0.0-preview.7.21363.9 + 6.0.0-preview.7.21365.2 1.0.215101 From 2458ff4717192d76ea46ac0008b1602d3365445d Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 15 Jul 2021 14:32:11 +0000 Subject: [PATCH 169/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210714.17 (#573) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 63754997d0d..c4fdb49f4d2 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - 837b17847c427be12d69623cf32223c10a4ddba5 + eccb20d7778f4ef4496d1e2797324c52e755a25c https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 021d4cdde01..ba0262321b4 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21363.2 - 6.0.0-preview.7.21363.17 + 6.0.0-preview.7.21364.17 5.0.0-preview.21363.1 5.0.0-preview.21363.1 From 16bb997713097e6cb268304354ec7a1350007186 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 15 Jul 2021 15:54:45 +0000 Subject: [PATCH 170/185] Update dependencies from https://github.com/dotnet/diagnostics build 20210714.1 (#570) [main] Update dependencies from dotnet/diagnostics --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index c4fdb49f4d2..b724e943067 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics - 4d3906d24d2aed094e0366f85481167fd883561a + 419db65453d353c654192b42fa5aa63785b02abc - + https://github.com/dotnet/diagnostics - 4d3906d24d2aed094e0366f85481167fd883561a + 419db65453d353c654192b42fa5aa63785b02abc diff --git a/eng/Versions.props b/eng/Versions.props index ba0262321b4..5a999b173bc 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-preview.7.21364.17 - 5.0.0-preview.21363.1 - 5.0.0-preview.21363.1 + 5.0.0-preview.21364.1 + 5.0.0-preview.21364.1 6.0.0-preview.7.21365.2 From a583362f43a52e1cfc57a6448a9dab63f6fc2259 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Thu, 15 Jul 2021 15:55:00 +0000 Subject: [PATCH 171/185] Update dependencies from https://github.com/dotnet/arcade build 20210714.3 (#571) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 8 +- eng/Versions.props | 2 +- eng/common/sdl/configure-sdl-tool.ps1 | 109 +++++++++++++++++++ eng/common/sdl/execute-all-sdl-tools.ps1 | 71 ++++++++++-- eng/common/sdl/extract-artifact-archives.ps1 | 63 +++++++++++ eng/common/sdl/run-sdl.ps1 | 50 +++------ eng/common/templates/job/execute-sdl.yml | 108 ++++++++++++++++-- eng/common/tools.ps1 | 51 +++++++++ global.json | 2 +- 9 files changed, 401 insertions(+), 63 deletions(-) create mode 100644 eng/common/sdl/configure-sdl-tool.ps1 create mode 100644 eng/common/sdl/extract-artifact-archives.ps1 diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index b724e943067..a39a9797615 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -14,13 +14,13 @@ - + https://github.com/dotnet/arcade - 1b053babb8a542e3ab20f93b3d0aedc732b7e0c7 + 6a8491b61e0c243cbb6a7ff4966b48e6d1e075b1 - + https://github.com/dotnet/arcade - 1b053babb8a542e3ab20f93b3d0aedc732b7e0c7 + 6a8491b61e0c243cbb6a7ff4966b48e6d1e075b1 https://github.com/dotnet/symstore diff --git a/eng/Versions.props b/eng/Versions.props index 5a999b173bc..95fa611ff13 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -27,7 +27,7 @@ --> - 6.0.0-beta.21363.2 + 6.0.0-beta.21364.3 6.0.0-preview.7.21364.17 diff --git a/eng/common/sdl/configure-sdl-tool.ps1 b/eng/common/sdl/configure-sdl-tool.ps1 new file mode 100644 index 00000000000..4999c307088 --- /dev/null +++ b/eng/common/sdl/configure-sdl-tool.ps1 @@ -0,0 +1,109 @@ +Param( + [string] $GuardianCliLocation, + [string] $WorkingDirectory, + [string] $TargetDirectory, + [string] $GdnFolder, + # The list of Guardian tools to configure. For each object in the array: + # - If the item is a [hashtable], it must contain these entries: + # - Name = The tool name as Guardian knows it. + # - Scenario = (Optional) Scenario-specific name for this configuration entry. It must be unique + # among all tool entries with the same Name. + # - Args = (Optional) Array of Guardian tool configuration args, like '@("Target > C:\temp")' + # - If the item is a [string] $v, it is treated as '@{ Name="$v" }' + [object[]] $ToolsList, + [string] $GuardianLoggerLevel='Standard', + # Optional: Additional params to add to any tool using CredScan. + [string[]] $CrScanAdditionalRunConfigParams, + # Optional: Additional params to add to any tool using PoliCheck. + [string[]] $PoliCheckAdditionalRunConfigParams +) + +$ErrorActionPreference = 'Stop' +Set-StrictMode -Version 2.0 +$disableConfigureToolsetImport = $true +$global:LASTEXITCODE = 0 + +try { + # `tools.ps1` checks $ci to perform some actions. Since the SDL + # scripts don't necessarily execute in the same agent that run the + # build.ps1/sh script this variable isn't automatically set. + $ci = $true + . $PSScriptRoot\..\tools.ps1 + + # Normalize tools list: all in [hashtable] form with defined values for each key. + $ToolsList = $ToolsList | + ForEach-Object { + if ($_ -is [string]) { + $_ = @{ Name = $_ } + } + + if (-not ($_['Scenario'])) { $_.Scenario = "" } + if (-not ($_['Args'])) { $_.Args = @() } + $_ + } + + Write-Host "List of tools to configure:" + $ToolsList | ForEach-Object { $_ | Out-String | Write-Host } + + # We store config files in the r directory of .gdn + $gdnConfigPath = Join-Path $GdnFolder 'r' + $ValidPath = Test-Path $GuardianCliLocation + + if ($ValidPath -eq $False) + { + Write-PipelineTelemetryError -Force -Category 'Sdl' -Message "Invalid Guardian CLI Location." + ExitWithExitCode 1 + } + + foreach ($tool in $ToolsList) { + # Put together the name and scenario to make a unique key. + $toolConfigName = $tool.Name + if ($tool.Scenario) { + $toolConfigName += "_" + $tool.Scenario + } + + Write-Host "=== Configuring $toolConfigName..." + + $gdnConfigFile = Join-Path $gdnConfigPath "$toolConfigName-configure.gdnconfig" + + # For some tools, add default and automatic args. + if ($tool.Name -eq 'credscan') { + if ($targetDirectory) { + $tool.Args += "TargetDirectory < $TargetDirectory" + } + $tool.Args += "OutputType < pre" + $tool.Args += $CrScanAdditionalRunConfigParams + } elseif ($tool.Name -eq 'policheck') { + if ($targetDirectory) { + $tool.Args += "Target < $TargetDirectory" + } + $tool.Args += $PoliCheckAdditionalRunConfigParams + } + + # Create variable pointing to the args array directly so we can use splat syntax later. + $toolArgs = $tool.Args + + # Configure the tool. If args array is provided or the current tool has some default arguments + # defined, add "--args" and splat each element on the end. Arg format is "{Arg id} < {Value}", + # one per parameter. Doc page for "guardian configure": + # https://dev.azure.com/securitytools/SecurityIntegration/_wiki/wikis/Guardian/1395/configure + Exec-BlockVerbosely { + & $GuardianCliLocation configure ` + --working-directory $WorkingDirectory ` + --tool $tool.Name ` + --output-path $gdnConfigFile ` + --logger-level $GuardianLoggerLevel ` + --noninteractive ` + --force ` + $(if ($toolArgs) { "--args" }) @toolArgs + Exit-IfNZEC "Sdl" + } + + Write-Host "Created '$toolConfigName' configuration file: $gdnConfigFile" + } +} +catch { + Write-Host $_.ScriptStackTrace + Write-PipelineTelemetryError -Force -Category 'Sdl' -Message $_ + ExitWithExitCode 1 +} diff --git a/eng/common/sdl/execute-all-sdl-tools.ps1 b/eng/common/sdl/execute-all-sdl-tools.ps1 index 2881a56083c..1157151f486 100644 --- a/eng/common/sdl/execute-all-sdl-tools.ps1 +++ b/eng/common/sdl/execute-all-sdl-tools.ps1 @@ -7,8 +7,17 @@ Param( [string] $SourceDirectory=$env:BUILD_SOURCESDIRECTORY, # Required: the directory where source files are located [string] $ArtifactsDirectory = (Join-Path $env:BUILD_ARTIFACTSTAGINGDIRECTORY ('artifacts')), # Required: the directory where build artifacts are located [string] $AzureDevOpsAccessToken, # Required: access token for dnceng; should be provided via KeyVault - [string[]] $SourceToolsList, # Optional: list of SDL tools to run on source code - [string[]] $ArtifactToolsList, # Optional: list of SDL tools to run on built artifacts + + # Optional: list of SDL tools to run on source code. See 'configure-sdl-tool.ps1' for tools list + # format. + [object[]] $SourceToolsList, + # Optional: list of SDL tools to run on built artifacts. See 'configure-sdl-tool.ps1' for tools + # list format. + [object[]] $ArtifactToolsList, + # Optional: list of SDL tools to run without automatically specifying a target directory. See + # 'configure-sdl-tool.ps1' for tools list format. + [object[]] $CustomToolsList, + [bool] $TsaPublish=$False, # Optional: true will publish results to TSA; only set to true after onboarding to TSA; TSA is the automated framework used to upload test results as bugs. [string] $TsaBranchName=$env:BUILD_SOURCEBRANCH, # Optional: required for TSA publish; defaults to $(Build.SourceBranchName); TSA is the automated framework used to upload test results as bugs. [string] $TsaRepositoryName=$env:BUILD_REPOSITORY_NAME, # Optional: TSA repository name; will be generated automatically if not submitted; TSA is the automated framework used to upload test results as bugs. @@ -63,13 +72,16 @@ try { ExitWithExitCode 1 } - & $(Join-Path $PSScriptRoot 'init-sdl.ps1') -GuardianCliLocation $guardianCliLocation -Repository $RepoName -BranchName $BranchName -WorkingDirectory $workingDirectory -AzureDevOpsAccessToken $AzureDevOpsAccessToken -GuardianLoggerLevel $GuardianLoggerLevel + Exec-BlockVerbosely { + & $(Join-Path $PSScriptRoot 'init-sdl.ps1') -GuardianCliLocation $guardianCliLocation -Repository $RepoName -BranchName $BranchName -WorkingDirectory $workingDirectory -AzureDevOpsAccessToken $AzureDevOpsAccessToken -GuardianLoggerLevel $GuardianLoggerLevel + } $gdnFolder = Join-Path $workingDirectory '.gdn' if ($TsaOnboard) { if ($TsaCodebaseName -and $TsaNotificationEmail -and $TsaCodebaseAdmin -and $TsaBugAreaPath) { - Write-Host "$guardianCliLocation tsa-onboard --codebase-name `"$TsaCodebaseName`" --notification-alias `"$TsaNotificationEmail`" --codebase-admin `"$TsaCodebaseAdmin`" --instance-url `"$TsaInstanceUrl`" --project-name `"$TsaProjectName`" --area-path `"$TsaBugAreaPath`" --iteration-path `"$TsaIterationPath`" --working-directory $workingDirectory --logger-level $GuardianLoggerLevel" - & $guardianCliLocation tsa-onboard --codebase-name "$TsaCodebaseName" --notification-alias "$TsaNotificationEmail" --codebase-admin "$TsaCodebaseAdmin" --instance-url "$TsaInstanceUrl" --project-name "$TsaProjectName" --area-path "$TsaBugAreaPath" --iteration-path "$TsaIterationPath" --working-directory $workingDirectory --logger-level $GuardianLoggerLevel + Exec-BlockVerbosely { + & $guardianCliLocation tsa-onboard --codebase-name "$TsaCodebaseName" --notification-alias "$TsaNotificationEmail" --codebase-admin "$TsaCodebaseAdmin" --instance-url "$TsaInstanceUrl" --project-name "$TsaProjectName" --area-path "$TsaBugAreaPath" --iteration-path "$TsaIterationPath" --working-directory $workingDirectory --logger-level $GuardianLoggerLevel + } if ($LASTEXITCODE -ne 0) { Write-PipelineTelemetryError -Force -Category 'Sdl' -Message "Guardian tsa-onboard failed with exit code $LASTEXITCODE." ExitWithExitCode $LASTEXITCODE @@ -80,11 +92,41 @@ try { } } - if ($ArtifactToolsList -and $ArtifactToolsList.Count -gt 0) { - & $(Join-Path $PSScriptRoot 'run-sdl.ps1') -GuardianCliLocation $guardianCliLocation -WorkingDirectory $workingDirectory -TargetDirectory $ArtifactsDirectory -GdnFolder $gdnFolder -ToolsList $ArtifactToolsList -AzureDevOpsAccessToken $AzureDevOpsAccessToken -UpdateBaseline $UpdateBaseline -GuardianLoggerLevel $GuardianLoggerLevel -CrScanAdditionalRunConfigParams $CrScanAdditionalRunConfigParams -PoliCheckAdditionalRunConfigParams $PoliCheckAdditionalRunConfigParams + # Configure a list of tools with a default target directory. Populates the ".gdn/r" directory. + function Configure-ToolsList([object[]] $tools, [string] $targetDirectory) { + if ($tools -and $tools.Count -gt 0) { + Exec-BlockVerbosely { + & $(Join-Path $PSScriptRoot 'configure-sdl-tool.ps1') ` + -GuardianCliLocation $guardianCliLocation ` + -WorkingDirectory $workingDirectory ` + -TargetDirectory $targetDirectory ` + -GdnFolder $gdnFolder ` + -ToolsList $tools ` + -AzureDevOpsAccessToken $AzureDevOpsAccessToken ` + -GuardianLoggerLevel $GuardianLoggerLevel ` + -CrScanAdditionalRunConfigParams $CrScanAdditionalRunConfigParams ` + -PoliCheckAdditionalRunConfigParams $PoliCheckAdditionalRunConfigParams + if ($BreakOnFailure) { + Exit-IfNZEC "Sdl" + } + } + } } - if ($SourceToolsList -and $SourceToolsList.Count -gt 0) { - & $(Join-Path $PSScriptRoot 'run-sdl.ps1') -GuardianCliLocation $guardianCliLocation -WorkingDirectory $workingDirectory -TargetDirectory $SourceDirectory -GdnFolder $gdnFolder -ToolsList $SourceToolsList -AzureDevOpsAccessToken $AzureDevOpsAccessToken -UpdateBaseline $UpdateBaseline -GuardianLoggerLevel $GuardianLoggerLevel -CrScanAdditionalRunConfigParams $CrScanAdditionalRunConfigParams -PoliCheckAdditionalRunConfigParams $PoliCheckAdditionalRunConfigParams + + # Configure Artifact and Source tools with default Target directories. + Configure-ToolsList $ArtifactToolsList $ArtifactsDirectory + Configure-ToolsList $SourceToolsList $SourceDirectory + # Configure custom tools with no default Target directory. + Configure-ToolsList $CustomToolsList $null + + # At this point, all tools are configured in the ".gdn" directory. Run them all in a single call. + # (If we used "run" multiple times, each run would overwrite data from earlier runs.) + Exec-BlockVerbosely { + & $(Join-Path $PSScriptRoot 'run-sdl.ps1') ` + -GuardianCliLocation $guardianCliLocation ` + -WorkingDirectory $workingDirectory ` + -UpdateBaseline $UpdateBaseline ` + -GdnFolder $gdnFolder } if ($TsaPublish) { @@ -92,8 +134,9 @@ try { if (-not $TsaRepositoryName) { $TsaRepositoryName = "$($Repository)-$($BranchName)" } - Write-Host "$guardianCliLocation tsa-publish --all-tools --repository-name `"$TsaRepositoryName`" --branch-name `"$TsaBranchName`" --build-number `"$BuildNumber`" --codebase-name `"$TsaCodebaseName`" --notification-alias `"$TsaNotificationEmail`" --codebase-admin `"$TsaCodebaseAdmin`" --instance-url `"$TsaInstanceUrl`" --project-name `"$TsaProjectName`" --area-path `"$TsaBugAreaPath`" --iteration-path `"$TsaIterationPath`" --working-directory $workingDirectory --logger-level $GuardianLoggerLevel" - & $guardianCliLocation tsa-publish --all-tools --repository-name "$TsaRepositoryName" --branch-name "$TsaBranchName" --build-number "$BuildNumber" --onboard $True --codebase-name "$TsaCodebaseName" --notification-alias "$TsaNotificationEmail" --codebase-admin "$TsaCodebaseAdmin" --instance-url "$TsaInstanceUrl" --project-name "$TsaProjectName" --area-path "$TsaBugAreaPath" --iteration-path "$TsaIterationPath" --working-directory $workingDirectory --logger-level $GuardianLoggerLevel + Exec-BlockVerbosely { + & $guardianCliLocation tsa-publish --all-tools --repository-name "$TsaRepositoryName" --branch-name "$TsaBranchName" --build-number "$BuildNumber" --onboard $True --codebase-name "$TsaCodebaseName" --notification-alias "$TsaNotificationEmail" --codebase-admin "$TsaCodebaseAdmin" --instance-url "$TsaInstanceUrl" --project-name "$TsaProjectName" --area-path "$TsaBugAreaPath" --iteration-path "$TsaIterationPath" --working-directory $workingDirectory --logger-level $GuardianLoggerLevel + } if ($LASTEXITCODE -ne 0) { Write-PipelineTelemetryError -Force -Category 'Sdl' -Message "Guardian tsa-publish failed with exit code $LASTEXITCODE." ExitWithExitCode $LASTEXITCODE @@ -106,7 +149,11 @@ try { if ($BreakOnFailure) { Write-Host "Failing the build in case of breaking results..." - & $guardianCliLocation break + Exec-BlockVerbosely { + & $guardianCliLocation break --working-directory $workingDirectory --logger-level $GuardianLoggerLevel + } + } else { + Write-Host "Letting the build pass even if there were breaking results..." } } catch { diff --git a/eng/common/sdl/extract-artifact-archives.ps1 b/eng/common/sdl/extract-artifact-archives.ps1 new file mode 100644 index 00000000000..68da4fbf257 --- /dev/null +++ b/eng/common/sdl/extract-artifact-archives.ps1 @@ -0,0 +1,63 @@ +# This script looks for each archive file in a directory and extracts it into the target directory. +# For example, the file "$InputPath/bin.tar.gz" extracts to "$ExtractPath/bin.tar.gz.extracted/**". +# Uses the "tar" utility added to Windows 10 / Windows 2019 that supports tar.gz and zip. +param( + # Full path to directory where archives are stored. + [Parameter(Mandatory=$true)][string] $InputPath, + # Full path to directory to extract archives into. May be the same as $InputPath. + [Parameter(Mandatory=$true)][string] $ExtractPath +) + +$ErrorActionPreference = 'Stop' +Set-StrictMode -Version 2.0 + +$disableConfigureToolsetImport = $true + +try { + # `tools.ps1` checks $ci to perform some actions. Since the SDL + # scripts don't necessarily execute in the same agent that run the + # build.ps1/sh script this variable isn't automatically set. + $ci = $true + . $PSScriptRoot\..\tools.ps1 + + Measure-Command { + $jobs = @() + + # Find archive files for non-Windows and Windows builds. + $archiveFiles = @( + Get-ChildItem (Join-Path $InputPath "*.tar.gz") + Get-ChildItem (Join-Path $InputPath "*.zip") + ) + + foreach ($targzFile in $archiveFiles) { + $jobs += Start-Job -ScriptBlock { + $file = $using:targzFile + $fileName = [System.IO.Path]::GetFileName($file) + $extractDir = Join-Path $using:ExtractPath "$fileName.extracted" + + New-Item $extractDir -ItemType Directory -Force | Out-Null + + Write-Host "Extracting '$file' to '$extractDir'..." + + # Pipe errors to stdout to prevent PowerShell detecting them and quitting the job early. + # This type of quit skips the catch, so we wouldn't be able to tell which file triggered the + # error. Save output so it can be stored in the exception string along with context. + $output = tar -xf $file -C $extractDir 2>&1 + # Handle NZEC manually rather than using Exit-IfNZEC: we are in a background job, so we + # don't have access to the outer scope. + if ($LASTEXITCODE -ne 0) { + throw "Error extracting '$file': non-zero exit code ($LASTEXITCODE). Output: '$output'" + } + + Write-Host "Extracted to $extractDir" + } + } + + Receive-Job $jobs -Wait + } +} +catch { + Write-Host $_ + Write-PipelineTelemetryError -Force -Category 'Sdl' -Message $_ + ExitWithExitCode 1 +} diff --git a/eng/common/sdl/run-sdl.ps1 b/eng/common/sdl/run-sdl.ps1 index 3d9c87aba6a..2eac8c78f10 100644 --- a/eng/common/sdl/run-sdl.ps1 +++ b/eng/common/sdl/run-sdl.ps1 @@ -1,13 +1,9 @@ Param( [string] $GuardianCliLocation, [string] $WorkingDirectory, - [string] $TargetDirectory, [string] $GdnFolder, - [string[]] $ToolsList, [string] $UpdateBaseline, - [string] $GuardianLoggerLevel='Standard', - [string[]] $CrScanAdditionalRunConfigParams, - [string[]] $PoliCheckAdditionalRunConfigParams + [string] $GuardianLoggerLevel='Standard' ) $ErrorActionPreference = 'Stop' @@ -23,7 +19,6 @@ try { . $PSScriptRoot\..\tools.ps1 # We store config files in the r directory of .gdn - Write-Host $ToolsList $gdnConfigPath = Join-Path $GdnFolder 'r' $ValidPath = Test-Path $GuardianCliLocation @@ -33,37 +28,18 @@ try { ExitWithExitCode 1 } - $configParam = @('--config') - - foreach ($tool in $ToolsList) { - $gdnConfigFile = Join-Path $gdnConfigPath "$tool-configure.gdnconfig" - Write-Host $tool - # We have to manually configure tools that run on source to look at the source directory only - if ($tool -eq 'credscan') { - Write-Host "$GuardianCliLocation configure --working-directory $WorkingDirectory --tool $tool --output-path $gdnConfigFile --logger-level $GuardianLoggerLevel --noninteractive --force --args `" TargetDirectory < $TargetDirectory `" `" OutputType < pre `" $(If ($CrScanAdditionalRunConfigParams) {$CrScanAdditionalRunConfigParams})" - & $GuardianCliLocation configure --working-directory $WorkingDirectory --tool $tool --output-path $gdnConfigFile --logger-level $GuardianLoggerLevel --noninteractive --force --args " TargetDirectory < $TargetDirectory " "OutputType < pre" $(If ($CrScanAdditionalRunConfigParams) {$CrScanAdditionalRunConfigParams}) - if ($LASTEXITCODE -ne 0) { - Write-PipelineTelemetryError -Force -Category 'Sdl' -Message "Guardian configure for $tool failed with exit code $LASTEXITCODE." - ExitWithExitCode $LASTEXITCODE - } - } - if ($tool -eq 'policheck') { - Write-Host "$GuardianCliLocation configure --working-directory $WorkingDirectory --tool $tool --output-path $gdnConfigFile --logger-level $GuardianLoggerLevel --noninteractive --force --args `" Target < $TargetDirectory `" $(If ($PoliCheckAdditionalRunConfigParams) {$PoliCheckAdditionalRunConfigParams})" - & $GuardianCliLocation configure --working-directory $WorkingDirectory --tool $tool --output-path $gdnConfigFile --logger-level $GuardianLoggerLevel --noninteractive --force --args " Target < $TargetDirectory " $(If ($PoliCheckAdditionalRunConfigParams) {$PoliCheckAdditionalRunConfigParams}) - if ($LASTEXITCODE -ne 0) { - Write-PipelineTelemetryError -Force -Category 'Sdl' -Message "Guardian configure for $tool failed with exit code $LASTEXITCODE." - ExitWithExitCode $LASTEXITCODE - } - } - - $configParam+=$gdnConfigFile - } - - Write-Host "$GuardianCliLocation run --working-directory $WorkingDirectory --baseline mainbaseline --update-baseline $UpdateBaseline --logger-level $GuardianLoggerLevel $configParam" - & $GuardianCliLocation run --working-directory $WorkingDirectory --tool $tool --baseline mainbaseline --update-baseline $UpdateBaseline --logger-level $GuardianLoggerLevel $configParam - if ($LASTEXITCODE -ne 0) { - Write-PipelineTelemetryError -Force -Category 'Sdl' -Message "Guardian run for $ToolsList using $configParam failed with exit code $LASTEXITCODE." - ExitWithExitCode $LASTEXITCODE + $gdnConfigFiles = Get-ChildItem $gdnConfigPath -Recurse -Include '*.gdnconfig' + Write-Host "Discovered Guardian config files:" + $gdnConfigFiles | Out-String | Write-Host + + Exec-BlockVerbosely { + & $GuardianCliLocation run ` + --working-directory $WorkingDirectory ` + --baseline mainbaseline ` + --update-baseline $UpdateBaseline ` + --logger-level $GuardianLoggerLevel ` + --config @gdnConfigFiles + Exit-IfNZEC "Sdl" } } catch { diff --git a/eng/common/templates/job/execute-sdl.yml b/eng/common/templates/job/execute-sdl.yml index 4a32181fd8f..69eb67849d7 100644 --- a/eng/common/templates/job/execute-sdl.yml +++ b/eng/common/templates/job/execute-sdl.yml @@ -2,17 +2,41 @@ parameters: enable: 'false' # Whether the SDL validation job should execute or not overrideParameters: '' # Optional: to override values for parameters. additionalParameters: '' # Optional: parameters that need user specific values eg: '-SourceToolsList @("abc","def") -ArtifactToolsList @("ghi","jkl")' + # Optional: if specified, restore and use this version of Guardian instead of the default. + overrideGuardianVersion: '' + # Optional: if true, publish the '.gdn' folder as a pipeline artifact. This can help with in-depth + # diagnosis of problems with specific tool configurations. + publishGuardianDirectoryToPipeline: false + # The script to run to execute all SDL tools. Use this if you want to use a script to define SDL + # parameters rather than relying on YAML. It may be better to use a local script, because you can + # reproduce results locally without piecing together a command based on the YAML. + executeAllSdlToolsScript: 'eng/common/sdl/execute-all-sdl-tools.ps1' # There is some sort of bug (has been reported) in Azure DevOps where if this parameter is named # 'continueOnError', the parameter value is not correctly picked up. # This can also be remedied by the caller (post-build.yml) if it does not use a nested parameter sdlContinueOnError: false # optional: determines whether to continue the build if the step errors; - downloadArtifacts: true # optional: determines if the artifacts should be dowloaded + # optional: determines if build artifacts should be downloaded. + downloadArtifacts: true + # optional: determines if this job should search the directory of downloaded artifacts for + # 'tar.gz' and 'zip' archive files and extract them before running SDL validation tasks. + extractArchiveArtifacts: false dependsOn: '' # Optional: dependencies of the job artifactNames: '' # Optional: patterns supplied to DownloadBuildArtifacts # Usage: # artifactNames: # - 'BlobArtifacts' # - 'Artifacts_Windows_NT_Release' + # Optional: download a list of pipeline artifacts. 'downloadArtifacts' controls build artifacts, + # not pipeline artifacts, so doesn't affect the use of this parameter. + pipelineArtifactNames: [] + # Optional: location and ID of the AzDO build that the build/pipeline artifacts should be + # downloaded from. By default, uses runtime expressions to decide based on the variables set by + # the 'setupMaestroVars' dependency. Overriding this parameter is necessary if SDL tasks are + # running without Maestro++/BAR involved, or to download artifacts from a specific existing build + # to iterate quickly on SDL changes. + AzDOProjectName: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ] + AzDOPipelineId: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ] + AzDOBuildId: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ] jobs: - job: Run_SDL @@ -22,16 +46,29 @@ jobs: variables: - group: DotNet-VSTS-Bot - name: AzDOProjectName - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOProjectName'] ] + value: ${{ parameters.AzDOProjectName }} - name: AzDOPipelineId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOPipelineId'] ] + value: ${{ parameters.AzDOPipelineId }} - name: AzDOBuildId - value: $[ dependencies.setupMaestroVars.outputs['setReleaseVars.AzDOBuildId'] ] + value: ${{ parameters.AzDOBuildId }} + # The Guardian version specified in 'eng/common/sdl/packages.config'. This value must be kept in + # sync with the packages.config file. + - name: DefaultGuardianVersion + value: 0.53.3 + - name: GuardianVersion + value: ${{ coalesce(parameters.overrideGuardianVersion, '$(DefaultGuardianVersion)') }} + - name: GuardianPackagesConfigFile + value: $(Build.SourcesDirectory)\eng\common\sdl\packages.config pool: - name: Hosted VS2017 + # To extract archives (.tar.gz, .zip), we need access to "tar", added in Windows 10/2019. + ${{ if eq(parameters.extractArchiveArtifacts, 'false') }}: + name: Hosted VS2017 + ${{ if ne(parameters.extractArchiveArtifacts, 'false') }}: + vmImage: windows-2019 steps: - checkout: self clean: true + - ${{ if ne(parameters.downloadArtifacts, 'false')}}: - ${{ if ne(parameters.artifactNames, '') }}: - ${{ each artifactName in parameters.artifactNames }}: @@ -59,16 +96,51 @@ jobs: itemPattern: "**" downloadPath: $(Build.ArtifactStagingDirectory)\artifacts checkDownloadedFiles: true + + - ${{ each artifactName in parameters.pipelineArtifactNames }}: + - task: DownloadPipelineArtifact@2 + displayName: Download Pipeline Artifacts + inputs: + buildType: specific + buildVersionToDownload: specific + project: $(AzDOProjectName) + pipeline: $(AzDOPipelineId) + buildId: $(AzDOBuildId) + artifactName: ${{ artifactName }} + downloadPath: $(Build.ArtifactStagingDirectory)\artifacts + checkDownloadedFiles: true + - powershell: eng/common/sdl/extract-artifact-packages.ps1 -InputPath $(Build.ArtifactStagingDirectory)\artifacts\BlobArtifacts -ExtractPath $(Build.ArtifactStagingDirectory)\artifacts\BlobArtifacts displayName: Extract Blob Artifacts continueOnError: ${{ parameters.sdlContinueOnError }} + - powershell: eng/common/sdl/extract-artifact-packages.ps1 -InputPath $(Build.ArtifactStagingDirectory)\artifacts\PackageArtifacts -ExtractPath $(Build.ArtifactStagingDirectory)\artifacts\PackageArtifacts displayName: Extract Package Artifacts continueOnError: ${{ parameters.sdlContinueOnError }} + + - ${{ if ne(parameters.extractArchiveArtifacts, 'false') }}: + - powershell: eng/common/sdl/extract-artifact-archives.ps1 + -InputPath $(Build.ArtifactStagingDirectory)\artifacts + -ExtractPath $(Build.ArtifactStagingDirectory)\artifacts + displayName: Extract Archive Artifacts + continueOnError: ${{ parameters.sdlContinueOnError }} + + - ${{ if ne(parameters.overrideGuardianVersion, '') }}: + - powershell: | + $content = Get-Content $(GuardianPackagesConfigFile) + + Write-Host "packages.config content was:`n$content" + + $content = $content.Replace('$(DefaultGuardianVersion)', '$(GuardianVersion)') + $content | Set-Content $(GuardianPackagesConfigFile) + + Write-Host "packages.config content updated to:`n$content" + displayName: Use overridden Guardian version ${{ parameters.overrideGuardianVersion }} + - task: NuGetToolInstaller@1 displayName: 'Install NuGet.exe' - task: NuGetCommand@2 @@ -79,15 +151,35 @@ jobs: nugetConfigPath: $(Build.SourcesDirectory)\eng\common\sdl\NuGet.config externalFeedCredentials: GuardianConnect restoreDirectory: $(Build.SourcesDirectory)\.packages + - ${{ if ne(parameters.overrideParameters, '') }}: - - powershell: eng/common/sdl/execute-all-sdl-tools.ps1 ${{ parameters.overrideParameters }} + - powershell: ${{ parameters.executeAllSdlToolsScript }} ${{ parameters.overrideParameters }} displayName: Execute SDL continueOnError: ${{ parameters.sdlContinueOnError }} - ${{ if eq(parameters.overrideParameters, '') }}: - - powershell: eng/common/sdl/execute-all-sdl-tools.ps1 - -GuardianPackageName Microsoft.Guardian.Cli.0.53.3 + - powershell: ${{ parameters.executeAllSdlToolsScript }} + -GuardianPackageName Microsoft.Guardian.Cli.$(GuardianVersion) -NugetPackageDirectory $(Build.SourcesDirectory)\.packages -AzureDevOpsAccessToken $(dn-bot-dotnet-build-rw-code-rw) ${{ parameters.additionalParameters }} displayName: Execute SDL continueOnError: ${{ parameters.sdlContinueOnError }} + + - ${{ if ne(parameters.publishGuardianDirectoryToPipeline, 'false') }}: + # We want to publish the Guardian results and configuration for easy diagnosis. However, the + # '.gdn' dir is a mix of configuration, results, extracted dependencies, and Guardian default + # tooling files. Some of these files are large and aren't useful during an investigation, so + # exclude them by simply deleting them before publishing. (As of writing, there is no documented + # way to selectively exclude a dir from the pipeline artifact publish task.) + - task: DeleteFiles@1 + displayName: Delete Guardian dependencies to avoid uploading + inputs: + SourceFolder: $(Agent.BuildDirectory)/.gdn + Contents: | + c + i + condition: succeededOrFailed() + - publish: $(Agent.BuildDirectory)/.gdn + artifact: GuardianConfiguration + displayName: Publish GuardianConfiguration + condition: succeededOrFailed() diff --git a/eng/common/tools.ps1 b/eng/common/tools.ps1 index 2df0909937d..5d526c74d51 100644 --- a/eng/common/tools.ps1 +++ b/eng/common/tools.ps1 @@ -106,6 +106,46 @@ function Exec-Process([string]$command, [string]$commandArgs) { } } +# Take the given block, print it, print what the block probably references from the current set of +# variables using low-effort string matching, then run the block. +# +# This is intended to replace the pattern of manually copy-pasting a command, wrapping it in quotes, +# and printing it using "Write-Host". The copy-paste method is more readable in build logs, but less +# maintainable and less reliable. It is easy to make a mistake and modify the command without +# properly updating the "Write-Host" line, resulting in misleading build logs. The probability of +# this mistake makes the pattern hard to trust when it shows up in build logs. Finding the bug in +# existing source code can also be difficult, because the strings are not aligned to each other and +# the line may be 300+ columns long. +# +# By removing the need to maintain two copies of the command, Exec-BlockVerbosely avoids the issues. +# +# In Bash (or any posix-like shell), "set -x" prints usable verbose output automatically. +# "Set-PSDebug" appears to be similar at first glance, but unfortunately, it isn't very useful: it +# doesn't print any info about the variables being used by the command, which is normally the +# interesting part to diagnose. +function Exec-BlockVerbosely([scriptblock] $block) { + Write-Host "--- Running script block:" + $blockString = $block.ToString().Trim() + Write-Host $blockString + + Write-Host "--- List of variables that might be used:" + # For each variable x in the environment, check the block for a reference to x via simple "$x" or + # "@x" syntax. This doesn't detect other ways to reference variables ("${x}" nor "$variable:x", + # among others). It only catches what this function was originally written for: simple + # command-line commands. + $variableTable = Get-Variable | + Where-Object { + $blockString.Contains("`$$($_.Name)") -or $blockString.Contains("@$($_.Name)") + } | + Format-Table -AutoSize -HideTableHeaders -Wrap | + Out-String + Write-Host $variableTable.Trim() + + Write-Host "--- Executing:" + & $block + Write-Host "--- Done running script block!" +} + # createSdkLocationFile parameter enables a file being generated under the toolset directory # which writes the sdk's location into. This is only necessary for cmd --> powershell invocations # as dot sourcing isn't possible. @@ -632,6 +672,17 @@ function ExitWithExitCode([int] $exitCode) { exit $exitCode } +# Check if $LASTEXITCODE is a nonzero exit code (NZEC). If so, print a Azure Pipeline error for +# diagnostics, then exit the script with the $LASTEXITCODE. +function Exit-IfNZEC([string] $category = "General") { + Write-Host "Exit code $LASTEXITCODE" + if ($LASTEXITCODE -ne 0) { + $message = "Last command failed with exit code $LASTEXITCODE." + Write-PipelineTelemetryError -Force -Category $category -Message $message + ExitWithExitCode $LASTEXITCODE + } +} + function Stop-Processes() { Write-Host 'Killing running build processes...' foreach ($processName in $processesToStopOnExit) { diff --git a/global.json b/global.json index efde5cc8a08..e2e9d5536a0 100644 --- a/global.json +++ b/global.json @@ -16,6 +16,6 @@ }, "msbuild-sdks": { "Microsoft.Build.NoTargets": "2.0.1", - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21363.2" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21364.3" } } From 36d9753397fef7b3b097c5af1c08887077daaa53 Mon Sep 17 00:00:00 2001 From: kkeirstead <85592574+kkeirstead@users.noreply.github.com> Date: Thu, 15 Jul 2021 10:34:09 -0700 Subject: [PATCH 172/185] Add /info Endpoint (#540) --- documentation/README.md | 1 + documentation/api/README.md | 1 + documentation/api/definitions.md | 11 ++++ documentation/api/info.md | 56 +++++++++++++++++ documentation/api/metrics.md | 1 - documentation/openapi.json | 58 ++++++++++++++++++ .../Controllers/DiagController.cs | 60 ++++++++++++++++++- .../DiagnosticPortConnectionMode.cs | 2 +- .../DiagnosticPortOptions.cs | 5 +- .../DiagnosticPortOptionsDefaults.cs | 4 +- .../Models/DotnetMonitorInfo.cs | 39 ++++++++++++ ...t.Diagnostics.Monitoring.TestCommon.csproj | 4 +- .../LogsTests.cs | 1 + ...agnostics.Monitoring.Tool.UnitTests.csproj | 4 +- .../DiagnosticPortValidateOptions.cs | 1 + .../DiagnosticsMonitorCommandHandler.cs | 7 ++- 16 files changed, 244 insertions(+), 11 deletions(-) create mode 100644 documentation/api/info.md rename src/{Tools/dotnet-monitor => Microsoft.Diagnostics.Monitoring.WebApi}/DiagnosticPortConnectionMode.cs (90%) rename src/{Tools/dotnet-monitor => Microsoft.Diagnostics.Monitoring.WebApi}/DiagnosticPortOptions.cs (96%) rename src/{Tools/dotnet-monitor => Microsoft.Diagnostics.Monitoring.WebApi}/DiagnosticPortOptionsDefaults.cs (82%) create mode 100644 src/Microsoft.Diagnostics.Monitoring.WebApi/Models/DotnetMonitorInfo.cs diff --git a/documentation/README.md b/documentation/README.md index 52ec14e7b06..ee029cb8433 100644 --- a/documentation/README.md +++ b/documentation/README.md @@ -20,6 +20,7 @@ When running a dotnet application, differences in diverse local and production e - [`/trace`](./api/trace.md) - [`/metrics`](./api/metrics.md) - [`/logs`](./api/logs.md) + - [`/info`](./api/info.md) - [Configuration](./configuration.md) - [JSON Schema](./schema.json) - [Authentication](./authentication.md) diff --git a/documentation/api/README.md b/documentation/api/README.md index 35962807221..7b6a8690c21 100644 --- a/documentation/api/README.md +++ b/documentation/api/README.md @@ -12,5 +12,6 @@ The following are the root routes on the HTTP API surface. | [`/trace`](trace.md) | Captures traces of processes without using a profiler. | | [`/metrics`](metrics.md) | Captures metrics of a process. | | [`/logs`](logs.md) | Captures logs of processes. | +| [`/info`](info.md) | Gets info about Dotnet Monitor. | The `dotnet monitor` tool is able to detect .NET Core 3.1 and .NET 5+ applications. When connecting to a .NET Core 3.1 application, some information may not be available and is called out in the documentation. diff --git a/documentation/api/definitions.md b/documentation/api/definitions.md index f1cd95b14f0..501c4070f44 100644 --- a/documentation/api/definitions.md +++ b/documentation/api/definitions.md @@ -1,5 +1,16 @@ # Definitions +## DotnetMonitorInfo + +Object describing diagnostic/automation information about the executing instance of `dotnet monitor`. + +| Name | Type | Description | +|---|---|---| +| Version | string | The current version of Dotnet-Monitor. | +| RuntimeVersion | string | The version of the dotnet runtime. | +| DiagnosticPortMode | DiagnosticPortConnectionMode | Indicates whether `dotnet monitor` is in `connect` mode or `listen` mode. | +| DiagnosticPortName | string | The name of the named pipe or unix domain socket to use for connecting to the diagnostic server. | + ## DumpType Enumeration that describes the type of information to capture in a managed dump. diff --git a/documentation/api/info.md b/documentation/api/info.md new file mode 100644 index 00000000000..d316da27162 --- /dev/null +++ b/documentation/api/info.md @@ -0,0 +1,56 @@ +# Info - Get + +Gets information about the `dotnet monitor` version, the runtime version, and the diagnostic port settings. + +## HTTP Route + +```http +GET /info HTTP/1.1 +``` + +## Host Address + +The default host address for these routes is `https://localhost:52323`. + +## Authentication + +Authentication is enforced for this route. See [Authentication](./../authentication.md) for further information. + +## Responses + +| Name | Type | Description | Content Type | +|---|---|---|---| +| 200 OK | | Information about `dotnet monitor` formatted as JSON. | `application/json` | +| 400 Bad Request | [ValidationProblemDetails](definitions.md#ValidationProblemDetails) | An error occurred due to invalid input. The response body describes the specific problem(s). | `application/problem+json` | +| 401 Unauthorized | | Authentication is required to complete the request. See [Authentication](./../authentication.md) for further information. | | + +## Examples + +### Sample Request + +```http +GET /info HTTP/1.1 +Host: localhost:52323 +``` + +### Sample Response + +```http +HTTP/1.1 200 OK +Content-Type: application/json + +{ + "version": "5.0.0", + "runtimeVersion": "3.1.16", + "diagnosticPortMode": "Connect", + "diagnosticPortName": null +} +``` + +## Supported Runtimes + +| Operating System | Runtime Version | +|---|---| +| Windows | .NET Core 3.1, .NET 5+ | +| Linux | .NET Core 3.1, .NET 5+ | +| MacOS | .NET Core 3.1, .NET 5+ | diff --git a/documentation/api/metrics.md b/documentation/api/metrics.md index 6ff2d59e9bb..53ee70d4400 100644 --- a/documentation/api/metrics.md +++ b/documentation/api/metrics.md @@ -34,7 +34,6 @@ Authentication is not enforced for this route. | 200 OK | | A list of metrics for a single process in the Prometheus exposition format. | `text/plain` | | 400 Bad Request | [ValidationProblemDetails](definitions.md#ValidationProblemDetails) | An error occurred due to invalid input. The response body describes the specific problem(s). | `application/problem+json` | | 401 Unauthorized | | Authentication is required to complete the request. See [Authentication](./../authentication.md) for further information. | | -| 429 Too Many Requests | | There are too many trace requests at this time. Try to request a trace at a later time. | | ## Examples diff --git a/documentation/openapi.json b/documentation/openapi.json index bfe6c3ffec0..73cc8740135 100644 --- a/documentation/openapi.json +++ b/documentation/openapi.json @@ -754,6 +754,33 @@ } } }, + "/info": { + "get": { + "tags": [ + "Diag" + ], + "summary": "Gets versioning and listening mode information about Dotnet-Monitor", + "operationId": "GetInfo", + "responses": { + "400": { + "$ref": "#/components/responses/BadRequestResponse" + }, + "401": { + "$ref": "#/components/responses/UnauthorizedResponse" + }, + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DotnetMonitorInfo" + } + } + } + } + } + } + }, "/metrics": { "get": { "tags": [ @@ -985,6 +1012,37 @@ } }, "additionalProperties": false + }, + "DiagnosticPortConnectionMode": { + "enum": [ + "Connect", + "Listen" + ], + "type": "string" + }, + "DotnetMonitorInfo": { + "type": "object", + "properties": { + "version": { + "type": "string", + "description": "The dotnet monitor version.", + "nullable": true + }, + "runtimeVersion": { + "type": "string", + "description": "The dotnet runtime version.", + "nullable": true + }, + "diagnosticPortMode": { + "$ref": "#/components/schemas/DiagnosticPortConnectionMode" + }, + "diagnosticPortName": { + "type": "string", + "description": "The name of the named pipe or unix domain socket to use for connecting to the diagnostic server.", + "nullable": true + } + }, + "additionalProperties": false } }, "responses": { diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.cs index 45d4bdc7fb4..b1777318a26 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.cs @@ -11,6 +11,7 @@ using Microsoft.Diagnostics.NETCore.Client; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; using Microsoft.Net.Http.Headers; using System; using System.Collections.Generic; @@ -18,6 +19,7 @@ using System.Diagnostics; using System.IO; using System.Linq; +using System.Reflection; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; @@ -47,11 +49,13 @@ public class DiagController : ControllerBase private readonly ILogger _logger; private readonly IDiagnosticServices _diagnosticServices; + private readonly IOptions _diagnosticPortOptions; public DiagController(ILogger logger, IServiceProvider serviceProvider) { _logger = logger; _diagnosticServices = serviceProvider.GetRequiredService(); + _diagnosticPortOptions = serviceProvider.GetService>(); } /// @@ -520,6 +524,60 @@ public Task CaptureLogsCustom( }, processKey, ArtifactType_Logs); } + /// + /// Gets versioning and listening mode information about Dotnet-Monitor + /// + [HttpGet("info", Name = nameof(GetInfo))] + [ProducesWithProblemDetails(ContentTypes.ApplicationJson)] + [ProducesResponseType(typeof(Models.DotnetMonitorInfo), StatusCodes.Status200OK)] + public ActionResult GetInfo() + { + return this.InvokeService(() => + { + string version = GetDotnetMonitorVersion(); + string runtimeVersion = Environment.Version.ToString(); + DiagnosticPortConnectionMode diagnosticPortMode = GetDiagnosticPortMode(); + string diagnosticPortName = GetDiagnosticPortName(); + + Models.DotnetMonitorInfo dotnetMonitorInfo = new Models.DotnetMonitorInfo() + { + Version = version, + RuntimeVersion = runtimeVersion, + DiagnosticPortMode = diagnosticPortMode, + DiagnosticPortName = diagnosticPortName + }; + + _logger.WrittenToHttpStream(); + return new ActionResult(dotnetMonitorInfo); + }, _logger); + } + + private static string GetDotnetMonitorVersion() + { + var assembly = Assembly.GetEntryAssembly() ?? Assembly.GetExecutingAssembly(); + + var assemblyVersionAttribute = assembly.GetCustomAttribute(); + + if (assemblyVersionAttribute is null) + { + return assembly.GetName().Version.ToString(); + } + else + { + return assemblyVersionAttribute.InformationalVersion; + } + } + + public DiagnosticPortConnectionMode GetDiagnosticPortMode() + { + return _diagnosticPortOptions.Value.ConnectionMode.GetValueOrDefault(DiagnosticPortOptionsDefaults.ConnectionMode); + } + + public string GetDiagnosticPortName() + { + return _diagnosticPortOptions.Value.EndpointName; + } + private ActionResult StartTrace( IProcessInfo processInfo, MonitoringSourceConfiguration configuration, @@ -570,7 +628,7 @@ private ActionResult StartLogs( string fileName = FormattableString.Invariant($"{GetFileNameTimeStampUtcNow()}_{processInfo.EndpointInfo.ProcessId}.txt"); string contentType = ContentTypes.TextEventStream; - + if (format == LogFormat.EventStream) { contentType = ContentTypes.TextEventStream; diff --git a/src/Tools/dotnet-monitor/DiagnosticPortConnectionMode.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/DiagnosticPortConnectionMode.cs similarity index 90% rename from src/Tools/dotnet-monitor/DiagnosticPortConnectionMode.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/DiagnosticPortConnectionMode.cs index 466815c7194..a31ea7c86fa 100644 --- a/src/Tools/dotnet-monitor/DiagnosticPortConnectionMode.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/DiagnosticPortConnectionMode.cs @@ -7,7 +7,7 @@ #if UNITTEST namespace Microsoft.Diagnostics.Monitoring.UnitTests.Options #else -namespace Microsoft.Diagnostics.Tools.Monitor +namespace Microsoft.Diagnostics.Monitoring.WebApi #endif { [JsonConverter(typeof(JsonStringEnumConverter))] diff --git a/src/Tools/dotnet-monitor/DiagnosticPortOptions.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/DiagnosticPortOptions.cs similarity index 96% rename from src/Tools/dotnet-monitor/DiagnosticPortOptions.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/DiagnosticPortOptions.cs index 34e3a9cd831..1c94bf9a640 100644 --- a/src/Tools/dotnet-monitor/DiagnosticPortOptions.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/DiagnosticPortOptions.cs @@ -2,14 +2,15 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. -using Microsoft.Diagnostics.Monitoring.WebApi; using System.ComponentModel; using System.ComponentModel.DataAnnotations; #if UNITTEST +using Microsoft.Diagnostics.Monitoring.WebApi; + namespace Microsoft.Diagnostics.Monitoring.UnitTests.Options #else -namespace Microsoft.Diagnostics.Tools.Monitor +namespace Microsoft.Diagnostics.Monitoring.WebApi #endif { public class DiagnosticPortOptions diff --git a/src/Tools/dotnet-monitor/DiagnosticPortOptionsDefaults.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/DiagnosticPortOptionsDefaults.cs similarity index 82% rename from src/Tools/dotnet-monitor/DiagnosticPortOptionsDefaults.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/DiagnosticPortOptionsDefaults.cs index 65b0cb9356c..a8ea0df6e93 100644 --- a/src/Tools/dotnet-monitor/DiagnosticPortOptionsDefaults.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/DiagnosticPortOptionsDefaults.cs @@ -3,9 +3,11 @@ // See the LICENSE file in the project root for more information. #if UNITTEST +using Microsoft.Diagnostics.Monitoring.WebApi; + namespace Microsoft.Diagnostics.Monitoring.UnitTests.Options #else -namespace Microsoft.Diagnostics.Tools.Monitor +namespace Microsoft.Diagnostics.Monitoring.WebApi #endif { internal class DiagnosticPortOptionsDefaults diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/DotnetMonitorInfo.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/DotnetMonitorInfo.cs new file mode 100644 index 00000000000..842f85cb1a3 --- /dev/null +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/DotnetMonitorInfo.cs @@ -0,0 +1,39 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System.Text.Json.Serialization; + +#if UNITTEST +namespace Microsoft.Diagnostics.Monitoring.UnitTests.Models +#else +namespace Microsoft.Diagnostics.Monitoring.WebApi.Models +#endif +{ + public class DotnetMonitorInfo + { + /// + /// The dotnet monitor version. + /// + [JsonPropertyName("version")] + public string Version { get; set; } + + /// + /// The dotnet runtime version. + /// + [JsonPropertyName("runtimeVersion")] + public string RuntimeVersion { get; set; } + + /// + /// Indicates whether dotnet monitor is in 'connect' mode or 'listen' mode. + /// + [JsonPropertyName("diagnosticPortMode")] + public DiagnosticPortConnectionMode DiagnosticPortMode { get; set; } + + /// + /// The name of the named pipe or unix domain socket to use for connecting to the diagnostic server. + /// + [JsonPropertyName("diagnosticPortName")] + public string DiagnosticPortName { get; set; } + } +} diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.TestCommon/Microsoft.Diagnostics.Monitoring.TestCommon.csproj b/src/Tests/Microsoft.Diagnostics.Monitoring.TestCommon/Microsoft.Diagnostics.Monitoring.TestCommon.csproj index 43b4ec2cd46..2f51b2ad737 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.TestCommon/Microsoft.Diagnostics.Monitoring.TestCommon.csproj +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.TestCommon/Microsoft.Diagnostics.Monitoring.TestCommon.csproj @@ -6,7 +6,7 @@ - + @@ -17,4 +17,4 @@ - + \ No newline at end of file diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/LogsTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/LogsTests.cs index 542d254b6b4..b6e6f12f0f4 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/LogsTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/LogsTests.cs @@ -23,6 +23,7 @@ using System.Threading.Tasks; using Xunit; using Xunit.Abstractions; +using DiagnosticPortConnectionMode = Microsoft.Diagnostics.Monitoring.UnitTests.Options.DiagnosticPortConnectionMode; namespace Microsoft.Diagnostics.Monitoring.UnitTests { diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj index 78e5ae123a5..94abd954490 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj @@ -20,8 +20,8 @@ - - + + diff --git a/src/Tools/dotnet-monitor/DiagnosticPortValidateOptions.cs b/src/Tools/dotnet-monitor/DiagnosticPortValidateOptions.cs index 3b702070959..b547e45ce6d 100644 --- a/src/Tools/dotnet-monitor/DiagnosticPortValidateOptions.cs +++ b/src/Tools/dotnet-monitor/DiagnosticPortValidateOptions.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.Extensions.Options; namespace Microsoft.Diagnostics.Tools.Monitor diff --git a/src/Tools/dotnet-monitor/DiagnosticsMonitorCommandHandler.cs b/src/Tools/dotnet-monitor/DiagnosticsMonitorCommandHandler.cs index 782b6ebb5d0..2c73b942c95 100644 --- a/src/Tools/dotnet-monitor/DiagnosticsMonitorCommandHandler.cs +++ b/src/Tools/dotnet-monitor/DiagnosticsMonitorCommandHandler.cs @@ -327,7 +327,7 @@ private static void ConfigureMetricsEndpoint(IConfigurationBuilder builder, bool private static void ConfigureEndpointInfoSource(IConfigurationBuilder builder, string diagnosticPort) { - DiagnosticPortConnectionMode connectionMode = string.IsNullOrEmpty(diagnosticPort) ? DiagnosticPortConnectionMode.Connect : DiagnosticPortConnectionMode.Listen; + DiagnosticPortConnectionMode connectionMode = GetConnectionMode(diagnosticPort); builder.AddInMemoryCollection(new Dictionary { {ConfigurationPath.Combine(ConfigurationKeys.DiagnosticPort, nameof(DiagnosticPortOptions.ConnectionMode)), connectionMode.ToString()}, @@ -335,6 +335,11 @@ private static void ConfigureEndpointInfoSource(IConfigurationBuilder builder, s }); } + private static DiagnosticPortConnectionMode GetConnectionMode(string diagnosticPort) + { + return string.IsNullOrEmpty(diagnosticPort) ? DiagnosticPortConnectionMode.Connect : DiagnosticPortConnectionMode.Listen; + } + private static string GetEnvironmentOverrideOrValue(string overrideEnvironmentVariable, string value) { return Environment.GetEnvironmentVariable(overrideEnvironmentVariable) ?? value; From 3df0b637c8cc339db83fec1a1b086e0d309a525a Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 16 Jul 2021 12:42:50 +0000 Subject: [PATCH 173/185] Update dependencies from https://github.com/dotnet/arcade build 20210715.11 (#575) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- global.json | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index a39a9797615..88249f283a0 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -14,13 +14,13 @@ - + https://github.com/dotnet/arcade - 6a8491b61e0c243cbb6a7ff4966b48e6d1e075b1 + 7b88b24068ecb4f6cf1da8395dbc2dee25a700bd - + https://github.com/dotnet/arcade - 6a8491b61e0c243cbb6a7ff4966b48e6d1e075b1 + 7b88b24068ecb4f6cf1da8395dbc2dee25a700bd https://github.com/dotnet/symstore diff --git a/eng/Versions.props b/eng/Versions.props index 95fa611ff13..7df78090804 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -27,7 +27,7 @@ --> - 6.0.0-beta.21364.3 + 6.0.0-beta.21365.11 6.0.0-preview.7.21364.17 diff --git a/global.json b/global.json index e2e9d5536a0..4dc853ec5fe 100644 --- a/global.json +++ b/global.json @@ -16,6 +16,6 @@ }, "msbuild-sdks": { "Microsoft.Build.NoTargets": "2.0.1", - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21364.3" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21365.11" } } From 67335e6aa48e2a7d53925b5a95ddece38c92d3b3 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 16 Jul 2021 13:10:30 +0000 Subject: [PATCH 174/185] Update dependencies from https://github.com/dotnet/runtime build 20210715.21 (#576) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 88249f283a0..d73652a02d7 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore eccb20d7778f4ef4496d1e2797324c52e755a25c - + https://github.com/dotnet/runtime - 90b8ddd7a6b28e57aebed7d478547ce07b9b60a6 + 62fa1f838e48459cda27c3d3f991253fdec9b4f8 diff --git a/eng/Versions.props b/eng/Versions.props index 7df78090804..4fa7e69e2ab 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21364.1 5.0.0-preview.21364.1 - 6.0.0-preview.7.21365.2 + 6.0.0-preview.7.21365.21 1.0.215101 From dd95388d4ee443d55b8d90db2d54f14dca45c63e Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 16 Jul 2021 13:10:40 +0000 Subject: [PATCH 175/185] Update dependencies from https://github.com/dotnet/aspnetcore build 20210716.1 (#577) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index d73652a02d7..5b8446c06ff 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - eccb20d7778f4ef4496d1e2797324c52e755a25c + 08368a2dee8b8ed1ed522bff7b6ecfbd150ff995 https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 4fa7e69e2ab..106260252dc 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21365.11 - 6.0.0-preview.7.21364.17 + 6.0.0-rc.1.21366.1 5.0.0-preview.21364.1 5.0.0-preview.21364.1 From be54b2074133a1c83790f0ea3a76e354f39f5ef9 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Fri, 16 Jul 2021 16:15:07 +0000 Subject: [PATCH 176/185] Update dependencies from https://github.com/dotnet/diagnostics build 20210715.1 (#574) [main] Update dependencies from dotnet/diagnostics --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 5b8446c06ff..bf0cfaea140 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,11 +4,11 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics 419db65453d353c654192b42fa5aa63785b02abc - + https://github.com/dotnet/diagnostics 419db65453d353c654192b42fa5aa63785b02abc diff --git a/eng/Versions.props b/eng/Versions.props index 106260252dc..5bad0c11263 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-rc.1.21366.1 - 5.0.0-preview.21364.1 - 5.0.0-preview.21364.1 + 5.0.0-preview.21365.1 + 5.0.0-preview.21365.1 6.0.0-preview.7.21365.21 From bf6844e907c40b617eab6ef9c807065603678d51 Mon Sep 17 00:00:00 2001 From: Wiktor Kopec Date: Fri, 16 Jul 2021 15:30:54 -0700 Subject: [PATCH 177/185] Add operational style api for egressed artifacts (#425) * Add operational style api for egressed artifacts * Add unit tests * Share throttling limits between endpoint and operations - Also add PR Feedback * Unify errors between middleware and controllers - Also add operation list capability * Use resource based strings + minor renames * More PR feedback * Regenerate api doc * Add list unit test * Ensure ConfigureAwait on api code * PR feedback --- documentation/openapi.json | 212 +++++++++++++- dotnet-monitor.sln | 3 - eng/Versions.props | 1 + .../ActionContextExtensions.cs | 99 +++++-- .../Controllers/DiagController.cs | 77 +++-- .../Controllers/DiagControllerExtensions.cs | 9 +- .../Controllers/OperationsController.cs | 74 +++++ ...osoft.Diagnostics.Monitoring.WebApi.csproj | 1 + .../Models/EgressOperationStatus.cs | 65 +++++ .../EgressOperation.cs} | 24 +- .../Operation/EgressOperationQueue.cs | 54 ++++ .../Operation/EgressOperationService.cs | 58 ++++ .../Operation/EgressOperationStore.cs | 166 +++++++++++ .../Operation/EgressRequest.cs | 45 +++ .../{ => Operation}/EgressResult.cs | 5 +- .../Operation/IEgressOperation.cs | 17 ++ .../Operation/OperationExtensions.cs | 23 ++ .../Operation/TooManyRequestsException.cs | 18 ++ .../RequestLimitAttribute.cs | 2 +- .../RequestThrottling/RequestLimitTracker.cs | 61 ++++ .../Strings.Designer.cs | 36 +++ .../Strings.resx | 15 + src/Tests/Directory.Build.props | 6 - .../OpenApiGeneratorTests.cs | 2 + .../TooManyRequestsResponseDocumentFilter.cs | 16 ++ .../TooManyRequestsResponseOperationFilter.cs | 18 +- .../EgressTests.cs | 270 ++++++++++++++++++ .../HttpApi/ApiClient.cs | 92 ++++++ .../HttpApi/ApiClientExtensions.cs | 54 ++++ .../HttpApi/OperationResponse.cs | 24 ++ .../HttpApi/OperationStatusResponse.cs | 24 ++ ...agnostics.Monitoring.Tool.UnitTests.csproj | 1 + .../Options/OptionsExtensions.cs | 22 +- .../Runners/ScenarioRunner.cs | 11 +- .../TestTimeouts.cs | 6 + src/Tests/test.runsettings | 8 - .../DiagnosticsMonitorCommandHandler.cs | 2 + .../dotnet-monitor/Egress/EgressService.cs | 4 +- ...hrottling.cs => RequestLimitMiddleware.cs} | 47 +-- src/Tools/dotnet-monitor/Startup.cs | 2 +- 40 files changed, 1541 insertions(+), 133 deletions(-) create mode 100644 src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/OperationsController.cs create mode 100644 src/Microsoft.Diagnostics.Monitoring.WebApi/Models/EgressOperationStatus.cs rename src/Microsoft.Diagnostics.Monitoring.WebApi/{EgressStreamResult.cs => Operation/EgressOperation.cs} (62%) create mode 100644 src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressOperationQueue.cs create mode 100644 src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressOperationService.cs create mode 100644 src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressOperationStore.cs create mode 100644 src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressRequest.cs rename src/Microsoft.Diagnostics.Monitoring.WebApi/{ => Operation}/EgressResult.cs (76%) create mode 100644 src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/IEgressOperation.cs create mode 100644 src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/OperationExtensions.cs create mode 100644 src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/TooManyRequestsException.cs create mode 100644 src/Microsoft.Diagnostics.Monitoring.WebApi/RequestThrottling/RequestLimitTracker.cs delete mode 100644 src/Tests/Directory.Build.props create mode 100644 src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressTests.cs create mode 100644 src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/OperationResponse.cs create mode 100644 src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/OperationStatusResponse.cs delete mode 100644 src/Tests/test.runsettings rename src/Tools/dotnet-monitor/{Throttling.cs => RequestLimitMiddleware.cs} (51%) diff --git a/documentation/openapi.json b/documentation/openapi.json index 73cc8740135..14d4773302b 100644 --- a/documentation/openapi.json +++ b/documentation/openapi.json @@ -239,6 +239,9 @@ } } } + }, + "202": { + "description": "Success" } } } @@ -314,6 +317,9 @@ } } } + }, + "202": { + "description": "Success" } } } @@ -423,6 +429,9 @@ } } } + }, + "202": { + "description": "Success" } } }, @@ -530,6 +539,9 @@ } } } + }, + "202": { + "description": "Success" } } } @@ -635,6 +647,9 @@ } } } + }, + "202": { + "description": "Success" } } }, @@ -750,6 +765,9 @@ } } } + }, + "202": { + "description": "Success" } } } @@ -804,6 +822,98 @@ } } } + }, + "/operations": { + "get": { + "tags": [ + "Operations" + ], + "responses": { + "401": { + "$ref": "#/components/responses/UnauthorizedResponse" + }, + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/OperationSummary" + } + } + } + } + } + } + } + }, + "/operations/{operationId}": { + "get": { + "tags": [ + "Operations" + ], + "parameters": [ + { + "name": "operationId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "401": { + "$ref": "#/components/responses/UnauthorizedResponse" + }, + "201": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OperationStatus" + } + } + } + }, + "200": { + "description": "Success", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/OperationStatus" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Operations" + ], + "parameters": [ + { + "name": "operationId", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "uuid" + } + } + ], + "responses": { + "401": { + "$ref": "#/components/responses/UnauthorizedResponse" + }, + "200": { + "description": "Success" + } + } + } } }, "components": { @@ -906,6 +1016,33 @@ ], "type": "string" }, + "ProblemDetails": { + "type": "object", + "properties": { + "type": { + "type": "string", + "nullable": true + }, + "title": { + "type": "string", + "nullable": true + }, + "status": { + "type": "integer", + "format": "int32", + "nullable": true + }, + "detail": { + "type": "string", + "nullable": true + }, + "instance": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": { } + }, "TraceProfile": { "enum": [ "Cpu", @@ -1043,6 +1180,72 @@ } }, "additionalProperties": false + }, + "OperationState": { + "enum": [ + "Running", + "Succeeded", + "Failed", + "Cancelled" + ], + "type": "string" + }, + "OperationSummary": { + "type": "object", + "properties": { + "operationId": { + "type": "string", + "format": "uuid" + }, + "createdDateTime": { + "type": "string", + "format": "date-time" + }, + "status": { + "$ref": "#/components/schemas/OperationState" + } + }, + "additionalProperties": false, + "description": "Represents a partial model when enumerating all operations." + }, + "OperationError": { + "type": "object", + "properties": { + "code": { + "type": "string", + "nullable": true + }, + "message": { + "type": "string", + "nullable": true + } + }, + "additionalProperties": false + }, + "OperationStatus": { + "type": "object", + "properties": { + "operationId": { + "type": "string", + "format": "uuid" + }, + "createdDateTime": { + "type": "string", + "format": "date-time" + }, + "status": { + "$ref": "#/components/schemas/OperationState" + }, + "resourceLocation": { + "type": "string", + "nullable": true + }, + "error": { + "$ref": "#/components/schemas/OperationError" + } + }, + "additionalProperties": false, + "description": "Represents the state of a long running operation. Used for all types of results, including successes and failures." } }, "responses": { @@ -1067,7 +1270,14 @@ } }, "TooManyRequestsResponse": { - "description": "TooManyRequests" + "description": "TooManyRequests", + "content": { + "application/problem+json": { + "schema": { + "$ref": "#/components/schemas/ProblemDetails" + } + } + } } } } diff --git a/dotnet-monitor.sln b/dotnet-monitor.sln index 1e0d0587aa8..0b355c55e98 100644 --- a/dotnet-monitor.sln +++ b/dotnet-monitor.sln @@ -17,9 +17,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Common", "Common", "{B24CD8 EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{C7568468-1C79-4944-8136-18812A7F9EA7}" - ProjectSection(SolutionItems) = preProject - src\Tests\test.runsettings = src\Tests\test.runsettings - EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Diagnostics.Monitoring.TestCommon", "src\Tests\Microsoft.Diagnostics.Monitoring.TestCommon\Microsoft.Diagnostics.Monitoring.TestCommon.csproj", "{863AA12D-0918-49CE-9E76-45A22680268B}" EndProject diff --git a/eng/Versions.props b/eng/Versions.props index 5bad0c11263..83ee57eefb0 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -61,6 +61,7 @@ 4.5.1 5.0.0 4.7.2 + 5.0.0 10.3.11 5.6.3 diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/ActionContextExtensions.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/ActionContextExtensions.cs index ad81d41cda4..5df555cdaf5 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/ActionContextExtensions.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/ActionContextExtensions.cs @@ -14,68 +14,70 @@ namespace Microsoft.Diagnostics.Monitoring.WebApi { - internal static class ActionContextExtensions + public sealed class ExecutionResult { - public static Task ProblemAsync(this ActionContext context, Exception ex) - { - if (context.HttpContext.Features.Get().HasStarted) - { - // If already started writing response, do not rewrite - // as this will throw an InvalidOperationException. - return Task.CompletedTask; - } - else - { - BadRequestObjectResult result = new BadRequestObjectResult(ex.ToProblemDetails((int)HttpStatusCode.BadRequest)); - // Need to manually add this here because this ObjectResult is not processed by the filter pipeline, - // which would look up the applicable content types and apply them before executing the result. - result.ContentTypes.Add(ContentTypes.ApplicationProblemJson); - return result.ExecuteResultAsync(context); - } - } + private static readonly ExecutionResult _empty = new ExecutionResult(); - public static async Task InvokeAsync(this ActionContext context, Func action, ILogger logger) + public T Result { get; private set; } + public ProblemDetails ProblemDetails { get; private set; } + + private ExecutionResult() { } + + public static ExecutionResult Succeeded(T result) => new ExecutionResult { Result = result }; + + public static ExecutionResult Failed(ProblemDetails problemDetails) => + new ExecutionResult { ProblemDetails = problemDetails }; + + public static ExecutionResult Empty() => _empty; + } + + internal static class ExecutionHelper + { + private static ExecutionResult ExceptionToResult(Exception ex) => + ExecutionResult.Failed(ex.ToProblemDetails((int)HttpStatusCode.BadRequest)); + + public static async Task> InvokeAsync(Func>> action, ILogger logger, + CancellationToken token) { - CancellationToken token = context.HttpContext.RequestAborted; // Exceptions are logged in the "when" clause in order to preview the exception // from the point of where it was thrown. This allows capturing of the log scopes // that were active when the exception was thrown. Waiting to log during the exception // handler will miss any scopes that were added during invocation of action. try { - await action(token); + return await action(token); } catch (ArgumentException ex) when (LogError(logger, ex)) { - await context.ProblemAsync(ex); + return ExceptionToResult(ex); } catch (DiagnosticsClientException ex) when (LogError(logger, ex)) { - await context.ProblemAsync(ex); + return ExceptionToResult(ex); } catch (InvalidOperationException ex) when (LogError(logger, ex)) { - await context.ProblemAsync(ex); + return ExceptionToResult(ex); } catch (OperationCanceledException ex) when (token.IsCancellationRequested && LogInformation(logger, ex)) { - await context.ProblemAsync(ex); + return ExceptionToResult(ex); } catch (OperationCanceledException ex) when (LogError(logger, ex)) { - await context.ProblemAsync(ex); + return ExceptionToResult(ex); } catch (MonitoringException ex) when (LogError(logger, ex)) { - await context.ProblemAsync(ex); + return ExceptionToResult(ex); } catch (ValidationException ex) when (LogError(logger, ex)) { - await context.ProblemAsync(ex); + return ExceptionToResult(ex); } catch (UnauthorizedAccessException ex) when (LogError(logger, ex)) { - await context.ProblemAsync(ex); + return ExceptionToResult(ex); } } @@ -91,4 +93,43 @@ private static bool LogInformation(ILogger logger, Exception ex) return true; } } + + internal static class ActionContextExtensions + { + public static Task ProblemAsync(this ActionContext context, BadRequestObjectResult result) + { + if (context.HttpContext.Features.Get().HasStarted) + { + // If already started writing response, do not rewrite + // as this will throw an InvalidOperationException. + return Task.CompletedTask; + } + else + { + // Need to manually add this here because this ObjectResult is not processed by the filter pipeline, + // which would look up the applicable content types and apply them before executing the result. + result.ContentTypes.Add(ContentTypes.ApplicationProblemJson); + return result.ExecuteResultAsync(context); + } + } + + public static async Task InvokeAsync(this ActionContext context, Func action, ILogger logger) + { + //We want to handle two scenarios: + //1) These functions are part of an ExecuteResultAsync implementation, in which case + //they don't need to return anything. (The delegate below handles this case). + //2) They are part of deferred processing and return a result. + Func>> innerAction = async (CancellationToken token) => + { + await action(token); + return ExecutionResult.Empty(); + }; + + ExecutionResult result = await ExecutionHelper.InvokeAsync(innerAction, logger, context.HttpContext.RequestAborted); + if (result.ProblemDetails != null) + { + await context.ProblemAsync(new BadRequestObjectResult(result.ProblemDetails)); + } + } + } } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.cs index b1777318a26..4755f9eb128 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagController.cs @@ -20,6 +20,7 @@ using System.IO; using System.Linq; using System.Reflection; +using System.Net; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; @@ -37,10 +38,10 @@ namespace Microsoft.Diagnostics.Monitoring.WebApi.Controllers [ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)] public class DiagController : ControllerBase { - private const string ArtifactType_Dump = "dump"; - private const string ArtifactType_GCDump = "gcdump"; - private const string ArtifactType_Logs = "logs"; - private const string ArtifactType_Trace = "trace"; + public const string ArtifactType_Dump = "dump"; + public const string ArtifactType_GCDump = "gcdump"; + public const string ArtifactType_Logs = "logs"; + public const string ArtifactType_Trace = "trace"; private const Models.TraceProfile DefaultTraceProfiles = Models.TraceProfile.Cpu | Models.TraceProfile.Http | Models.TraceProfile.Metrics; private static readonly MediaTypeHeaderValue NdJsonHeader = new MediaTypeHeaderValue(ContentTypes.ApplicationNdJson); @@ -50,12 +51,15 @@ public class DiagController : ControllerBase private readonly ILogger _logger; private readonly IDiagnosticServices _diagnosticServices; private readonly IOptions _diagnosticPortOptions; + private readonly EgressOperationStore _operationsStore; - public DiagController(ILogger logger, IServiceProvider serviceProvider) + public DiagController(ILogger logger, + IServiceProvider serviceProvider) { _logger = logger; _diagnosticServices = serviceProvider.GetRequiredService(); _diagnosticPortOptions = serviceProvider.GetService>(); + _operationsStore = serviceProvider.GetRequiredService(); } /// @@ -186,9 +190,10 @@ public Task>> GetProcessEnvironment( [ProducesWithProblemDetails(ContentTypes.ApplicationOctetStream)] // FileResult is the closest representation of the output so that the OpenAPI document correctly // describes the result as a binary file. - [ProducesResponseType(typeof(void), StatusCodes.Status429TooManyRequests)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status429TooManyRequests)] [ProducesResponseType(typeof(FileResult), StatusCodes.Status200OK)] - [RequestLimit(MaxConcurrency = 1)] + [ProducesResponseType(typeof(void), StatusCodes.Status202Accepted)] + [RequestLimit(LimitKey = ArtifactType_Dump)] public Task CaptureDump( [FromQuery] int? pid = null, @@ -224,13 +229,13 @@ public Task CaptureDump( scope.AddArtifactType(ArtifactType_Dump); scope.AddEndpointInfo(processInfo.EndpointInfo); - return new EgressStreamResult( + return await SendToEgress(new EgressOperation( token => _diagnosticServices.GetDump(processInfo, type, token), egressProvider, dumpFileName, processInfo.EndpointInfo, ContentTypes.ApplicationOctetStream, - scope); + scope), limitKey: ArtifactType_Dump); } }, processKey, ArtifactType_Dump); } @@ -247,9 +252,10 @@ public Task CaptureDump( [ProducesWithProblemDetails(ContentTypes.ApplicationOctetStream)] // FileResult is the closest representation of the output so that the OpenAPI document correctly // describes the result as a binary file. - [ProducesResponseType(typeof(void), StatusCodes.Status429TooManyRequests)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status429TooManyRequests)] [ProducesResponseType(typeof(FileResult), StatusCodes.Status200OK)] - [RequestLimit(MaxConcurrency = 1)] + [ProducesResponseType(typeof(void), StatusCodes.Status202Accepted)] + [RequestLimit(LimitKey = ArtifactType_GCDump)] public Task CaptureGcDump( [FromQuery] int? pid = null, @@ -309,9 +315,10 @@ public Task CaptureGcDump( [ProducesWithProblemDetails(ContentTypes.ApplicationOctetStream)] // FileResult is the closest representation of the output so that the OpenAPI document correctly // describes the result as a binary file. - [ProducesResponseType(typeof(void), StatusCodes.Status429TooManyRequests)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status429TooManyRequests)] [ProducesResponseType(typeof(FileResult), StatusCodes.Status200OK)] - [RequestLimit(MaxConcurrency = 3)] + [ProducesResponseType(typeof(void), StatusCodes.Status202Accepted)] + [RequestLimit(LimitKey = ArtifactType_Trace)] public Task CaptureTrace( [FromQuery] int? pid = null, @@ -375,9 +382,10 @@ public Task CaptureTrace( [ProducesWithProblemDetails(ContentTypes.ApplicationOctetStream)] // FileResult is the closest representation of the output so that the OpenAPI document correctly // describes the result as a binary file. - [ProducesResponseType(typeof(void), StatusCodes.Status429TooManyRequests)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status429TooManyRequests)] [ProducesResponseType(typeof(FileResult), StatusCodes.Status200OK)] - [RequestLimit(MaxConcurrency = 3)] + [ProducesResponseType(typeof(void), StatusCodes.Status202Accepted)] + [RequestLimit(LimitKey = ArtifactType_Trace)] public Task CaptureTraceCustom( [FromBody][Required] Models.EventPipeConfiguration configuration, @@ -435,9 +443,10 @@ public Task CaptureTraceCustom( /// The egress provider to which the logs are saved. [HttpGet("logs", Name = nameof(CaptureLogs))] [ProducesWithProblemDetails(ContentTypes.ApplicationNdJson, ContentTypes.ApplicationJsonSequence, ContentTypes.TextEventStream)] - [ProducesResponseType(typeof(void), StatusCodes.Status429TooManyRequests)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status429TooManyRequests)] [ProducesResponseType(typeof(string), StatusCodes.Status200OK)] - [RequestLimit(MaxConcurrency = 3)] + [ProducesResponseType(typeof(void), StatusCodes.Status202Accepted)] + [RequestLimit(LimitKey = ArtifactType_Logs)] public Task CaptureLogs( [FromQuery] int? pid = null, @@ -489,9 +498,10 @@ public Task CaptureLogs( /// The egress provider to which the logs are saved. [HttpPost("logs", Name = nameof(CaptureLogsCustom))] [ProducesWithProblemDetails(ContentTypes.ApplicationNdJson, ContentTypes.ApplicationJsonSequence, ContentTypes.TextEventStream)] - [ProducesResponseType(typeof(void), StatusCodes.Status429TooManyRequests)] + [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status429TooManyRequests)] [ProducesResponseType(typeof(string), StatusCodes.Status200OK)] - [RequestLimit(MaxConcurrency = 3)] + [ProducesResponseType(typeof(void), StatusCodes.Status202Accepted)] + [RequestLimit(LimitKey = ArtifactType_Logs)] public Task CaptureLogsCustom( [FromBody] Models.LogsConfiguration configuration, @@ -578,7 +588,7 @@ public string GetDiagnosticPortName() return _diagnosticPortOptions.Value.EndpointName; } - private ActionResult StartTrace( + private Task StartTrace( IProcessInfo processInfo, MonitoringSourceConfiguration configuration, TimeSpan duration, @@ -615,7 +625,7 @@ private ActionResult StartTrace( processInfo.EndpointInfo); } - private ActionResult StartLogs( + private Task StartLogs( IProcessInfo processInfo, EventLogsPipelineSettings settings, string egressProvider) @@ -623,7 +633,7 @@ private ActionResult StartLogs( LogFormat format = ComputeLogFormat(Request.GetTypedHeaders().Accept); if (format == LogFormat.None) { - return this.NotAcceptable(); + return Task.FromResult(this.NotAcceptable()); } string fileName = FormattableString.Invariant($"{GetFileNameTimeStampUtcNow()}_{processInfo.EndpointInfo.ProcessId}.txt"); @@ -715,7 +725,7 @@ private static LogFormat ComputeLogFormat(IList acceptedHe return LogFormat.None; } - private ActionResult Result( + private Task Result( string artifactType, string providerName, Func action, @@ -730,24 +740,37 @@ private ActionResult Result( if (string.IsNullOrEmpty(providerName)) { - return new OutputStreamResult( + return Task.FromResult(new OutputStreamResult( action, contentType, asAttachment ? fileName : null, - scope); + scope)); } else { - return new EgressStreamResult( + return SendToEgress(new EgressOperation( action, providerName, fileName, endpointInfo, contentType, - scope); + scope), + limitKey: artifactType); } } + private async Task SendToEgress(EgressOperation egressStreamResult, string limitKey) + { + // Will throw TooManyRequestsException if there are too many concurrent operations. + Guid operationId = await _operationsStore.AddOperation(egressStreamResult, limitKey); + string newUrl = this.Url.Action( + action: nameof(OperationsController.GetOperationStatus), + controller: OperationsController.ControllerName, new { operationId = operationId }, + protocol: this.HttpContext.Request.Scheme, this.HttpContext.Request.Host.ToString()); + + return Accepted(newUrl); + } + private static Func ConvertFastSerializeAction(Func> action) { return async (stream, token) => diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagControllerExtensions.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagControllerExtensions.cs index af240697c6e..91110e3a75e 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagControllerExtensions.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/DiagControllerExtensions.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Diagnostics.NETCore.Client; using Microsoft.Extensions.Logging; @@ -75,6 +76,10 @@ public static async Task> InvokeService(this ControllerBase c { return controller.Problem(e); } + catch (TooManyRequestsException e) when (LogError(logger, e)) + { + return controller.Problem(e, statusCode: StatusCodes.Status429TooManyRequests); + } catch (MonitoringException e) when (LogError(logger, e)) { return controller.Problem(e); @@ -85,9 +90,9 @@ public static async Task> InvokeService(this ControllerBase c } } - public static ObjectResult Problem(this ControllerBase controller, Exception ex) + public static ObjectResult Problem(this ControllerBase controller, Exception ex, int statusCode = StatusCodes.Status400BadRequest) { - return controller.BadRequest(ex.ToProblemDetails((int)HttpStatusCode.BadRequest)); + return new BadRequestObjectResult(ex.ToProblemDetails(statusCode)) { StatusCode = statusCode }; } private static bool LogError(ILogger logger, Exception ex) diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/OperationsController.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/OperationsController.cs new file mode 100644 index 00000000000..14bcf456d8d --- /dev/null +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Controllers/OperationsController.cs @@ -0,0 +1,74 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.AspNetCore.Authorization; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Microsoft.Diagnostics.Monitoring.WebApi.Controllers +{ + [Route(ControllerName)] + [ApiController] + [HostRestriction] + [Authorize(Policy = AuthConstants.PolicyName)] + [ProducesResponseType(typeof(void), StatusCodes.Status401Unauthorized)] + public class OperationsController : ControllerBase + { + private readonly ILogger _logger; + private readonly EgressOperationStore _operationsStore; + + public const string ControllerName = "operations"; + + public OperationsController(ILogger logger, IServiceProvider serviceProvider) + { + _logger = logger; + _operationsStore = serviceProvider.GetRequiredService(); + } + + [HttpGet] + [ProducesWithProblemDetails(ContentTypes.ApplicationJson)] + [ProducesResponseType(typeof(IEnumerable), StatusCodes.Status200OK)] + public ActionResult> GetOperations() + { + return this.InvokeService(() => + { + return new ActionResult>(_operationsStore.GetOperations()); + }, _logger); + } + + [HttpGet("{operationId}")] + [ProducesWithProblemDetails(ContentTypes.ApplicationJson)] + [ProducesResponseType(typeof(Models.OperationStatus), StatusCodes.Status201Created)] + [ProducesResponseType(typeof(Models.OperationStatus), StatusCodes.Status200OK)] + public IActionResult GetOperationStatus(Guid operationId) + { + return this.InvokeService(() => + { + Models.OperationStatus status = _operationsStore.GetOperationStatus(operationId); + int statusCode = (int)(status.Status == Models.OperationState.Succeeded ? StatusCodes.Status201Created : StatusCodes.Status200OK); + return this.StatusCode(statusCode, status); + }, _logger); + } + + [HttpDelete("{operationId}")] + [ProducesWithProblemDetails(ContentTypes.ApplicationJson)] + [ProducesResponseType(typeof(void), StatusCodes.Status200OK)] + public IActionResult CancelOperation(Guid operationId) + { + return this.InvokeService(() => + { + //Note that if the operation is not found, it will throw an InvalidOperationException and + //return an error code. + _operationsStore.CancelOperation(operationId); + return Ok(); + }, _logger); + } + } +} diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Microsoft.Diagnostics.Monitoring.WebApi.csproj b/src/Microsoft.Diagnostics.Monitoring.WebApi/Microsoft.Diagnostics.Monitoring.WebApi.csproj index 5c39085284d..f69275b4960 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Microsoft.Diagnostics.Monitoring.WebApi.csproj +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Microsoft.Diagnostics.Monitoring.WebApi.csproj @@ -36,6 +36,7 @@ + diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/EgressOperationStatus.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/EgressOperationStatus.cs new file mode 100644 index 00000000000..01e57eb1579 --- /dev/null +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Models/EgressOperationStatus.cs @@ -0,0 +1,65 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text.Json.Serialization; +using System.Threading.Tasks; + +#if UNITTEST +namespace Microsoft.Diagnostics.Monitoring.UnitTests.Models +#else +namespace Microsoft.Diagnostics.Monitoring.WebApi.Models +#endif +{ + /// + /// Represents a partial model when enumerating all operations. + /// + public class OperationSummary + { + [JsonPropertyName("operationId")] + public Guid OperationId { get; set; } + + [JsonPropertyName("createdDateTime")] + public DateTime CreatedDateTime { get; set; } + + [JsonPropertyName("status")] + public OperationState Status { get; set; } + } + + /// + /// Represents the state of a long running operation. Used for all types of results, including successes and failures. + /// + public class OperationStatus : OperationSummary + { + //CONSIDER Should we also have a retry-after? Not sure we can produce meaningful values for this. + + //Success cases + [JsonPropertyName("resourceLocation")] + public string ResourceLocation { get; set; } + + //Failure cases + [JsonPropertyName("error")] + public OperationError Error { get; set; } + } + + [JsonConverter(typeof(JsonStringEnumConverter))] + public enum OperationState + { + Running, + Succeeded, + Failed, + Cancelled + } + + public class OperationError + { + [JsonPropertyName("code")] + public string Code { get; set; } + + [JsonPropertyName("message")] + public string Message { get; set; } + } +} diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/EgressStreamResult.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressOperation.cs similarity index 62% rename from src/Microsoft.Diagnostics.Monitoring.WebApi/EgressStreamResult.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressOperation.cs index 0af1c3ec1be..4b7746f9247 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/EgressStreamResult.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressOperation.cs @@ -13,34 +13,34 @@ namespace Microsoft.Diagnostics.Monitoring.WebApi { - internal class EgressStreamResult : ActionResult + internal class EgressOperation : IEgressOperation { private readonly Func> _egress; private readonly KeyValueLogScope _scope; - public EgressStreamResult(Func> action, string endpointName, string artifactName, IEndpointInfo source, string contentType, KeyValueLogScope scope) + public EgressOperation(Func> action, string endpointName, string artifactName, IEndpointInfo source, string contentType, KeyValueLogScope scope) { _egress = (service, token) => service.EgressAsync(endpointName, action, artifactName, contentType, source, token); _scope = scope; } - public EgressStreamResult(Func action, string endpointName, string artifactName, IEndpointInfo source, string contentType, KeyValueLogScope scope) + public EgressOperation(Func action, string endpointName, string artifactName, IEndpointInfo source, string contentType, KeyValueLogScope scope) { _egress = (service, token) => service.EgressAsync(endpointName, action, artifactName, contentType, source, token); _scope = scope; } - public override async Task ExecuteResultAsync(ActionContext context) + public async Task> ExecuteAsync(IServiceProvider serviceProvider, CancellationToken token) { - ILogger logger = context.HttpContext.RequestServices + ILogger logger = serviceProvider .GetRequiredService() - .CreateLogger(); + .CreateLogger(); using var _ = logger.BeginScope(_scope); - await context.InvokeAsync(async (token) => + return await ExecutionHelper.InvokeAsync(async (token) => { - IEgressService egressService = context.HttpContext.RequestServices + IEgressService egressService = serviceProvider .GetRequiredService(); EgressResult egressResult = await _egress(egressService, token); @@ -52,12 +52,8 @@ await context.InvokeAsync(async (token) => // automatically generated by the REST API and the caller of the endpoint might not know // the specific configuration information for the egress provider, this value allows the // caller to more easily find the artifact after egress has completed. - IDictionary data = new Dictionary(StringComparer.Ordinal); - data.Add(egressResult.Name, egressResult.Value); - - ActionResult jsonResult = new JsonResult(data); - await jsonResult.ExecuteResultAsync(context); - }, logger); + return ExecutionResult.Succeeded(egressResult); + }, logger, token); } } } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressOperationQueue.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressOperationQueue.cs new file mode 100644 index 00000000000..f381e4aa3fa --- /dev/null +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressOperationQueue.cs @@ -0,0 +1,54 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Channels; +using System.Threading.Tasks; + +namespace Microsoft.Diagnostics.Monitoring.WebApi +{ + internal sealed class EgressOperationQueue : IDisposable + { + private readonly Channel _queue; + private bool _disposed; + + public EgressOperationQueue() + { + var options = new BoundedChannelOptions(256) + { + FullMode = BoundedChannelFullMode.Wait + }; + _queue = Channel.CreateBounded(options); + } + + public ValueTask EnqueueAsync( + EgressRequest workItem) + { + if (workItem == null) + { + throw new ArgumentNullException(nameof(workItem)); + } + + return _queue.Writer.WriteAsync(workItem); + } + + public ValueTask DequeueAsync( + CancellationToken cancellationToken) + { + return _queue.Reader.ReadAsync(cancellationToken); + } + + public void Dispose() + { + if (!_disposed) + { + _disposed = true; + _queue.Writer.Complete(); + } + } + } +} diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressOperationService.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressOperationService.cs new file mode 100644 index 00000000000..39d5f4decf1 --- /dev/null +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressOperationService.cs @@ -0,0 +1,58 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Extensions.Hosting; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.Diagnostics.Monitoring.WebApi +{ + internal sealed class EgressOperationService : BackgroundService + { + private EgressOperationQueue _queue; + private IServiceProvider _serviceProvider; + private EgressOperationStore _operationsStore; + + public EgressOperationService(EgressOperationQueue taskQueue, + IServiceProvider serviceProvider, + EgressOperationStore operationStore) + { + _queue = taskQueue; + _serviceProvider = serviceProvider; + _operationsStore = operationStore; + } + + protected override async Task ExecuteAsync(CancellationToken stoppingToken) + { + while (!stoppingToken.IsCancellationRequested) + { + EgressRequest egressRequest = await _queue.DequeueAsync(stoppingToken); + + //Note we do not await these tasks, but we do limit how many can be executed at the same time + _ = Task.Run(() => ExecuteEgressOperation(egressRequest, stoppingToken), stoppingToken); + } + } + + private async Task ExecuteEgressOperation(EgressRequest egressRequest, CancellationToken stoppingToken) + { + //We have two stopping tokens, one per item that can be triggered via Delete + //and if we are stopping the service + using (CancellationTokenSource linkedTokenSource = + CancellationTokenSource.CreateLinkedTokenSource(egressRequest.CancellationTokenSource.Token, stoppingToken)) + { + CancellationToken token = linkedTokenSource.Token; + token.ThrowIfCancellationRequested(); + + var result = await egressRequest.EgressOperation.ExecuteAsync(_serviceProvider, token); + + //It is possible that this operation never completes, due to infinite duration operations. + + _operationsStore.CompleteOperation(egressRequest.OperationId, result); + } + } + } +} diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressOperationStore.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressOperationStore.cs new file mode 100644 index 00000000000..e9b653db0e8 --- /dev/null +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressOperationStore.cs @@ -0,0 +1,166 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Threading; +using System.Threading.Channels; +using System.Threading.Tasks; + +namespace Microsoft.Diagnostics.Monitoring.WebApi +{ + internal sealed class EgressOperationStore + { + private sealed class EgressEntry + { + public ExecutionResult ExecutionResult { get; set; } + public Models.OperationState State { get; set;} + + public EgressRequest EgressRequest { get; set; } + + public DateTime CreatedDateTime { get; } = DateTime.UtcNow; + + public Guid OperationId { get; set; } + } + + private readonly Dictionary _requests = new(); + private readonly EgressOperationQueue _taskQueue; + private readonly RequestLimitTracker _requestLimits; + + public EgressOperationStore(EgressOperationQueue queue, RequestLimitTracker requestLimits) + { + _taskQueue = queue; + _requestLimits = requestLimits; + } + + public async Task AddOperation(IEgressOperation egressOperation, string limitKey) + { + Guid operationId = Guid.NewGuid(); + + IDisposable limitTracker = _requestLimits.Increment(limitKey, out bool allowOperation); + //We increment the limit here, and decrement it once the operation is cancelled or completed. + //We do this here so that we can provide immediate errors if the user queues up too many operations. + + if (!allowOperation) + { + limitTracker.Dispose(); + throw new TooManyRequestsException(); + } + + var request = new EgressRequest(operationId, egressOperation, limitTracker); + lock (_requests) + { + //Add operation object to central table. + _requests.Add(operationId, + new EgressEntry + { + State = Models.OperationState.Running, + EgressRequest = request, + OperationId = operationId + }); + } + + //Kick off work to attempt egress + await _taskQueue.EnqueueAsync(request); + + return operationId; + } + + public void CancelOperation(Guid operationId) + { + lock (_requests) + { + if (!_requests.TryGetValue(operationId, out EgressEntry entry)) + { + throw new InvalidOperationException(Strings.ErrorMessage_OperationNotFound); + } + + if (entry.State != Models.OperationState.Running) + { + throw new InvalidOperationException(Strings.ErrorMessage_OperationNotRunning); + } + + entry.State = Models.OperationState.Cancelled; + entry.EgressRequest.CancellationTokenSource.Cancel(); + entry.EgressRequest.Dispose(); + } + } + + public void CompleteOperation(Guid operationId, ExecutionResult result) + { + lock (_requests) + { + if (!_requests.TryGetValue(operationId, out EgressEntry entry)) + { + throw new InvalidOperationException(Strings.ErrorMessage_OperationNotFound); + } + if (entry.State != Models.OperationState.Running) + { + throw new InvalidOperationException(Strings.ErrorMessage_OperationNotRunning); + } + + entry.ExecutionResult = result; + entry.EgressRequest.Dispose(); + + if (entry.ExecutionResult.ProblemDetails == null) + { + entry.State = Models.OperationState.Succeeded; + } + else + { + entry.State = Models.OperationState.Failed; + } + } + } + + public IEnumerable GetOperations() + { + lock (_requests) + { + return _requests.Select((kvp) => new Models.OperationSummary + { + OperationId = kvp.Key, + CreatedDateTime = kvp.Value.CreatedDateTime, + Status = kvp.Value.State + }).ToList(); + } + } + + public Models.OperationStatus GetOperationStatus(Guid operationId) + { + lock (_requests) + { + if (!_requests.TryGetValue(operationId, out EgressEntry entry)) + { + throw new InvalidOperationException(Strings.ErrorMessage_OperationNotFound); + } + + var status = new Models.OperationStatus() + { + OperationId = entry.EgressRequest.OperationId, + Status = entry.State, + CreatedDateTime = entry.CreatedDateTime, + }; + + if (entry.State == Models.OperationState.Succeeded) + { + status.ResourceLocation = entry.ExecutionResult.Result.Value; + } + else if (entry.State == Models.OperationState.Failed) + { + status.Error = new Models.OperationError + { + Code = entry.ExecutionResult.ProblemDetails.Status?.ToString(CultureInfo.InvariantCulture), + Message = entry.ExecutionResult.ProblemDetails.Detail + }; + } + + return status; + } + } + } +} diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressRequest.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressRequest.cs new file mode 100644 index 00000000000..3ff5d407c06 --- /dev/null +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressRequest.cs @@ -0,0 +1,45 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.Diagnostics.Monitoring.WebApi +{ + /// + /// Represents the execution of an egress operation as well as its associated cancellation + /// and operation id. This is mainly used to transfer data between controllers and the background egress service. + /// + internal sealed class EgressRequest : IDisposable + { + private bool _disposed; + private IDisposable _limitTracker; + + public EgressRequest(Guid operationId, IEgressOperation egressOperation, IDisposable limitTracker) + { + OperationId = operationId; + EgressOperation = egressOperation; + _limitTracker = limitTracker; + } + + public CancellationTokenSource CancellationTokenSource { get; } = new(); + + public Guid OperationId { get; } + + public IEgressOperation EgressOperation { get; } + + public void Dispose() + { + if (!_disposed) + { + _disposed = true; + _limitTracker.Dispose(); + CancellationTokenSource.Dispose(); + } + } + } +} diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/EgressResult.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressResult.cs similarity index 76% rename from src/Microsoft.Diagnostics.Monitoring.WebApi/EgressResult.cs rename to src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressResult.cs index 71a9fcd2c8f..57d30afe16e 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/EgressResult.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/EgressResult.cs @@ -6,14 +6,11 @@ namespace Microsoft.Diagnostics.Monitoring.WebApi { internal struct EgressResult { - public EgressResult(string name, string value) + public EgressResult(string value) { - Name = name; Value = value; } - public string Name { get; } - public string Value { get; } } } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/IEgressOperation.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/IEgressOperation.cs new file mode 100644 index 00000000000..948cba629c0 --- /dev/null +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/IEgressOperation.cs @@ -0,0 +1,17 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.Diagnostics.Monitoring.WebApi +{ + internal interface IEgressOperation + { + Task> ExecuteAsync(IServiceProvider serviceProvider, CancellationToken token); + } +} diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/OperationExtensions.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/OperationExtensions.cs new file mode 100644 index 00000000000..5be176d6898 --- /dev/null +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/OperationExtensions.cs @@ -0,0 +1,23 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Extensions.DependencyInjection; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Microsoft.Diagnostics.Monitoring.WebApi +{ + internal static class OperationExtensions + { + public static IServiceCollection ConfigureOperationStore(this IServiceCollection services) + { + services.AddSingleton(); + services.AddSingleton(); + services.AddHostedService(); + return services; + } + } +} diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/TooManyRequestsException.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/TooManyRequestsException.cs new file mode 100644 index 00000000000..1cf54bdece0 --- /dev/null +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Operation/TooManyRequestsException.cs @@ -0,0 +1,18 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; + +namespace Microsoft.Diagnostics.Monitoring.WebApi +{ + internal sealed class TooManyRequestsException : MonitoringException + { + public TooManyRequestsException() : base(Strings.ErrorMessage_TooManyRequests) + { + } + } +} diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/RequestThrottling/RequestLimitAttribute.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/RequestThrottling/RequestLimitAttribute.cs index 2eb7c281856..880b4866e45 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/RequestThrottling/RequestLimitAttribute.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/RequestThrottling/RequestLimitAttribute.cs @@ -12,6 +12,6 @@ namespace Microsoft.Diagnostics.Monitoring.WebApi [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] internal sealed class RequestLimitAttribute : Attribute { - public int MaxConcurrency { get; set; } = 1; + public string LimitKey { get; set; } } } diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/RequestThrottling/RequestLimitTracker.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/RequestThrottling/RequestLimitTracker.cs new file mode 100644 index 00000000000..14f6d9698d3 --- /dev/null +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/RequestThrottling/RequestLimitTracker.cs @@ -0,0 +1,61 @@ +using Microsoft.Extensions.Logging; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.Diagnostics.Monitoring.WebApi +{ + internal sealed class RequestLimitTracker + { + private sealed class RequestCount : IDisposable + { + private int _count = 0; + public int Increment() => Interlocked.Increment(ref _count); + + public void Decrement() => Interlocked.Decrement(ref _count); + + public void Dispose() => Decrement(); + } + + private readonly Dictionary _requestLimitTable = new(); + private readonly ConcurrentDictionary _requestCounts = new(); + private readonly ILogger _logger; + + public RequestLimitTracker(ILogger logger) + { + //CONSIDER Should we have configuration for these? + + _requestLimitTable.Add(Controllers.DiagController.ArtifactType_Dump, 1); + _requestLimitTable.Add(Controllers.DiagController.ArtifactType_GCDump, 1); + _requestLimitTable.Add(Controllers.DiagController.ArtifactType_Logs, 3); + _requestLimitTable.Add(Controllers.DiagController.ArtifactType_Trace, 3); + + _logger = logger; + } + + public IDisposable Increment(string key, out bool allowOperation) + { + if (!_requestLimitTable.TryGetValue(key, out int maxConcurrency)) + { + throw new InvalidOperationException(string.Format(System.Globalization.CultureInfo.CurrentCulture, Strings.ErrorMessage_UnexpectedLimitKey, key)); + } + + RequestCount requestCount = _requestCounts.GetOrAdd(key, (_) => new RequestCount()); + int newRequestCount = requestCount.Increment(); + if (newRequestCount > maxConcurrency) + { + _logger.ThrottledEndpoint(maxConcurrency, newRequestCount); + allowOperation = false; + } + else + { + allowOperation = true; + } + + return requestCount; + } + } +} diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Strings.Designer.cs b/src/Microsoft.Diagnostics.Monitoring.WebApi/Strings.Designer.cs index d3a73e00c0b..0e66532db81 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Strings.Designer.cs +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Strings.Designer.cs @@ -114,6 +114,24 @@ internal static string ErrorMessage_NoTargetProcess { } } + /// + /// Looks up a localized string similar to Operation not found.. + /// + internal static string ErrorMessage_OperationNotFound { + get { + return ResourceManager.GetString("ErrorMessage_OperationNotFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Operation is not running.. + /// + internal static string ErrorMessage_OperationNotRunning { + get { + return ResourceManager.GetString("ErrorMessage_OperationNotRunning", resourceCulture); + } + } + /// /// Looks up a localized string similar to Unable to enumerate processes.. /// @@ -123,6 +141,24 @@ internal static string ErrorMessage_ProcessEnumeratuinFailed { } } + /// + /// Looks up a localized string similar to Rate limit reached.. + /// + internal static string ErrorMessage_TooManyRequests { + get { + return ResourceManager.GetString("ErrorMessage_TooManyRequests", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Unexpected limit key: '{0}'. + /// + internal static string ErrorMessage_UnexpectedLimitKey { + get { + return ResourceManager.GetString("ErrorMessage_UnexpectedLimitKey", resourceCulture); + } + } + /// /// Looks up a localized string similar to Unexpected {0}: {1}. /// diff --git a/src/Microsoft.Diagnostics.Monitoring.WebApi/Strings.resx b/src/Microsoft.Diagnostics.Monitoring.WebApi/Strings.resx index e2e73a1afd1..ed4a62eb93e 100644 --- a/src/Microsoft.Diagnostics.Monitoring.WebApi/Strings.resx +++ b/src/Microsoft.Diagnostics.Monitoring.WebApi/Strings.resx @@ -141,10 +141,25 @@ Unable to discover a target process. Gets a string similar to "Unable to discover a target process.". + + Operation not found. + + + Operation is not running. + Unable to enumerate processes. Gets a string similar to "Unable to enumerate processes.". + + Rate limit reached. + + + Unexpected limit key: '{0}' + Gets the format string for unexpected limit keys. +1 Format Parameter: +1. Unlocalized name of artifact type + Unexpected {0}: {1} Gets the format string for unexpected type provided. diff --git a/src/Tests/Directory.Build.props b/src/Tests/Directory.Build.props deleted file mode 100644 index d472ddd2de3..00000000000 --- a/src/Tests/Directory.Build.props +++ /dev/null @@ -1,6 +0,0 @@ - - - - $(MSBuildThisFileDirectory)test.runsettings - - diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.OpenApiGen.UnitTests/OpenApiGeneratorTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.OpenApiGen.UnitTests/OpenApiGeneratorTests.cs index 55397ffce73..4315d78bef9 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.OpenApiGen.UnitTests/OpenApiGeneratorTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.OpenApiGen.UnitTests/OpenApiGeneratorTests.cs @@ -70,6 +70,8 @@ public async Task BaselineDifferenceTest() break; } } + + _outputHelper.WriteLine(generatedContent); } Assert.True(equal, "The generated OpenAPI description is different than the documented baseline."); } diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.OpenApiGen/TooManyRequestsResponseDocumentFilter.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.OpenApiGen/TooManyRequestsResponseDocumentFilter.cs index 751719e4ae0..0903a0d755f 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.OpenApiGen/TooManyRequestsResponseDocumentFilter.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.OpenApiGen/TooManyRequestsResponseDocumentFilter.cs @@ -2,6 +2,8 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using Microsoft.AspNetCore.Mvc; +using Microsoft.Diagnostics.Monitoring.WebApi; using Microsoft.OpenApi.Models; using Swashbuckle.AspNetCore.SwaggerGen; @@ -18,6 +20,20 @@ public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) OpenApiResponse tooManyRequests = new(); tooManyRequests.Description = "TooManyRequests"; + tooManyRequests.Content.Add( + ContentTypes.ApplicationProblemJson, + new OpenApiMediaType() + { + Schema = new OpenApiSchema() + { + Reference = new OpenApiReference() + { + Id = typeof(ProblemDetails).Name, + Type = ReferenceType.Schema + } + } + }); + swaggerDoc.Components.Responses.Add( ResponseNames.TooManyRequestsResponse, tooManyRequests); diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.OpenApiGen/TooManyRequestsResponseOperationFilter.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.OpenApiGen/TooManyRequestsResponseOperationFilter.cs index 92318375595..21fd6ed54d5 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.OpenApiGen/TooManyRequestsResponseOperationFilter.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.OpenApiGen/TooManyRequestsResponseOperationFilter.cs @@ -14,14 +14,18 @@ internal sealed class TooManyRequestsResponseOperationFilter : IOperationFilter { public void Apply(OpenApiOperation operation, OperationFilterContext context) { - if (operation.Responses.TryGetValue(StatusCodeStrings.Status429TooManyRequests, out OpenApiResponse tooManyRequests)) + if (operation.Responses.Remove(StatusCodeStrings.Status429TooManyRequests)) { - tooManyRequests.Content.Clear(); - tooManyRequests.Reference = new OpenApiReference() - { - Id = ResponseNames.TooManyRequestsResponse, - Type = ReferenceType.Response - }; + operation.Responses.Add( + StatusCodeStrings.Status429TooManyRequests, + new OpenApiResponse() + { + Reference = new OpenApiReference() + { + Id = ResponseNames.TooManyRequestsResponse, + Type = ReferenceType.Response + } + }); } } } diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressTests.cs new file mode 100644 index 00000000000..775abd0c91e --- /dev/null +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressTests.cs @@ -0,0 +1,270 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Diagnostics.Monitoring.TestCommon; +using Microsoft.Diagnostics.Monitoring.UnitTests.Fixtures; +using Microsoft.Diagnostics.Monitoring.UnitTests.HttpApi; +using Microsoft.Diagnostics.Monitoring.UnitTests.Models; +using Microsoft.Diagnostics.Monitoring.UnitTests.Options; +using Microsoft.Diagnostics.Monitoring.UnitTests.Runners; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.FileFormats; +using Microsoft.FileFormats.ELF; +using Microsoft.FileFormats.MachO; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; +using System.Net.Http; +using System.Reflection; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.Diagnostics.Monitoring.UnitTests +{ + [Collection(DefaultCollectionFixture.Name)] + public class EgressTests : IDisposable + { + private readonly IHttpClientFactory _httpClientFactory; + private readonly ITestOutputHelper _outputHelper; + private readonly DirectoryInfo _tempEgressPath; + + private const string FileProviderName = "files"; + + + public EgressTests(ITestOutputHelper outputHelper, ServiceProviderFixture serviceProviderFixture) + { + _httpClientFactory = serviceProviderFixture.ServiceProvider.GetService(); + _outputHelper = outputHelper; + _tempEgressPath = Directory.CreateDirectory(Path.Combine(Path.GetTempPath(), "Egress", Guid.NewGuid().ToString())); + } + + [Fact] + public async Task EgressTraceTest() + { + await ScenarioRunner.SingleTarget( + _outputHelper, + _httpClientFactory, + DiagnosticPortConnectionMode.Connect, + TestAppScenarios.AsyncWait.Name, + appValidate: async (appRunner, apiClient) => + { + OperationResponse response = await apiClient.EgressTraceAsync(appRunner.ProcessId, durationSeconds: 5, FileProviderName); + Assert.Equal(HttpStatusCode.Accepted, response.StatusCode); + + OperationStatusResponse operationResult = await apiClient.PollOperationToCompletion(response.OperationUri); + Assert.Equal(HttpStatusCode.Created, operationResult.StatusCode); + Assert.Equal(OperationState.Succeeded, operationResult.OperationStatus.Status); + Assert.True(File.Exists(operationResult.OperationStatus.ResourceLocation)); + + await appRunner.SendCommandAsync(TestAppScenarios.AsyncWait.Commands.Continue); + }, + configureTool: (toolRunner) => + { + toolRunner.WriteKeyPerValueConfiguration(new RootOptions().AddFileSystemEgress(FileProviderName, _tempEgressPath.FullName)); + }); + } + + [Fact] + public async Task EgressCancelTest() + { + await ScenarioRunner.SingleTarget( + _outputHelper, + _httpClientFactory, + DiagnosticPortConnectionMode.Connect, + TestAppScenarios.AsyncWait.Name, + appValidate: async (appRunner, apiClient) => + { + OperationResponse response = await apiClient.EgressTraceAsync(appRunner.ProcessId, durationSeconds: -1, FileProviderName); + Assert.Equal(HttpStatusCode.Accepted, response.StatusCode); + + OperationStatusResponse operationResult = await apiClient.GetOperationStatus(response.OperationUri); + Assert.Equal(HttpStatusCode.OK, operationResult.StatusCode); + Assert.True(operationResult.OperationStatus.Status == OperationState.Running); + + HttpStatusCode deleteStatus = await apiClient.CancelEgressOperation(response.OperationUri); + Assert.Equal(HttpStatusCode.OK, deleteStatus); + + operationResult = await apiClient.GetOperationStatus(response.OperationUri); + Assert.Equal(HttpStatusCode.OK, operationResult.StatusCode); + Assert.Equal(OperationState.Cancelled, operationResult.OperationStatus.Status); + + await appRunner.SendCommandAsync(TestAppScenarios.AsyncWait.Commands.Continue); + }, + configureTool: (toolRunner) => + { + toolRunner.WriteKeyPerValueConfiguration(new RootOptions().AddFileSystemEgress(FileProviderName, _tempEgressPath.FullName)); + }); + } + + [Fact] + public async Task EgressListTest() + { + await ScenarioRunner.SingleTarget( + _outputHelper, + _httpClientFactory, + DiagnosticPortConnectionMode.Connect, + TestAppScenarios.AsyncWait.Name, + appValidate: async (appRunner, apiClient) => + { + OperationResponse response1 = await EgressTraceWithDelay(apiClient, appRunner.ProcessId); + OperationResponse response2 = await EgressTraceWithDelay(apiClient, appRunner.ProcessId, delay: false); + await CancelEgressOperation(apiClient, response2); + + List result = await apiClient.GetOperations(); + Assert.Equal(2, result.Count); + + OperationStatusResponse status1 = await apiClient.GetOperationStatus(response1.OperationUri); + OperationSummary summary1 = result.First(os => os.OperationId == status1.OperationStatus.OperationId); + ValidateOperation(status1.OperationStatus, summary1); + + OperationStatusResponse status2 = await apiClient.GetOperationStatus(response2.OperationUri); + OperationSummary summary2 = result.First(os => os.OperationId == status2.OperationStatus.OperationId); + ValidateOperation(status2.OperationStatus, summary2); + + await appRunner.SendCommandAsync(TestAppScenarios.AsyncWait.Commands.Continue); + }, + configureTool: (toolRunner) => + { + toolRunner.WriteKeyPerValueConfiguration(new RootOptions().AddFileSystemEgress(FileProviderName, _tempEgressPath.FullName)); + }); + } + + [Fact] + public async Task ConcurrencyLimitTest() + { + await ScenarioRunner.SingleTarget( + _outputHelper, + _httpClientFactory, + DiagnosticPortConnectionMode.Connect, + TestAppScenarios.AsyncWait.Name, + appValidate: async (appRunner, apiClient) => + { + OperationResponse response1 = await EgressTraceWithDelay(apiClient, appRunner.ProcessId); + OperationResponse response2 = await EgressTraceWithDelay(apiClient, appRunner.ProcessId); + OperationResponse response3 = await EgressTraceWithDelay(apiClient, appRunner.ProcessId); + + ValidationProblemDetailsException ex = await Assert.ThrowsAsync(() => EgressTraceWithDelay(apiClient, appRunner.ProcessId)); + Assert.Equal(HttpStatusCode.TooManyRequests, ex.StatusCode); + Assert.Equal((int)HttpStatusCode.TooManyRequests, ex.Details.Status.GetValueOrDefault()); + + + await CancelEgressOperation(apiClient, response1); + await CancelEgressOperation(apiClient, response2); + + OperationResponse response4 = await EgressTraceWithDelay(apiClient, appRunner.ProcessId, delay: false); + + await CancelEgressOperation(apiClient, response3); + await CancelEgressOperation(apiClient, response4); + + await appRunner.SendCommandAsync(TestAppScenarios.AsyncWait.Commands.Continue); + }, + configureTool: (toolRunner) => + { + toolRunner.WriteKeyPerValueConfiguration(new RootOptions().AddFileSystemEgress(FileProviderName, _tempEgressPath.FullName)); + }); + } + + [Fact] + public async Task SharedConcurrencyLimitTest() + { + await ScenarioRunner.SingleTarget( + _outputHelper, + _httpClientFactory, + DiagnosticPortConnectionMode.Connect, + TestAppScenarios.AsyncWait.Name, + appValidate: async (appRunner, apiClient) => + { + OperationResponse response1 = await EgressTraceWithDelay(apiClient, appRunner.ProcessId); + OperationResponse response3 = await EgressTraceWithDelay(apiClient, appRunner.ProcessId); + using HttpResponseMessage traceDirect1 = await TraceWithDelay(apiClient, appRunner.ProcessId); + Assert.Equal(HttpStatusCode.OK, traceDirect1.StatusCode); + + ValidationProblemDetailsException ex = await Assert.ThrowsAsync(() => EgressTraceWithDelay(apiClient, appRunner.ProcessId, delay: false)); + Assert.Equal(HttpStatusCode.TooManyRequests, ex.StatusCode); + + using HttpResponseMessage traceDirect = await TraceWithDelay(apiClient, appRunner.ProcessId, delay: false); + Assert.Equal(HttpStatusCode.TooManyRequests, traceDirect.StatusCode); + + //Validate that the failure from a direct call (handled by middleware) + //matches the failure produces by egress operations (handled by the Mvc ActionResult stack) + using HttpResponseMessage egressDirect = await EgressDirect(apiClient, appRunner.ProcessId); + Assert.Equal(HttpStatusCode.TooManyRequests, egressDirect.StatusCode); + Assert.Equal(await egressDirect.Content.ReadAsStringAsync(), await traceDirect.Content.ReadAsStringAsync()); + + await CancelEgressOperation(apiClient, response1); + OperationResponse response4 = await EgressTraceWithDelay(apiClient, appRunner.ProcessId, delay: false); + + await CancelEgressOperation(apiClient, response3); + await CancelEgressOperation(apiClient, response4); + + await appRunner.SendCommandAsync(TestAppScenarios.AsyncWait.Commands.Continue); + }, + configureTool: (toolRunner) => + { + toolRunner.WriteKeyPerValueConfiguration(new RootOptions().AddFileSystemEgress(FileProviderName, _tempEgressPath.FullName)); + }); + } + + private async Task TraceWithDelay(ApiClient client, int processId, bool delay = true) + { + HttpResponseMessage message = await client.ApiCall(FormattableString.Invariant($"/trace?pid={processId}&durationSeconds=-1")); + if (delay) + { + await Task.Delay(TimeSpan.FromSeconds(1)); + } + return message; + } + + private Task EgressDirect(ApiClient client, int processId) + { + return client.ApiCall(FormattableString.Invariant($"/trace?pid={processId}&egressProvider={FileProviderName}")); + } + + private async Task EgressTraceWithDelay(ApiClient apiClient, int processId, bool delay = true) + { + try + { + OperationResponse response = await apiClient.EgressTraceAsync(processId, durationSeconds: -1, FileProviderName); + return response; + } + finally + { + if (delay) + { + //Wait 1 second to make sure the file names do not collide + await Task.Delay(TimeSpan.FromSeconds(1)); + } + } + } + + private async Task CancelEgressOperation(ApiClient apiClient, OperationResponse response) + { + HttpStatusCode deleteStatus = await apiClient.CancelEgressOperation(response.OperationUri); + Assert.Equal(HttpStatusCode.OK, deleteStatus); + } + + private void ValidateOperation(OperationStatus expected, OperationSummary summary) + { + Assert.Equal(expected.OperationId, summary.OperationId); + Assert.Equal(expected.Status, summary.Status); + Assert.Equal(expected.CreatedDateTime, summary.CreatedDateTime); + } + + public void Dispose() + { + try + { + _tempEgressPath?.Delete(recursive: true); + } + catch + { + } + } + } +} \ No newline at end of file diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClient.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClient.cs index 5448b201241..5fe9b3a4f2f 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClient.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClient.cs @@ -304,6 +304,98 @@ public async Task GetMetricsAsync(CancellationToken token) throw await CreateUnexpectedStatusCodeExceptionAsync(response).ConfigureAwait(false); } + public async Task ApiCall(string routeAndQuery, CancellationToken token) + { + using HttpRequestMessage request = new(HttpMethod.Get, routeAndQuery); + HttpResponseMessage response = await SendAndLogAsync(request, HttpCompletionOption.ResponseHeadersRead, token).ConfigureAwait(false); + return response; + } + + public async Task EgressTraceAsync(int processId, int durationSeconds, string egressProvider, CancellationToken token) + { + string uri = FormattableString.Invariant($"/trace?pid={processId}&egressProvider={egressProvider}&durationSeconds={durationSeconds}"); + using HttpRequestMessage request = new(HttpMethod.Get, uri); + using HttpResponseMessage response = await SendAndLogAsync(request, HttpCompletionOption.ResponseContentRead, token).ConfigureAwait(false); + + switch (response.StatusCode) + { + case HttpStatusCode.Accepted: + return new OperationResponse(response.StatusCode, response.Headers.Location); + case HttpStatusCode.BadRequest: + case HttpStatusCode.TooManyRequests: + ValidateContentType(response, ContentTypes.ApplicationProblemJson); + throw await CreateValidationProblemDetailsExceptionAsync(response).ConfigureAwait(false); + case HttpStatusCode.Unauthorized: + ThrowIfNotSuccess(response); + break; + } + + throw await CreateUnexpectedStatusCodeExceptionAsync(response).ConfigureAwait(false); + } + + public async Task> GetOperations(CancellationToken token) + { + using HttpRequestMessage request = new(HttpMethod.Get, "/operations"); + using HttpResponseMessage response = await SendAndLogAsync(request, HttpCompletionOption.ResponseContentRead, token).ConfigureAwait(false); + + switch (response.StatusCode) + { + case HttpStatusCode.OK: + ValidateContentType(response, ContentTypes.ApplicationJson); + return await ReadContentEnumerableAsync(response).ConfigureAwait(false); + case HttpStatusCode.BadRequest: + ValidateContentType(response, ContentTypes.ApplicationProblemJson); + throw await CreateValidationProblemDetailsExceptionAsync(response).ConfigureAwait(false); + case HttpStatusCode.Unauthorized: + ThrowIfNotSuccess(response); + break; + } + + throw await CreateUnexpectedStatusCodeExceptionAsync(response).ConfigureAwait(false); + } + + public async Task GetOperationStatus(Uri operation, CancellationToken token) + { + using HttpRequestMessage request = new(HttpMethod.Get, operation.ToString()); + using HttpResponseMessage response = await SendAndLogAsync(request, HttpCompletionOption.ResponseContentRead, token).ConfigureAwait(false); + + switch (response.StatusCode) + { + case HttpStatusCode.Created: + case HttpStatusCode.OK: + ValidateContentType(response, ContentTypes.ApplicationJson); + return new OperationStatusResponse(response.StatusCode, await ReadContentAsync(response).ConfigureAwait(false)); + case HttpStatusCode.BadRequest: + ValidateContentType(response, ContentTypes.ApplicationProblemJson); + throw await CreateValidationProblemDetailsExceptionAsync(response).ConfigureAwait(false); + case HttpStatusCode.Unauthorized: + ThrowIfNotSuccess(response); + break; + } + + throw await CreateUnexpectedStatusCodeExceptionAsync(response).ConfigureAwait(false); + } + + public async Task CancelEgressOperation(Uri operation, CancellationToken token) + { + using HttpRequestMessage request = new(HttpMethod.Delete, operation.ToString()); + using HttpResponseMessage response = await SendAndLogAsync(request, HttpCompletionOption.ResponseContentRead, token).ConfigureAwait(false); + + switch (response.StatusCode) + { + case HttpStatusCode.OK: + return response.StatusCode; + case HttpStatusCode.BadRequest: + ValidateContentType(response, ContentTypes.ApplicationProblemJson); + throw await CreateValidationProblemDetailsExceptionAsync(response).ConfigureAwait(false); + case HttpStatusCode.Unauthorized: + ThrowIfNotSuccess(response); + break; + } + + throw await CreateUnexpectedStatusCodeExceptionAsync(response).ConfigureAwait(false); + } + private static async Task ReadContentAsync(HttpResponseMessage responseMessage) { using Stream contentStream = await responseMessage.Content.ReadAsStreamAsync().ConfigureAwait(false); diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClientExtensions.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClientExtensions.cs index ea4b80eb134..385e82f78c2 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClientExtensions.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/ApiClientExtensions.cs @@ -9,8 +9,10 @@ using System.Collections.Generic; using System.Linq; using System.Net; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; +using Xunit; using Xunit.Abstractions; namespace Microsoft.Diagnostics.Monitoring.UnitTests.HttpApi @@ -283,5 +285,57 @@ public static async Task GetMetricsAsync(this ApiClient client, TimeSpan using CancellationTokenSource timeoutSource = new(timeout); return await client.GetMetricsAsync(timeoutSource.Token).ConfigureAwait(false); } + + public static async Task EgressTraceAsync(this ApiClient client, int processId, int durationSeconds, string egressProvider) + { + using CancellationTokenSource timeoutSource = new(TestTimeouts.HttpApi); + return await client.EgressTraceAsync(processId, durationSeconds, egressProvider, timeoutSource.Token).ConfigureAwait(false); + } + + public static async Task GetOperationStatus(this ApiClient client, Uri operation) + { + using CancellationTokenSource timeoutSource = new(TestTimeouts.HttpApi); + return await client.GetOperationStatus(operation, timeoutSource.Token).ConfigureAwait(false); + } + + public static async Task> GetOperations(this ApiClient client) + { + using CancellationTokenSource timeoutSource = new(TestTimeouts.HttpApi); + return await client.GetOperations(timeoutSource.Token).ConfigureAwait(false); + } + + public static async Task CancelEgressOperation(this ApiClient client, Uri operation) + { + using CancellationTokenSource timeoutSource = new(TestTimeouts.HttpApi); + return await client.CancelEgressOperation(operation, timeoutSource.Token).ConfigureAwait(false); + } + + public static async Task ApiCall(this ApiClient client, string routeAndQuery) + { + using CancellationTokenSource timeoutSource = new(TestTimeouts.HttpApi); + return await client.ApiCall(routeAndQuery, timeoutSource.Token).ConfigureAwait(false); + } + + public static Task PollOperationToCompletion(this ApiClient apiClient, Uri operationUrl) + { + return apiClient.PollOperationToCompletion(operationUrl, TestTimeouts.OperationTimeout); + } + + public static async Task PollOperationToCompletion(this ApiClient apiClient, Uri operationUrl, TimeSpan timeout) + { + OperationStatusResponse operationResult = await apiClient.GetOperationStatus(operationUrl).ConfigureAwait(false); + Assert.True(operationResult.StatusCode == HttpStatusCode.OK || operationResult.StatusCode == HttpStatusCode.Created); + Assert.True(operationResult.OperationStatus.Status == OperationState.Running || operationResult.OperationStatus.Status == OperationState.Succeeded); + + using CancellationTokenSource cancellationTokenSource = new(timeout); + while (operationResult.OperationStatus.Status == OperationState.Running) + { + cancellationTokenSource.Token.ThrowIfCancellationRequested(); + await Task.Delay(TimeSpan.FromSeconds(1), cancellationTokenSource.Token).ConfigureAwait(false); + operationResult = await apiClient.GetOperationStatus(operationUrl).ConfigureAwait(false); + } + + return operationResult; + } } } diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/OperationResponse.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/OperationResponse.cs new file mode 100644 index 00000000000..b66de0b4901 --- /dev/null +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/OperationResponse.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; +using System.Net; +using System.Text; + +namespace Microsoft.Diagnostics.Monitoring.UnitTests.HttpApi +{ + internal sealed class OperationResponse + { + public Uri OperationUri { get; } + + public HttpStatusCode StatusCode { get; } + + public OperationResponse(HttpStatusCode statusCode, Uri operationUri = null) + { + OperationUri = operationUri; + StatusCode = statusCode; + } + } +} diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/OperationStatusResponse.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/OperationStatusResponse.cs new file mode 100644 index 00000000000..e0861b7f060 --- /dev/null +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/HttpApi/OperationStatusResponse.cs @@ -0,0 +1,24 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using Microsoft.Diagnostics.Monitoring.UnitTests.Models; +using System; +using System.Collections.Generic; +using System.Net; + +namespace Microsoft.Diagnostics.Monitoring.UnitTests.HttpApi +{ + internal sealed class OperationStatusResponse + { + public HttpStatusCode StatusCode { get; } + + public OperationStatus OperationStatus { get; } + + public OperationStatusResponse(HttpStatusCode statusCode, OperationStatus status) + { + StatusCode = statusCode; + OperationStatus = status; + } + } +} diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj index 94abd954490..9ad719af987 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests.csproj @@ -16,6 +16,7 @@ + diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Options/OptionsExtensions.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Options/OptionsExtensions.cs index 82dffeda9e3..e4738fb0ac8 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Options/OptionsExtensions.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Options/OptionsExtensions.cs @@ -60,6 +60,24 @@ public static RootOptions UseApiKey(this RootOptions options, string algorithmNa return options; } + public static RootOptions AddFileSystemEgress(this RootOptions options, string name, string outputPath) + { + var egressProvider = new FileSystemEgressProviderOptions() + { + DirectoryPath = outputPath + }; + + options.Egress = new EgressOptions + { + FileSystem = new Dictionary() + { + { name, egressProvider } + } + }; + + return options; + } + private static void MapDictionary(IDictionary dictionary, string prefix, IDictionary map) { foreach (var key in dictionary.Keys) @@ -97,9 +115,11 @@ private static void MapObject(object obj, string prefix, IDictionary()?.PropertyName ?? property.Name; + MapValue( property.GetValue(obj), - FormattableString.Invariant($"{prefix}{property.Name}"), + FormattableString.Invariant($"{prefix}{propertyName}"), map); } } diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Runners/ScenarioRunner.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Runners/ScenarioRunner.cs index 2d187827629..5e344f6e853 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Runners/ScenarioRunner.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/Runners/ScenarioRunner.cs @@ -22,7 +22,8 @@ public static async Task SingleTarget( string scenarioName, Func appValidate, Func postAppValidate = null, - Action configureApp = null) + Action configureApp = null, + Action configureTool = null) { DiagnosticPortHelper.Generate( mode, @@ -33,6 +34,9 @@ public static async Task SingleTarget( toolRunner.ConnectionMode = mode; toolRunner.DiagnosticPortPath = diagnosticPortPath; toolRunner.DisableAuthentication = true; + + configureTool?.Invoke(toolRunner); + await toolRunner.StartAsync(); using HttpClient httpClient = await toolRunner.CreateHttpClientDefaultAddressAsync(httpClientFactory); @@ -43,10 +47,7 @@ public static async Task SingleTarget( appRunner.DiagnosticPortPath = diagnosticPortPath; appRunner.ScenarioName = scenarioName; - if (null != configureApp) - { - configureApp(appRunner); - } + configureApp?.Invoke(appRunner); await appRunner.ExecuteAsync(async () => { diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/TestTimeouts.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/TestTimeouts.cs index d303e543e34..a7c552ab847 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/TestTimeouts.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/TestTimeouts.cs @@ -25,5 +25,11 @@ internal static class TestTimeouts /// Dumps (especially full dumps) can be quite large and take a significant amount of time to transfer. /// public static readonly TimeSpan DumpTimeout = TimeSpan.FromMinutes(3); + + /// + /// Timeout for polling a long running operation to completion. + /// This may need to be adjusted for individual calls that are longer than 30 seconds. + /// + public static readonly TimeSpan OperationTimeout = TimeSpan.FromSeconds(30); } } diff --git a/src/Tests/test.runsettings b/src/Tests/test.runsettings deleted file mode 100644 index b53ad103768..00000000000 --- a/src/Tests/test.runsettings +++ /dev/null @@ -1,8 +0,0 @@ - - - - - 0 - - - \ No newline at end of file diff --git a/src/Tools/dotnet-monitor/DiagnosticsMonitorCommandHandler.cs b/src/Tools/dotnet-monitor/DiagnosticsMonitorCommandHandler.cs index 2c73b942c95..f56c77f0013 100644 --- a/src/Tools/dotnet-monitor/DiagnosticsMonitorCommandHandler.cs +++ b/src/Tools/dotnet-monitor/DiagnosticsMonitorCommandHandler.cs @@ -241,6 +241,8 @@ public static IHostBuilder CreateHostBuilder(IConsole console, string[] urls, st services.AddSingleton(); services.AddHostedService(); services.AddSingleton(); + services.AddSingleton(); + services.ConfigureOperationStore(); services.ConfigureEgress(context.Configuration); services.ConfigureMetrics(context.Configuration); services.ConfigureStorage(context.Configuration); diff --git a/src/Tools/dotnet-monitor/Egress/EgressService.cs b/src/Tools/dotnet-monitor/Egress/EgressService.cs index 3b59c9d7c20..c94e12581ec 100644 --- a/src/Tools/dotnet-monitor/Egress/EgressService.cs +++ b/src/Tools/dotnet-monitor/Egress/EgressService.cs @@ -63,7 +63,7 @@ public async Task EgressAsync(string providerName, Func EgressAsync(string providerName, Func action, string fileName, string contentType, IEndpointInfo source, CancellationToken token) @@ -74,7 +74,7 @@ public async Task EgressAsync(string providerName, Func - internal sealed class Throttling + internal sealed class RequestLimitMiddleware { - private sealed class RequestCount - { - private int _count = 0; - public int Increment() => Interlocked.Increment(ref _count); - - public void Decrement() => Interlocked.Decrement(ref _count); - } - private readonly RequestDelegate _next; - private readonly ConcurrentDictionary _requestCounts = new ConcurrentDictionary(); - private readonly ILogger _logger; - public Throttling(RequestDelegate next, ILogger logger) + private readonly RequestLimitTracker _limitTracker; + private const string EgressQuery = "egressprovider"; + + public RequestLimitMiddleware(RequestDelegate next, RequestLimitTracker requestLimitTracker) { _next = next; - _logger = logger; + _limitTracker = requestLimitTracker; } public async Task Invoke(HttpContext context) @@ -44,18 +40,26 @@ public async Task Invoke(HttpContext context) var endpoint = context.GetEndpoint(); RequestLimitAttribute requestLimit = endpoint?.Metadata.GetMetadata(); - RequestCount requestCount = null; + IDisposable incrementor = null; try { - if (requestLimit != null) + //Operations and middleware both share the same increment limits, but + //we don't want the middleware to increment the limit if the operation is doing it as well. + if ((requestLimit != null) && !context.Request.Query.ContainsKey(EgressQuery)) { - requestCount = _requestCounts.GetOrAdd(endpoint.DisplayName, (_) => new RequestCount()); - int newRequestCount = requestCount.Increment(); - if (newRequestCount > requestLimit.MaxConcurrency) + incrementor = _limitTracker.Increment(requestLimit.LimitKey, out bool allowOperation); + if (!allowOperation) { - _logger.ThrottledEndpoint(requestLimit.MaxConcurrency, newRequestCount); - context.Response.StatusCode = (int)HttpStatusCode.TooManyRequests; + + //We should report the same kind of error from Middleware and the Mvc layer. + context.Response.StatusCode = StatusCodes.Status429TooManyRequests; + context.Response.ContentType = ContentTypes.ApplicationProblemJson; + await context.Response.WriteAsync(JsonSerializer.Serialize(new ProblemDetails + { + Status = StatusCodes.Status429TooManyRequests, + Detail = Microsoft.Diagnostics.Monitoring.WebApi.Strings.ErrorMessage_TooManyRequests + }), context.RequestAborted); return; } } @@ -64,8 +68,7 @@ public async Task Invoke(HttpContext context) } finally { - //IMPORTANT This will not work for operation style apis, such as when returning a 202 for egress calls. - requestCount?.Decrement(); + incrementor?.Dispose(); } } } diff --git a/src/Tools/dotnet-monitor/Startup.cs b/src/Tools/dotnet-monitor/Startup.cs index a2264d5677d..1ff62bb0c41 100644 --- a/src/Tools/dotnet-monitor/Startup.cs +++ b/src/Tools/dotnet-monitor/Startup.cs @@ -186,7 +186,7 @@ public void Configure( app.UseResponseCompression(); //Note this must be after UseRouting but before UseEndpoints - app.UseMiddleware(); + app.UseMiddleware(); app.UseEndpoints(builder => { From ebcd96ed53db384736c105e54e91e5511abc39ad Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 17 Jul 2021 12:37:04 +0000 Subject: [PATCH 178/185] Update dependencies from https://github.com/dotnet/diagnostics build 20210716.1 (#578) [main] Update dependencies from dotnet/diagnostics --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index bf0cfaea140..ca900968d8d 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics - 419db65453d353c654192b42fa5aa63785b02abc + ce3b20de0dd81ae00f749e5d4d3d92ae7f37fa0d - + https://github.com/dotnet/diagnostics - 419db65453d353c654192b42fa5aa63785b02abc + ce3b20de0dd81ae00f749e5d4d3d92ae7f37fa0d diff --git a/eng/Versions.props b/eng/Versions.props index 83ee57eefb0..65eae567d5b 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-rc.1.21366.1 - 5.0.0-preview.21365.1 - 5.0.0-preview.21365.1 + 5.0.0-preview.21366.1 + 5.0.0-preview.21366.1 6.0.0-preview.7.21365.21 From 8c77b3df986080afb1b776d719c3aacf6f75c0ce Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 17 Jul 2021 12:37:20 +0000 Subject: [PATCH 179/185] Update dependencies from https://github.com/dotnet/arcade build 20210716.1 (#579) [main] Update dependencies from dotnet/arcade --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 2 +- global.json | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index ca900968d8d..2f984622b56 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -14,13 +14,13 @@ - + https://github.com/dotnet/arcade - 7b88b24068ecb4f6cf1da8395dbc2dee25a700bd + b03966cd85285e425ffe56003c0ab57e103dd14e - + https://github.com/dotnet/arcade - 7b88b24068ecb4f6cf1da8395dbc2dee25a700bd + b03966cd85285e425ffe56003c0ab57e103dd14e https://github.com/dotnet/symstore diff --git a/eng/Versions.props b/eng/Versions.props index 65eae567d5b..615ba0a70de 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -27,7 +27,7 @@ --> - 6.0.0-beta.21365.11 + 6.0.0-beta.21366.1 6.0.0-rc.1.21366.1 diff --git a/global.json b/global.json index 4dc853ec5fe..cf09bea1067 100644 --- a/global.json +++ b/global.json @@ -16,6 +16,6 @@ }, "msbuild-sdks": { "Microsoft.Build.NoTargets": "2.0.1", - "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21365.11" + "Microsoft.DotNet.Arcade.Sdk": "6.0.0-beta.21366.1" } } From bf9bab1a5a02e65c8f3be240af8f86ca2cb8329f Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Sat, 17 Jul 2021 12:50:37 +0000 Subject: [PATCH 180/185] Update dependencies from https://github.com/dotnet/runtime build 20210716.15 (#580) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 2f984622b56..abbc9faa926 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 08368a2dee8b8ed1ed522bff7b6ecfbd150ff995 - + https://github.com/dotnet/runtime - 62fa1f838e48459cda27c3d3f991253fdec9b4f8 + 5842db2c301cb1752ae854232a4fbae51d4a9ed0 diff --git a/eng/Versions.props b/eng/Versions.props index 615ba0a70de..add2b33dd58 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21366.1 5.0.0-preview.21366.1 - 6.0.0-preview.7.21365.21 + 6.0.0-rc.1.21366.15 1.0.215101 From 1c444d29621d49398a7e247d73345efd430e3661 Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Mon, 19 Jul 2021 12:48:51 +0000 Subject: [PATCH 181/185] [main] Update dependencies from dotnet/runtime (#583) [main] Update dependencies from dotnet/runtime --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index abbc9faa926..8983449c94c 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -30,9 +30,9 @@ https://github.com/dotnet/aspnetcore 08368a2dee8b8ed1ed522bff7b6ecfbd150ff995 - + https://github.com/dotnet/runtime - 5842db2c301cb1752ae854232a4fbae51d4a9ed0 + f7e4c261815c66fde2c1e750b744f193e236c17e diff --git a/eng/Versions.props b/eng/Versions.props index add2b33dd58..973ff502439 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -34,7 +34,7 @@ 5.0.0-preview.21366.1 5.0.0-preview.21366.1 - 6.0.0-rc.1.21366.15 + 6.0.0-rc.1.21369.2 1.0.215101 From 822f3aea7d1e0a6caa9c10fe4ed1cca8f5fb56cb Mon Sep 17 00:00:00 2001 From: "dotnet-maestro[bot]" <42748379+dotnet-maestro[bot]@users.noreply.github.com> Date: Tue, 20 Jul 2021 00:31:08 +0000 Subject: [PATCH 182/185] [main] Update dependencies from dotnet/aspnetcore (#581) [main] Update dependencies from dotnet/aspnetcore --- eng/Version.Details.xml | 4 ++-- eng/Versions.props | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 8983449c94c..f9d7d7ebd33 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -26,9 +26,9 @@ https://github.com/dotnet/symstore 3ed87724fe4e98c7ecc77617720591783ee2e676 - + https://github.com/dotnet/aspnetcore - 08368a2dee8b8ed1ed522bff7b6ecfbd150ff995 + 19f1321aa92911d6e1f66090313f2db9a543021f https://github.com/dotnet/runtime diff --git a/eng/Versions.props b/eng/Versions.props index 973ff502439..3fbf01af6b8 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -29,7 +29,7 @@ 6.0.0-beta.21366.1 - 6.0.0-rc.1.21366.1 + 6.0.0-rc.1.21367.4 5.0.0-preview.21366.1 5.0.0-preview.21366.1 From 08454f80dc55b8a8e9281a6d0b3743aa5ff22e3f Mon Sep 17 00:00:00 2001 From: Justin Anderson Date: Mon, 19 Jul 2021 17:38:46 -0700 Subject: [PATCH 183/185] Skip ConcurrencyLimitTest (#587) --- .../EgressTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressTests.cs b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressTests.cs index 775abd0c91e..57e49505c93 100644 --- a/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressTests.cs +++ b/src/Tests/Microsoft.Diagnostics.Monitoring.Tool.UnitTests/EgressTests.cs @@ -135,7 +135,7 @@ await ScenarioRunner.SingleTarget( }); } - [Fact] + [Fact(Skip = "https://github.com/dotnet/dotnet-monitor/issues/586")] public async Task ConcurrencyLimitTest() { await ScenarioRunner.SingleTarget( From ab6dc9286a3ff8e44776628dc935ac570a0e33f9 Mon Sep 17 00:00:00 2001 From: Patrick Fenelon Date: Tue, 20 Jul 2021 00:25:51 -0700 Subject: [PATCH 184/185] Use newer dotnet diagnostics resources --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index 36030cc99a0..f9d7d7ebd33 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics - f3ffe27acd2739518d359da0284ae6bf9e9e7966 + ce3b20de0dd81ae00f749e5d4d3d92ae7f37fa0d - + https://github.com/dotnet/diagnostics - f3ffe27acd2739518d359da0284ae6bf9e9e7966 + ce3b20de0dd81ae00f749e5d4d3d92ae7f37fa0d diff --git a/eng/Versions.props b/eng/Versions.props index 471f6f72f7f..418b5671bb8 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-rc.1.21367.4 - 5.0.227602 - 5.0.227602 + 5.0.0-preview.21366.1 + 5.0.0-preview.21366.1 6.0.0-rc.1.21369.2 From 075a442da9f3e1267654163131b56e2a3aad69a3 Mon Sep 17 00:00:00 2001 From: Justin Anderson Date: Tue, 20 Jul 2021 08:21:57 -0700 Subject: [PATCH 185/185] Update dotnet/diagnostics dependencies to release versions. --- eng/Version.Details.xml | 8 ++++---- eng/Versions.props | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index f9d7d7ebd33..3fcfa8fc731 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/command-line-api 166610c56ff732093f0145a2911d4f6c40b786da - + https://github.com/dotnet/diagnostics - ce3b20de0dd81ae00f749e5d4d3d92ae7f37fa0d + 5366510b270d0f0ebffc9e36e9496688b20b96c2 - + https://github.com/dotnet/diagnostics - ce3b20de0dd81ae00f749e5d4d3d92ae7f37fa0d + 5366510b270d0f0ebffc9e36e9496688b20b96c2 diff --git a/eng/Versions.props b/eng/Versions.props index 418b5671bb8..226c5021ebb 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -31,8 +31,8 @@ 6.0.0-rc.1.21367.4 - 5.0.0-preview.21366.1 - 5.0.0-preview.21366.1 + 5.0.236902 + 5.0.236902 6.0.0-rc.1.21369.2