Validated that engine rewrite works with JavaScript and fixed related bugs.
This commit is contained in:
Родитель
8ecbe1a1e5
Коммит
1669a87d74
|
@ -2,6 +2,8 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace Microsoft.Azure.AvailabilityMonitoring
|
||||
{
|
||||
|
@ -63,11 +65,54 @@ namespace Microsoft.Azure.AvailabilityMonitoring
|
|||
}
|
||||
}
|
||||
|
||||
internal static string LocationNameAsId(string locationDisplayName)
|
||||
public static string LocationNameAsId(string locationDisplayName)
|
||||
{
|
||||
string locationId = locationDisplayName?.Trim()?.ToLowerInvariant()?.Replace(' ', '-');
|
||||
return locationId;
|
||||
}
|
||||
|
||||
|
||||
public static string LimitLength(object value, int maxLength, bool trim)
|
||||
{
|
||||
string valueStr = value?.ToString();
|
||||
return LimitLength(valueStr, maxLength, trim);
|
||||
}
|
||||
|
||||
public static string LimitLength(string value, int maxLength, bool trim)
|
||||
{
|
||||
if (maxLength < 0)
|
||||
{
|
||||
throw new ArgumentException($"{nameof(maxLength)} may not be smaller than zero, but it was {maxLength}.");
|
||||
}
|
||||
|
||||
const string FillStr = "...";
|
||||
int fillStrLen = FillStr.Length;
|
||||
|
||||
value = SpellIfNull(value);
|
||||
value = trim ? value.Trim() : value;
|
||||
int valueLen = value.Length;
|
||||
|
||||
if (valueLen <= maxLength)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
if (maxLength < fillStrLen + 2)
|
||||
{
|
||||
string superShortResult = value.Substring(0, maxLength);
|
||||
return superShortResult;
|
||||
}
|
||||
|
||||
int postLen = (maxLength - fillStrLen) / 2;
|
||||
int preLen = maxLength - fillStrLen - postLen;
|
||||
|
||||
string postStr = value.Substring(valueLen - postLen, postLen);
|
||||
string preStr = value.Substring(0, preLen);
|
||||
|
||||
var shortResult = new StringBuilder(preStr, maxLength);
|
||||
shortResult.Append(FillStr);
|
||||
shortResult.Append(postStr);
|
||||
|
||||
return shortResult.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,6 @@ namespace Microsoft.Azure.AvailabilityMonitoring
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public static Logging Log { get { return AvailabilityTest.Logging.SingeltonInstance; } }
|
||||
|
@ -42,14 +41,6 @@ namespace Microsoft.Azure.AvailabilityMonitoring
|
|||
return StartNew(testConfig, telemetryConfig, flushOnDispose, log, logScope: null);
|
||||
}
|
||||
|
||||
internal static AvailabilityTestScope StartNew(IAvailabilityTestConfiguration testConfig,
|
||||
TelemetryClient telemetryClient,
|
||||
bool flushOnDispose,
|
||||
ILogger log)
|
||||
{
|
||||
return StartNew(testConfig, telemetryClient, flushOnDispose, log, logScope: null);
|
||||
}
|
||||
|
||||
internal static AvailabilityTestScope StartNew(IAvailabilityTestConfiguration testConfig,
|
||||
TelemetryConfiguration telemetryConfig,
|
||||
bool flushOnDispose,
|
||||
|
@ -60,16 +51,6 @@ namespace Microsoft.Azure.AvailabilityMonitoring
|
|||
return StartNew(testConfig.TestDisplayName, testConfig.LocationDisplayName, testConfig.LocationId, telemetryConfig, flushOnDispose, log, logScope);
|
||||
}
|
||||
|
||||
internal static AvailabilityTestScope StartNew(IAvailabilityTestConfiguration testConfig,
|
||||
TelemetryClient telemetryClient,
|
||||
bool flushOnDispose,
|
||||
ILogger log,
|
||||
object logScope)
|
||||
{
|
||||
Validate.NotNull(testConfig, nameof(testConfig));
|
||||
return StartNew(testConfig.TestDisplayName, testConfig.LocationDisplayName, testConfig.LocationId, telemetryClient, flushOnDispose, log, logScope);
|
||||
}
|
||||
|
||||
public static AvailabilityTestScope StartNew(string testDisplayName,
|
||||
string locationDisplayName,
|
||||
TelemetryConfiguration telemetryConfig,
|
||||
|
@ -81,16 +62,6 @@ namespace Microsoft.Azure.AvailabilityMonitoring
|
|||
return StartNew(testDisplayName, locationDisplayName, locationId, telemetryConfig, flushOnDispose, log, logScope: null);
|
||||
}
|
||||
|
||||
public static AvailabilityTestScope StartNew(string testDisplayName,
|
||||
string locationDisplayName,
|
||||
TelemetryClient telemetryClient,
|
||||
bool flushOnDispose,
|
||||
ILogger log)
|
||||
{
|
||||
string locationId = Format.LocationNameAsId(locationDisplayName);
|
||||
return StartNew(testDisplayName, locationDisplayName, locationId, telemetryClient, flushOnDispose, log, logScope: null);
|
||||
}
|
||||
|
||||
public static AvailabilityTestScope StartNew(string testDisplayName,
|
||||
string locationDisplayName,
|
||||
string locationId,
|
||||
|
@ -102,16 +73,6 @@ namespace Microsoft.Azure.AvailabilityMonitoring
|
|||
return StartNew(testDisplayName, locationDisplayName, locationId, telemetryConfig, flushOnDispose, log, logScope: null);
|
||||
}
|
||||
|
||||
public static AvailabilityTestScope StartNew(string testDisplayName,
|
||||
string locationDisplayName,
|
||||
string locationId,
|
||||
TelemetryClient telemetryClient,
|
||||
bool flushOnDispose,
|
||||
ILogger log)
|
||||
{
|
||||
return StartNew(testDisplayName, locationDisplayName, locationId, telemetryClient, flushOnDispose, log, logScope: null);
|
||||
}
|
||||
|
||||
public static AvailabilityTestScope StartNew(string testDisplayName,
|
||||
string locationDisplayName,
|
||||
string locationId,
|
||||
|
@ -120,24 +81,10 @@ namespace Microsoft.Azure.AvailabilityMonitoring
|
|||
ILogger log,
|
||||
object logScope)
|
||||
|
||||
{
|
||||
Validate.NotNull(telemetryConfig, nameof(telemetryConfig));
|
||||
|
||||
var telemetryClient = new TelemetryClient(telemetryConfig);
|
||||
return StartNew(testDisplayName, locationDisplayName, locationId, telemetryClient, flushOnDispose,log, logScope);
|
||||
}
|
||||
|
||||
public static AvailabilityTestScope StartNew(string testDisplayName,
|
||||
string locationDisplayName,
|
||||
string locationId,
|
||||
TelemetryClient telemetryClient,
|
||||
bool flushOnDispose,
|
||||
ILogger log,
|
||||
object logScope)
|
||||
{
|
||||
log = AvailabilityTest.Log.CreateFallbackLogIfRequired(log);
|
||||
|
||||
var testScope = new AvailabilityTestScope(testDisplayName, locationDisplayName, locationId, telemetryClient, flushOnDispose, log, logScope);
|
||||
|
||||
var testScope = new AvailabilityTestScope(testDisplayName, locationDisplayName, locationId, telemetryConfig, flushOnDispose, log, logScope);
|
||||
testScope.Start();
|
||||
|
||||
return testScope;
|
||||
|
|
|
@ -3,8 +3,10 @@ using System.Diagnostics;
|
|||
using System.Threading;
|
||||
using Microsoft.ApplicationInsights;
|
||||
using Microsoft.ApplicationInsights.DataContracts;
|
||||
using Microsoft.ApplicationInsights.Extensibility;
|
||||
using Microsoft.Azure.WebJobs.Extensions.AvailabilityMonitoring;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
|
||||
namespace Microsoft.Azure.AvailabilityMonitoring
|
||||
{
|
||||
|
@ -36,10 +38,7 @@ namespace Microsoft.Azure.AvailabilityMonitoring
|
|||
private const string PropertyName_AssociatedAvailabilityResult_Id = "AssociatedAvailabilityResult.Id";
|
||||
private const string PropertyName_AssociatedAvailabilityResult_IsTimeout = "AssociatedAvailabilityResult.IsTimeout";
|
||||
|
||||
private readonly string _testDisplayName;
|
||||
private readonly string _locationDisplayName;
|
||||
private readonly string _locationId;
|
||||
|
||||
private readonly string _instrumentationKey;
|
||||
private readonly TelemetryClient _telemetryClient;
|
||||
private readonly bool _flushOnDispose;
|
||||
private readonly ILogger _log;
|
||||
|
@ -55,24 +54,26 @@ namespace Microsoft.Azure.AvailabilityMonitoring
|
|||
|
||||
public AvailabilityTestScope.Stage CurrentStage { get { return (AvailabilityTestScope.Stage) _currentStage; } }
|
||||
|
||||
public string TestDisplayName { get { return _testDisplayName; } }
|
||||
public string TestDisplayName { get; }
|
||||
|
||||
public string LocationDisplayName { get { return _locationDisplayName; } }
|
||||
public string LocationDisplayName { get; }
|
||||
|
||||
public string LocationId { get { return _locationId; } }
|
||||
public string LocationId { get; }
|
||||
|
||||
public AvailabilityTestScope(string testDisplayName, string locationDisplayName, string locationId, TelemetryClient telemetryClient, bool flushOnDispose, ILogger log, object logScope)
|
||||
public AvailabilityTestScope(string testDisplayName, string locationDisplayName, string locationId, TelemetryConfiguration telemetryConfig, bool flushOnDispose, ILogger log, object logScope)
|
||||
{
|
||||
Validate.NotNullOrWhitespace(testDisplayName, nameof(testDisplayName));
|
||||
Validate.NotNullOrWhitespace(locationDisplayName, nameof(locationDisplayName));
|
||||
Validate.NotNullOrWhitespace(locationId, nameof(locationId));
|
||||
Validate.NotNull(telemetryClient, nameof(telemetryClient));
|
||||
Validate.NotNull(telemetryConfig, nameof(telemetryConfig));
|
||||
|
||||
_testDisplayName = testDisplayName;
|
||||
_locationDisplayName = locationDisplayName;
|
||||
_locationId = locationId;
|
||||
this.TestDisplayName = testDisplayName;
|
||||
this.LocationDisplayName = locationDisplayName;
|
||||
this.LocationId = locationId;
|
||||
|
||||
_instrumentationKey = telemetryConfig.InstrumentationKey;
|
||||
_telemetryClient = new TelemetryClient(telemetryConfig);
|
||||
|
||||
_telemetryClient = telemetryClient;
|
||||
_flushOnDispose = flushOnDispose;
|
||||
|
||||
_log = log;
|
||||
|
@ -87,12 +88,12 @@ namespace Microsoft.Azure.AvailabilityMonitoring
|
|||
{
|
||||
_log?.LogInformation($"{nameof(AvailabilityTestScope)}.{nameof(Start)} beginning:"
|
||||
+ " {{TestDisplayName=\"{TestDisplayName}\", LocationDisplayName=\"{LocationDisplayName}\", LocationId=\"{LocationId}\"}}",
|
||||
_testDisplayName, _locationDisplayName, _locationId);
|
||||
TestDisplayName, LocationDisplayName, LocationId);
|
||||
|
||||
TransitionStage(from: Stage.New, to: Stage.Started);
|
||||
|
||||
// Start activity:
|
||||
string activityOperationName = Format.SpanOperationName(_testDisplayName, _locationDisplayName);
|
||||
string activityOperationName = Format.SpanOperationName(TestDisplayName, LocationDisplayName);
|
||||
_activitySpan = new Activity(activityOperationName).Start();
|
||||
_activitySpanId = Format.SpanId(_activitySpan);
|
||||
|
||||
|
@ -102,7 +103,7 @@ namespace Microsoft.Azure.AvailabilityMonitoring
|
|||
_log?.LogInformation($"{nameof(AvailabilityTestScope)}.{nameof(Start)} finished:"
|
||||
+ " {{TestDisplayName=\"{TestDisplayName}\", LocationDisplayName=\"{LocationDisplayName}\", LocationId=\"{LocationId}\","
|
||||
+ " SpanId=\"{SpanId}\", StartTime=\"{StartTime}\", OperationName=\"{OperationName}\"}}",
|
||||
_testDisplayName, _locationDisplayName, _locationId,
|
||||
TestDisplayName, LocationDisplayName, LocationId,
|
||||
_activitySpanId, _startTime.ToString("o"), activityOperationName);
|
||||
}
|
||||
}
|
||||
|
@ -115,7 +116,7 @@ namespace Microsoft.Azure.AvailabilityMonitoring
|
|||
+ " {{TestDisplayName=\"{TestDisplayName}\", LocationDisplayName=\"{LocationDisplayName}\", LocationId=\"{LocationId}\","
|
||||
+ " SpanId=\"{SpanId}\"}}",
|
||||
success,
|
||||
_testDisplayName, _locationDisplayName, _locationId,
|
||||
TestDisplayName, LocationDisplayName, LocationId,
|
||||
Format.SpellIfNull(_activitySpanId));
|
||||
|
||||
EnsureStage(Stage.Started);
|
||||
|
@ -138,7 +139,7 @@ namespace Microsoft.Azure.AvailabilityMonitoring
|
|||
+ " SpanId=\"{SpanId}\"}}."
|
||||
+ " This indicates that the test result was not set by calling Complete(..); a Failure will be assumed.",
|
||||
disposing,
|
||||
_testDisplayName, _locationDisplayName, _locationId,
|
||||
TestDisplayName, LocationDisplayName, LocationId,
|
||||
Format.SpellIfNull(_activitySpanId));
|
||||
|
||||
EnsureStage(Stage.Started);
|
||||
|
@ -162,11 +163,12 @@ namespace Microsoft.Azure.AvailabilityMonitoring
|
|||
{
|
||||
using (_log.BeginScopeSafe(_logScope))
|
||||
{
|
||||
_log?.LogInformation($"{nameof(AvailabilityTestScope)}.{nameof(Complete)} invoked with ExceptionType={{ExceptionType}} and IsTimeout={{IsTimeout}}:"
|
||||
+ " {{TestDisplayName=\"{TestDisplayName}\", LocationDisplayName=\"{LocationDisplayName}\", LocationId=\"{LocationId}\","
|
||||
+ " SpanId=\"{SpanId}\"}}",
|
||||
Format.SpellIfNull(error?.GetType()?.Name), isTimeout,
|
||||
_testDisplayName, _locationDisplayName, _locationId,
|
||||
_log?.LogInformation($"{nameof(AvailabilityTestScope)}.{nameof(Complete)} invoked with"
|
||||
+ " (ExceptionType={ExceptionType}, ExceptionMessage=\"{ExceptionMessage}\", IsTimeout={IsTimeout}):"
|
||||
+ " {{TestDisplayName=\"{TestDisplayName}\", LocationDisplayName=\"{LocationDisplayName}\", LocationId=\"{LocationId}\","
|
||||
+ " SpanId=\"{SpanId}\"}}",
|
||||
Format.SpellIfNull(error?.GetType()?.Name), Format.LimitLength(error.Message, 100, trim: true), isTimeout,
|
||||
TestDisplayName, LocationDisplayName, LocationId,
|
||||
Format.SpellIfNull(_activitySpanId));
|
||||
|
||||
EnsureStage(Stage.Started);
|
||||
|
@ -201,7 +203,7 @@ namespace Microsoft.Azure.AvailabilityMonitoring
|
|||
_log?.LogInformation($"{nameof(AvailabilityTestScope)}.{nameof(Complete)} beginning:"
|
||||
+ " {{TestDisplayName=\"{TestDisplayName}\", LocationDisplayName=\"{LocationDisplayName}\", LocationId=\"{LocationId}\","
|
||||
+ " SpanId=\"{SpanId}\"}}",
|
||||
_testDisplayName, _locationDisplayName, _locationId,
|
||||
TestDisplayName, LocationDisplayName, LocationId,
|
||||
Format.SpellIfNull(_activitySpanId));
|
||||
|
||||
Validate.NotNull(availabilityResult, nameof(availabilityResult));
|
||||
|
@ -254,28 +256,28 @@ namespace Microsoft.Azure.AvailabilityMonitoring
|
|||
|
||||
if (String.IsNullOrWhiteSpace(availabilityResult.Name))
|
||||
{
|
||||
availabilityResult.Name = _testDisplayName;
|
||||
availabilityResult.Name = TestDisplayName;
|
||||
}
|
||||
else if (! availabilityResult.Name.Equals(_testDisplayName, StringComparison.Ordinal))
|
||||
else if (! availabilityResult.Name.Equals(TestDisplayName, StringComparison.Ordinal))
|
||||
{
|
||||
_log?.LogDebug($"{nameof(AvailabilityTestScope)}.{nameof(Complete)} (SpanId=\"{{SpanId}}\") detected that the Name of the"
|
||||
+ $" specified Availability Result is different from the corresponding value of this {nameof(AvailabilityTestScope)}."
|
||||
+ $" The value specified in the Availability Result takes precedence for tracking."
|
||||
+ " AvailabilityTestScope_TestDisplayName=\"{AvailabilityTestScope_TestDisplayName}\". AvailabilityResult_Name=\"{AvailabilityResult_Name}\"",
|
||||
_activitySpanId, _testDisplayName, availabilityResult.Name);
|
||||
+ " AvailabilityTestScopeTestDisplayName=\"{AvailabilityTestScope_TestDisplayName}\". AvailabilityResult_Name=\"{AvailabilityResult_Name}\"",
|
||||
_activitySpanId, TestDisplayName, availabilityResult.Name);
|
||||
}
|
||||
|
||||
if (String.IsNullOrWhiteSpace(availabilityResult.RunLocation))
|
||||
{
|
||||
availabilityResult.RunLocation = _locationDisplayName;
|
||||
availabilityResult.RunLocation = LocationDisplayName;
|
||||
}
|
||||
else if (! availabilityResult.RunLocation.Equals(_locationDisplayName, StringComparison.Ordinal))
|
||||
else if (! availabilityResult.RunLocation.Equals(LocationDisplayName, StringComparison.Ordinal))
|
||||
{
|
||||
_log?.LogDebug($"{nameof(AvailabilityTestScope)}.{nameof(Complete)} (SpanId=\"{{SpanId}}\") detected that the RunLocation of the"
|
||||
+ $" specified Availability Result is different from the corresponding value of this {nameof(AvailabilityTestScope)}."
|
||||
+ $" The value specified in the Availability Result takes precedence for tracking."
|
||||
+ " AvailabilityTestScope_LocationDisplayName=\"{AvailabilityTestScope_LocationDisplayName}\". AvailabilityResult_RunLocation=\"{AvailabilityResult_RunLocation}\"",
|
||||
_activitySpanId, _locationDisplayName, availabilityResult.RunLocation);
|
||||
_activitySpanId, LocationDisplayName, availabilityResult.RunLocation);
|
||||
}
|
||||
|
||||
if (! availabilityResult.Properties.TryGetValue(PropertyName_WebtestLocationId, out string availabilityResultLocationId))
|
||||
|
@ -285,15 +287,15 @@ namespace Microsoft.Azure.AvailabilityMonitoring
|
|||
|
||||
if (String.IsNullOrWhiteSpace(availabilityResultLocationId))
|
||||
{
|
||||
availabilityResult.Properties[PropertyName_WebtestLocationId] = _locationId;
|
||||
availabilityResult.Properties[PropertyName_WebtestLocationId] = LocationId;
|
||||
}
|
||||
else if (! availabilityResultLocationId.Equals(_locationId, StringComparison.Ordinal))
|
||||
else if (! availabilityResultLocationId.Equals(LocationId, StringComparison.Ordinal))
|
||||
{
|
||||
_log?.LogDebug($"{nameof(AvailabilityTestScope)}.{nameof(Complete)} (SpanId=\"{{SpanId}}\") detected that the WebtestLocationId of the"
|
||||
+ $" specified Availability Result is different from the corresponding value of this {nameof(AvailabilityTestScope)}."
|
||||
+ $" The value specified in the Availability Result takes precedence for tracking."
|
||||
+ " AvailabilityTestScope_LocationId=\"{AvailabilityTestScope_LocationId}\". AvailabilityResult_WebtestLocationId=\"{AvailabilityResult_WebtestLocationId}\"",
|
||||
_activitySpanId, _locationId, availabilityResultLocationId);
|
||||
_activitySpanId, LocationId, availabilityResultLocationId);
|
||||
}
|
||||
|
||||
// The user may or may not have set the ID of the availability result telemetry.
|
||||
|
@ -306,7 +308,7 @@ namespace Microsoft.Azure.AvailabilityMonitoring
|
|||
_log?.LogInformation($"{nameof(AvailabilityTestScope)}.{nameof(Complete)} finished"
|
||||
+ " {{TestDisplayName=\"{TestDisplayName}\", LocationDisplayName=\"{LocationDisplayName}\", LocationId=\"{LocationId}\","
|
||||
+ " SpanId=\"{SpanId}\", StartTime=\"{StartTime}\", EndTime=\"{EndTime}\", Duration=\"{Duration}\", Success=\"{Success}\"}}",
|
||||
_testDisplayName, _locationDisplayName, _locationId,
|
||||
TestDisplayName, LocationDisplayName, LocationId,
|
||||
_activitySpanId, _startTime.ToString("o"), _endTime.ToString("o"), duration, availabilityResult.Success);
|
||||
}
|
||||
}
|
||||
|
@ -314,7 +316,7 @@ namespace Microsoft.Azure.AvailabilityMonitoring
|
|||
public AvailabilityTestInfo CreateAvailabilityTestInfo()
|
||||
{
|
||||
AvailabilityTelemetry defaultAvailabilityResult = CreateDefaultAvailabilityResult();
|
||||
var testInfo = new AvailabilityTestInfo(_testDisplayName, _locationDisplayName, _locationId, _startTime, defaultAvailabilityResult);
|
||||
var testInfo = new AvailabilityTestInfo(TestDisplayName, LocationDisplayName, LocationId, _startTime, defaultAvailabilityResult);
|
||||
return testInfo;
|
||||
}
|
||||
|
||||
|
@ -359,7 +361,7 @@ namespace Microsoft.Azure.AvailabilityMonitoring
|
|||
_log?.LogInformation($"{nameof(AvailabilityTestScope)}.{nameof(Dispose)} beginning:"
|
||||
+ " {{TestDisplayName=\"{TestDisplayName}\", LocationDisplayName=\"{LocationDisplayName}\", LocationId=\"{LocationId}\","
|
||||
+ " SpanId=\"{SpanId}\", CurrentStage=\"{CurrentStage}\", Disposing=\"{Disposing}\"}}",
|
||||
_testDisplayName, _locationDisplayName, _locationId,
|
||||
TestDisplayName, LocationDisplayName, LocationId,
|
||||
Format.SpellIfNull(_activitySpanId), stage, disposing);
|
||||
|
||||
switch (stage)
|
||||
|
@ -386,7 +388,7 @@ namespace Microsoft.Azure.AvailabilityMonitoring
|
|||
_log?.LogInformation($"{nameof(AvailabilityTestScope)}.{nameof(Dispose)} finished:"
|
||||
+ " {{TestDisplayName=\"{TestDisplayName}\", LocationDisplayName=\"{LocationDisplayName}\", LocationId=\"{LocationId}\","
|
||||
+ " SpanId=\"{SpanId}\", CurrentStage=\"{CurrentStage}\", Disposing=\"{Disposing}\"}}",
|
||||
_testDisplayName, _locationDisplayName, _locationId,
|
||||
TestDisplayName, LocationDisplayName, LocationId,
|
||||
Format.SpellIfNull(_activitySpanId), CurrentStage, disposing);
|
||||
}
|
||||
}
|
||||
|
@ -396,7 +398,7 @@ namespace Microsoft.Azure.AvailabilityMonitoring
|
|||
_log?.LogInformation($"{nameof(AvailabilityTestScope)}.{nameof(SendResult)} beginning:"
|
||||
+ " {{TestDisplayName=\"{TestDisplayName}\", LocationDisplayName=\"{LocationDisplayName}\", LocationId=\"{LocationId}\","
|
||||
+ " SpanId=\"{SpanId}\"}}",
|
||||
_testDisplayName, _locationDisplayName, _locationId,
|
||||
TestDisplayName, LocationDisplayName, LocationId,
|
||||
Format.SpellIfNull(_activitySpanId));
|
||||
|
||||
TransitionStage(from: Stage.Completed, to: Stage.SentResults);
|
||||
|
@ -415,7 +417,7 @@ namespace Microsoft.Azure.AvailabilityMonitoring
|
|||
_log?.LogInformation($"{nameof(AvailabilityTestScope)}.{nameof(SendResult)} finished:"
|
||||
+ " {{TestDisplayName=\"{TestDisplayName}\", LocationDisplayName=\"{LocationDisplayName}\", LocationId=\"{LocationId}\","
|
||||
+ " SpanId=\"{SpanId}\"}}",
|
||||
_testDisplayName, _locationDisplayName, _locationId,
|
||||
TestDisplayName, LocationDisplayName, LocationId,
|
||||
Format.SpellIfNull(_activitySpanId));
|
||||
}
|
||||
|
||||
|
@ -426,7 +428,7 @@ namespace Microsoft.Azure.AvailabilityMonitoring
|
|||
_log?.LogInformation($"{nameof(AvailabilityTestScope)} is flushing its {nameof(TelemetryClient)}:"
|
||||
+ " {{TestDisplayName=\"{TestDisplayName}\", LocationDisplayName=\"{LocationDisplayName}\", LocationId=\"{LocationId}\","
|
||||
+ " SpanId=\"{SpanId}\", CurrentStage=\"{CurrentStage}\", FlushOnDispose=\"{FlushOnDispose}\"}}",
|
||||
_testDisplayName, _locationDisplayName, _locationId,
|
||||
TestDisplayName, LocationDisplayName, LocationId,
|
||||
Format.SpellIfNull(_activitySpanId), CurrentStage, _flushOnDispose);
|
||||
|
||||
_telemetryClient.Flush();
|
||||
|
@ -436,7 +438,7 @@ namespace Microsoft.Azure.AvailabilityMonitoring
|
|||
_log?.LogInformation($"{nameof(AvailabilityTestScope)} is NOT flushing its {nameof(TelemetryClient)}:"
|
||||
+ " {{TestDisplayName=\"{TestDisplayName}\", LocationDisplayName=\"{LocationDisplayName}\", LocationId=\"{LocationId}\","
|
||||
+ " SpanId=\"{SpanId}\", CurrentStage=\"{CurrentStage}\", FlushOnDispose=\"{FlushOnDispose}\"}}",
|
||||
_testDisplayName, _locationDisplayName, _locationId,
|
||||
TestDisplayName, LocationDisplayName, LocationId,
|
||||
Format.SpellIfNull(_activitySpanId), CurrentStage, _flushOnDispose);
|
||||
}
|
||||
}
|
||||
|
@ -467,8 +469,8 @@ namespace Microsoft.Azure.AvailabilityMonitoring
|
|||
availabilityResult.Duration = TimeSpan.Zero;
|
||||
availabilityResult.Success = false;
|
||||
|
||||
availabilityResult.Name = _testDisplayName;
|
||||
availabilityResult.RunLocation = _locationDisplayName;
|
||||
availabilityResult.Name = TestDisplayName;
|
||||
availabilityResult.RunLocation = LocationDisplayName;
|
||||
availabilityResult.Properties["WebtestLocationId"] = this.LocationId;
|
||||
|
||||
//availabilityResult.Properties["SyntheticMonitorId"] = $"default_{this.TestArmResourceName}_{this.LocationId}";
|
||||
|
@ -479,6 +481,11 @@ namespace Microsoft.Azure.AvailabilityMonitoring
|
|||
// + $"/features/{this.TestArmResourceName}"
|
||||
// + $"/locations/{this.LocationId}";
|
||||
|
||||
if (! String.IsNullOrWhiteSpace(_instrumentationKey))
|
||||
{
|
||||
availabilityResult.Context.InstrumentationKey = _instrumentationKey;
|
||||
}
|
||||
|
||||
return availabilityResult;
|
||||
}
|
||||
|
||||
|
|
|
@ -53,11 +53,6 @@ namespace Microsoft.Azure.WebJobs.Extensions.AvailabilityMonitoring
|
|||
FluentBindingRule<AvailabilityTestInfoAttribute> testInfoRule = extensionConfigContext.AddBindingRule<AvailabilityTestInfoAttribute>();
|
||||
#pragma warning restore CS0618
|
||||
|
||||
// This binding provider exists soley to allow us to inspect functions to determine whether they are Availability Tests.
|
||||
// It uses BindingProviderContext, which is not available when binding via BindToCollector(..) as
|
||||
// we do for the actual return value below.
|
||||
//testResultRule.Bind(new AvailabilityTestDiscoveryBindingProvider(_availabilityTestRegistry, _log));
|
||||
|
||||
// This binding is used to get and process the return value of the function:
|
||||
testResultRule.BindToCollector<AvailabilityTestResultAttribute, AvailabilityTelemetry>(CreateAvailabilityTelemetryAsyncCollector);
|
||||
testResultRule.BindToCollector<AvailabilityTestResultAttribute, bool>(CreateBoolAsyncCollector);
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Azure.AvailabilityMonitoring;
|
||||
using Microsoft.Azure.WebJobs.Host.Bindings;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Microsoft.Azure.WebJobs.Extensions.AvailabilityMonitoring
|
||||
{
|
||||
/// <summary>
|
||||
///This binding provider exists soley to inspect functions in order to determine whether they are an Availability Tests.
|
||||
///
|
||||
/// It uses BindingProviderContext, which is not available when binding via BindToCollector(..) as
|
||||
/// we do for the actual return value below.
|
||||
///
|
||||
/// Attention!:
|
||||
/// This works only for in-proc, .Net-based Functions.
|
||||
/// For out-of-proc runtimes this approach does not work, there, return-value bindings
|
||||
/// may be evaluated after the function user code completes.
|
||||
/// For out-of-proc runtimes, the AvailabilityTestInvocationManager will read the
|
||||
/// function metadata to determine whether the function is an Availability Test.
|
||||
/// </summary>
|
||||
internal class AvailabilityTestDiscoveryBindingProvider : IBindingProvider
|
||||
{
|
||||
private readonly AvailabilityTestRegistry _availabilityTestRegistry;
|
||||
private readonly ILogger _log;
|
||||
|
||||
public AvailabilityTestDiscoveryBindingProvider(AvailabilityTestRegistry availabilityTestRegistry, ILogger log)
|
||||
{
|
||||
Validate.NotNull(availabilityTestRegistry, nameof(availabilityTestRegistry));
|
||||
|
||||
_availabilityTestRegistry = availabilityTestRegistry;
|
||||
_log = log;
|
||||
}
|
||||
|
||||
public Task<IBinding> TryCreateAsync(BindingProviderContext bindingProviderContext)
|
||||
{
|
||||
ParameterInfo parameter = bindingProviderContext?.Parameter;
|
||||
AvailabilityTestResultAttribute attribute = parameter?.GetCustomAttribute<AvailabilityTestResultAttribute>(inherit: false);
|
||||
|
||||
|
||||
if (attribute != null &¶meter.Member is MethodInfo methodInfo)
|
||||
{
|
||||
string functionName = GetFunctionName(methodInfo);
|
||||
_availabilityTestRegistry.Functions.Register(functionName, attribute, _log);
|
||||
}
|
||||
|
||||
return Task.FromResult<IBinding>(null);
|
||||
}
|
||||
|
||||
private static string GetFunctionName(MethodInfo methodInfo)
|
||||
{
|
||||
// The Function name returned by this method MUST be the same as passed to invocation filters!
|
||||
// This is the same code as used by the WebJobs SDK for this.
|
||||
|
||||
FunctionNameAttribute functionNameAttribute = methodInfo.GetCustomAttribute<FunctionNameAttribute>();
|
||||
return (functionNameAttribute != null) ? functionNameAttribute.Name : $"{methodInfo.DeclaringType.Name}.{methodInfo.Name}";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -187,7 +187,7 @@ namespace Microsoft.Azure.WebJobs.Extensions.AvailabilityMonitoring
|
|||
// Type 'FunctionInvocationContext' (and other Filter-related types) is marked as preview/obsolete,
|
||||
// but the guidance from the Azure Functions team is to use it, so we disable the warning.
|
||||
#pragma warning disable CS0618
|
||||
private void GetTestConfigFromMetadata(string functionName,
|
||||
private static void GetTestConfigFromMetadata(string functionName,
|
||||
FunctionInvocationContext functionInvocationContext,
|
||||
ILogger log,
|
||||
out bool isAvailabilityTest,
|
||||
|
@ -257,7 +257,7 @@ namespace Microsoft.Azure.WebJobs.Extensions.AvailabilityMonitoring
|
|||
// Type 'FunctionInvocationContext' (and other Filter-related types) is marked as preview/obsolete,
|
||||
// but the guidance from the Azure Functions team is to use it, so we disable the warning.
|
||||
#pragma warning disable CS0618
|
||||
private string ReadFunctionMetadataFile(FunctionInvocationContext functionInvocationContext)
|
||||
private static string ReadFunctionMetadataFile(FunctionInvocationContext functionInvocationContext)
|
||||
#pragma warning restore CS0618
|
||||
{
|
||||
// We will do very verbose error checking and logging via exceptions here to aid supportability
|
||||
|
@ -283,10 +283,10 @@ namespace Microsoft.Azure.WebJobs.Extensions.AvailabilityMonitoring
|
|||
throw new InvalidOperationException(NeedContextArgumentErrorPrefix + " Such entry exists, but the value is null.");
|
||||
}
|
||||
|
||||
string functionAppDir;
|
||||
string metadataFilePath;
|
||||
if (execContextObj is ExecutionContext execContext)
|
||||
{
|
||||
functionAppDir = execContext.FunctionAppDirectory ?? String.Empty;
|
||||
metadataFilePath = GetFullFunctionMetadataPath(execContext);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -294,15 +294,37 @@ namespace Microsoft.Azure.WebJobs.Extensions.AvailabilityMonitoring
|
|||
+ $" Such entry exists, but is has the wrong type (\"{execContextObj.GetType().Name}\").");
|
||||
}
|
||||
|
||||
string metadataFilePath = Path.Combine(functionAppDir, "function.json");
|
||||
|
||||
if (! File.Exists(metadataFilePath))
|
||||
{
|
||||
throw new InvalidOperationException($"Determined that the Metadata File Path the this Function is \"{metadataFilePath}\", but that file does not exist.");
|
||||
}
|
||||
|
||||
string metadataFileContent = File.ReadAllText(metadataFilePath);
|
||||
return metadataFileContent;
|
||||
}
|
||||
|
||||
private static string GetFullFunctionMetadataPath(ExecutionContext execContext)
|
||||
{
|
||||
const string functionJson = "function.json";
|
||||
|
||||
string functionDir = execContext.FunctionDirectory ?? String.Empty;
|
||||
string metadataFilePathInFuncDir = Path.Combine(functionDir, functionJson);
|
||||
|
||||
if (File.Exists(metadataFilePathInFuncDir))
|
||||
{
|
||||
return metadataFilePathInFuncDir;
|
||||
}
|
||||
|
||||
// We did not find function.json where it should be (in FunctionDirectory).
|
||||
// Let us attempt to look in FunctionAppDirectory as a fallback.
|
||||
// @ToDo: Is this reqired / safe?
|
||||
|
||||
string functionAppDir = execContext.FunctionAppDirectory ?? String.Empty;
|
||||
string metadataFilePathInAppDir = Path.Combine(functionAppDir, functionJson);
|
||||
|
||||
if (File.Exists(metadataFilePathInAppDir))
|
||||
{
|
||||
return metadataFilePathInAppDir;
|
||||
}
|
||||
|
||||
throw new InvalidOperationException($"Looked for the Function Metadata File (\"{functionJson}\") first in"
|
||||
+ $" \"{metadataFilePathInFuncDir}\" and then in \"{metadataFilePathInAppDir}\","
|
||||
+ " but that file does not exist.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ using System.Diagnostics;
|
|||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.ApplicationInsights;
|
||||
using Microsoft.ApplicationInsights.Extensibility;
|
||||
using Microsoft.Azure.AvailabilityMonitoring;
|
||||
using Microsoft.Azure.WebJobs.Host;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
@ -18,16 +19,16 @@ namespace Microsoft.Azure.WebJobs.Extensions.AvailabilityMonitoring
|
|||
#pragma warning restore CS0618 // Type or member is obsolete (Filter-related types are obsolete, but we want to use them)
|
||||
{
|
||||
private readonly AvailabilityTestRegistry _availabilityTestRegistry;
|
||||
private readonly TelemetryClient _telemetryClient;
|
||||
private readonly TelemetryConfiguration _telemetryConfiguration;
|
||||
private readonly AvailabilityTestScopeSettingsResolver _availabilityTestScopeSettingsResolver;
|
||||
|
||||
public FunctionInvocationManagementFilter(AvailabilityTestRegistry availabilityTestRegistry, TelemetryClient telemetryClient, IConfiguration configuration, INameResolver nameResolver)
|
||||
public FunctionInvocationManagementFilter(AvailabilityTestRegistry availabilityTestRegistry, TelemetryConfiguration telemetryConfiguration, IConfiguration configuration, INameResolver nameResolver)
|
||||
{
|
||||
Validate.NotNull(availabilityTestRegistry, nameof(availabilityTestRegistry));
|
||||
Validate.NotNull(telemetryClient, nameof(telemetryClient));
|
||||
Validate.NotNull(telemetryConfiguration, nameof(telemetryConfiguration));
|
||||
|
||||
_availabilityTestRegistry = availabilityTestRegistry;
|
||||
_telemetryClient = telemetryClient;
|
||||
_telemetryConfiguration = telemetryConfiguration;
|
||||
_availabilityTestScopeSettingsResolver = new AvailabilityTestScopeSettingsResolver(configuration, nameResolver);
|
||||
}
|
||||
|
||||
|
@ -112,7 +113,7 @@ namespace Microsoft.Azure.WebJobs.Extensions.AvailabilityMonitoring
|
|||
IAvailabilityTestConfiguration resolvedTestConfig = _availabilityTestScopeSettingsResolver.Resolve(testConfig, functionName);
|
||||
|
||||
// Start the availability test scope (this will start timers and set up the activity span):
|
||||
AvailabilityTestScope testScope = AvailabilityTest.StartNew(resolvedTestConfig, _telemetryClient, flushOnDispose: true, log, logScopeInfo);
|
||||
AvailabilityTestScope testScope = AvailabilityTest.StartNew(resolvedTestConfig, _telemetryConfiguration, flushOnDispose: true, log, logScopeInfo);
|
||||
invocationState.AttachTestScope(testScope);
|
||||
|
||||
// If we have previously instantiated a result collector, initialize it now:
|
||||
|
@ -215,15 +216,16 @@ namespace Microsoft.Azure.WebJobs.Extensions.AvailabilityMonitoring
|
|||
|
||||
// If configured, use a fall-back logger:
|
||||
log = AvailabilityTest.Log.CreateFallbackLogIfRequired(log);
|
||||
const int MaxErrorMessageLength = 100;
|
||||
|
||||
IReadOnlyDictionary<string, object> logScopeInfo = LogMonikers.Scopes.CreateForTestInvocation(functionName);
|
||||
using (log?.BeginScopeSafe(logScopeInfo))
|
||||
{
|
||||
log?.LogDebug($"Availability Test Post-Function error handling routine (via {entryPointName}) beginning:"
|
||||
+ " {{FunctionName=\"{FunctionName}\", FunctionInstanceId=\"{FunctionInstanceId}\","
|
||||
+ " ErrorType=\"{ErrorType}\"}}",
|
||||
+ " ErrorType=\"{ErrorType}\", ErrorMessage=\"{ErrorMessage}\"}}",
|
||||
functionName, functionInstanceId,
|
||||
Format.SpellIfNull(error?.GetType()?.Name));
|
||||
Format.SpellIfNull(error?.GetType()?.Name), Format.LimitLength(error?.Message, MaxErrorMessageLength, trim: true));
|
||||
|
||||
// A function is an Availability Test iff is has a return value marked with [AvailabilityTestResult];
|
||||
// whereas a [AvailabilityTestInfo] is optional to get test information at runtime.
|
||||
|
@ -238,9 +240,9 @@ namespace Microsoft.Azure.WebJobs.Extensions.AvailabilityMonitoring
|
|||
log?.LogDebug($"Availability Test Post-Function error handling routine (via {entryPointName}) finished:"
|
||||
+ " This function invocation instance is not being tracked."
|
||||
+ " {{FunctionName=\"{FunctionName}\", FunctionInstanceId=\"{FunctionInstanceId}\","
|
||||
+ " ErrorType=\"{ErrorType}\"}}",
|
||||
+ " ErrorType=\"{ErrorType}\", ErrorMessage=\"{ErrorMessage}\"}}",
|
||||
functionName, functionInstanceId,
|
||||
Format.SpellIfNull(error?.GetType()?.Name));
|
||||
Format.SpellIfNull(error?.GetType()?.Name), Format.LimitLength(error?.Message, MaxErrorMessageLength, trim: true));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -252,9 +254,9 @@ namespace Microsoft.Azure.WebJobs.Extensions.AvailabilityMonitoring
|
|||
log?.LogDebug($"Availability Test Post-Function error handling routine (via {entryPointName}) finished:"
|
||||
+ " No error to be handled."
|
||||
+ " {{FunctionName=\"{FunctionName}\", FunctionInstanceId=\"{FunctionInstanceId}\","
|
||||
+ " ErrorType=\"{ErrorType}\"}}",
|
||||
+ " ErrorType=\"{ErrorType}\", , ErrorMessage=\"{ErrorMessage}\"}}",
|
||||
functionName, functionInstanceId,
|
||||
Format.SpellIfNull(error?.GetType()?.Name));
|
||||
Format.SpellIfNull(null), Format.LimitLength(null, MaxErrorMessageLength, trim: true));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -264,7 +266,7 @@ namespace Microsoft.Azure.WebJobs.Extensions.AvailabilityMonitoring
|
|||
{
|
||||
// This should never happen!
|
||||
|
||||
log?.LogError($"Availability Test Post-Function error handling routine (via {entryPointName}) finised:"
|
||||
log?.LogError($"Availability Test Post-Function error handling routine (via {entryPointName}) finished:"
|
||||
+ " Error: No AvailabilityTestScope was attached to the invocation state - Cannot continue processing!"
|
||||
+ " {{FunctionName=\"{FunctionName}\", FunctionInstanceId=\"{FunctionInstanceId}\"}}"
|
||||
+ " ErrorType=\"{ErrorType}\", ErrorMessage=\"{ErrorMessage}\"}}",
|
||||
|
@ -278,7 +280,8 @@ namespace Microsoft.Azure.WebJobs.Extensions.AvailabilityMonitoring
|
|||
testScope.Complete(error, isTimeout);
|
||||
testScope.Dispose();
|
||||
|
||||
log?.LogDebug($"Availability Test Post-Function error handling routine (via {entryPointName}) finidhed:"
|
||||
log?.LogDebug($"Availability Test Post-Function error handling routine (via {entryPointName}) finished" +
|
||||
$":"
|
||||
+ $" {nameof(AvailabilityTestScope)} was completed and disposed."
|
||||
+ " {{FunctionName=\"{FunctionName}\", FunctionInstanceId=\"{FunctionInstanceId}\","
|
||||
+ " ErrorType=\"{ErrorType}\", ErrorMessage=\"{ErrorMessage}\","
|
||||
|
@ -286,7 +289,7 @@ namespace Microsoft.Azure.WebJobs.Extensions.AvailabilityMonitoring
|
|||
+ " LocationDisplayName=\"{LocationDisplayName}\","
|
||||
+ " LocationId=\"{LocationId}\"}} }}",
|
||||
functionName, functionInstanceId,
|
||||
error.GetType().Name, error.Message,
|
||||
error.GetType().Name, Format.LimitLength(error.Message, MaxErrorMessageLength, trim: true),
|
||||
testScope.TestDisplayName, testScope.LocationDisplayName, testScope.LocationId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@ namespace Microsoft.Azure.WebJobs.Extensions.AvailabilityMonitoring
|
|||
|
||||
private static readonly Random Rnd = new Random();
|
||||
|
||||
|
||||
internal static bool IsSpecification(string testIntervalSpec)
|
||||
{
|
||||
// Ignore nulls and empty strings:
|
||||
|
|
Загрузка…
Ссылка в новой задаче