Example #1
0
        public void ValidateDbRemoteDependencyData()
        {
            using ActivitySource activitySource = new ActivitySource(ActivitySourceName);
            using var activity = activitySource.StartActivity(
                      ActivityName,
                      ActivityKind.Client,
                      parentContext: new ActivityContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.Recorded),
                      startTime: DateTime.UtcNow);
            activity.Stop();

            activity.SetStatus(Status.Ok);
            activity.SetTag(SemanticConventions.AttributeDbSystem, "mssql");
            activity.SetTag(SemanticConventions.AttributePeerService, "localhost"); // only adding test via peer.service. all possible combinations are covered in HttpHelperTests.
            activity.SetTag(SemanticConventions.AttributeDbStatement, "Select * from table");

            var monitorTags = AzureMonitorConverter.EnumerateActivityTags(activity);

            var remoteDependencyData = TelemetryPartB.GetRemoteDependencyData(activity, ref monitorTags);

            Assert.Equal(ActivityName, remoteDependencyData.Name);
            Assert.Equal(activity.Context.SpanId.ToHexString(), remoteDependencyData.Id);
            Assert.Equal("Select * from table", remoteDependencyData.Data);
            Assert.Null(remoteDependencyData.ResultCode);
            Assert.Equal(activity.Duration.ToString("c", CultureInfo.InvariantCulture), remoteDependencyData.Duration);
            Assert.Equal(activity.GetStatus() != Status.Error, remoteDependencyData.Success);
            Assert.True(remoteDependencyData.Properties.Count == 0);
            Assert.True(remoteDependencyData.Measurements.Count == 0);
        }
Example #2
0
        public void ValidateHttpRequestData()
        {
            using ActivitySource activitySource = new ActivitySource(ActivitySourceName);
            using var activity = activitySource.StartActivity(
                      ActivityName,
                      ActivityKind.Server,
                      parentContext: new ActivityContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.Recorded),
                      startTime: DateTime.UtcNow);
            activity.Stop();

            var httpUrl = "https://www.foo.bar/search";

            activity.SetStatus(Status.Ok);
            activity.SetTag(SemanticConventions.AttributeHttpMethod, "GET");
            activity.SetTag(SemanticConventions.AttributeHttpUrl, httpUrl); // only adding test via http.url. all possible combinations are covered in HttpHelperTests.
            activity.SetTag(SemanticConventions.AttributeHttpStatusCode, null);

            var monitorTags = AzureMonitorConverter.EnumerateActivityTags(activity);

            var requestData = TelemetryPartB.GetRequestData(activity, ref monitorTags);

            Assert.Equal($"GET {activity.DisplayName}", requestData.Name);
            Assert.Equal(activity.Context.SpanId.ToHexString(), requestData.Id);
            Assert.Equal(httpUrl, requestData.Url);
            Assert.Equal("0", requestData.ResponseCode);
            Assert.Equal(activity.Duration.ToString("c", CultureInfo.InvariantCulture), requestData.Duration);
            Assert.Equal(activity.GetStatus() != Status.Error, requestData.Success);
            Assert.Null(requestData.Source);
            Assert.True(requestData.Properties.Count == 1); //Because of otel_statuscode attribute for activity status. todo: do not add all tags to PartC
            Assert.True(requestData.Measurements.Count == 0);
        }
Example #3
0
        public void ValidateRequestDataSuccess(string activityStatus)
        {
            using ActivitySource activitySource = new ActivitySource(ActivitySourceName);
            using var activity = activitySource.StartActivity(
                      ActivityName,
                      ActivityKind.Server,
                      parentContext: new ActivityContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.Recorded),
                      startTime: DateTime.UtcNow);

            if (activityStatus == "Ok")
            {
                activity.SetStatus(Status.Ok);
            }
            else if (activityStatus == "Error")
            {
                activity.SetStatus(Status.Error);
            }
            else
            {
                activity.SetStatus(Status.Unset);
            }
            activity.SetTag(SemanticConventions.AttributeHttpUrl, "https://www.foo.bar/search");

            var monitorTags = AzureMonitorConverter.EnumerateActivityTags(activity);

            var requestData = TelemetryPartB.GetRequestData(activity, ref monitorTags);

            Assert.Equal(activity.GetStatus() != Status.Error, requestData.Success);
        }
Example #4
0
        public void InitRoleInfo_NullResource()
        {
            AzureMonitorConverter.InitRoleInfo(null);

            Assert.Null(AzureMonitorConverter.RoleName);
            Assert.Null(AzureMonitorConverter.RoleInstance);
        }
Example #5
0
        public void HttpMethodAndHttpRouteIsUsedForHttpRequestOperationName(string route)
        {
            using ActivitySource activitySource = new ActivitySource(ActivitySourceName);
            using var activity = activitySource.StartActivity(
                      ActivityName,
                      ActivityKind.Server,
                      null,
                      startTime: DateTime.UtcNow);
            var resource = CreateTestResource();

            activity.DisplayName = "/getaction";

            activity.SetTag(SemanticConventions.AttributeHttpMethod, "GET");
            activity.SetTag(SemanticConventions.AttributeHttpRoute, route);
            activity.SetTag(SemanticConventions.AttributeHttpUrl, "https://www.foo.bar/search");

            string expectedOperationName;

            if (route == "{controller}/{action}/{id}" || route == null)
            {
                expectedOperationName = "GET /search";
            }
            else
            {
                expectedOperationName = $"GET {route}";
            }

            var monitorTags = AzureMonitorConverter.EnumerateActivityTags(activity);

            var telemetryItem = TelemetryPartA.GetTelemetryItem(activity, ref monitorTags, resource, null);

            Assert.Equal(expectedOperationName, telemetryItem.Tags[ContextTagKeys.AiOperationName.ToString()]);
        }
        public void ExtractRoleInfo_ServiceName()
        {
            var resource = Resources.CreateServiceResource("my-service");

            AzureMonitorConverter.ExtractRoleInfo(resource, out var roleName, out var roleInstance);
            Assert.Equal("my-service", roleName);
            Assert.True(Guid.TryParse(roleInstance, out var guid));
        }
        public void ExtractRoleInfo_Empty()
        {
            var resource = Resources.CreateServiceResource(null);

            AzureMonitorConverter.ExtractRoleInfo(resource, out var roleName, out var roleInstance);
            Assert.Null(roleName);
            Assert.Null(roleInstance);
        }
Example #8
0
 public void InitRoleInfo_ServiceName()
 {
     using var activity = new Activity("InitRoleInfo_ServiceName");
     activity.SetCustomProperty(ResourcePropertyName, Resources.CreateServiceResource("my-service"));
     AzureMonitorConverter.InitRoleInfo(activity);
     Assert.Equal("my-service", AzureMonitorConverter.RoleName);
     Assert.True(Guid.TryParse(AzureMonitorConverter.RoleInstance, out var guid));
 }
Example #9
0
 public void InitRoleInfo_ServiceNamespace()
 {
     using var activity = new Activity("InitRoleInfo_ServiceNamespace");
     activity.SetCustomProperty(ResourcePropertyName, Resources.CreateServiceResource(null, null, "my-namespace"));
     AzureMonitorConverter.InitRoleInfo(activity);
     Assert.Null(AzureMonitorConverter.RoleName);
     Assert.Null(AzureMonitorConverter.RoleInstance);
 }
Example #10
0
 public void InitRoleInfo_ServiceNameAndInstance()
 {
     using var activity = new Activity("InitRoleInfo_ServiceNameAndInstance");
     activity.SetCustomProperty(ResourcePropertyName, Resources.CreateServiceResource("my-service", "roleInstance_1"));
     AzureMonitorConverter.InitRoleInfo(activity);
     Assert.Equal("my-service", AzureMonitorConverter.RoleName);
     Assert.Equal("roleInstance_1", AzureMonitorConverter.RoleInstance);
 }
        public void ExtractRoleInfo_ServiceNameAndInstanceAndNamespace()
        {
            var resource = Resources.CreateServiceResource("my-service", "roleInstance_1", "my-namespace");

            AzureMonitorConverter.ExtractRoleInfo(resource, out var roleName, out var roleInstance);
            Assert.Equal("my-namespace.my-service", roleName);
            Assert.Equal("roleInstance_1", roleInstance);
        }
        public void ExtractRoleInfo_ServiceNamespace()
        {
            var resource = Resources.CreateServiceResource(null, null, "my-namespace");

            AzureMonitorConverter.ExtractRoleInfo(resource, out var roleName, out var roleInstance);
            Assert.Empty(resource.Attributes);
            Assert.Null(roleName);
            Assert.Null(roleInstance);
        }
Example #13
0
        public void ExtractRoleInfo_ServiceInstance()
        {
            var resource = OpenTelemetry.Resources.Resources.CreateServiceResource(null, "roleInstance_1");

            AzureMonitorConverter.ExtractRoleInfo(resource, out var roleName, out var roleInstance);
            Assert.Empty(resource.Attributes);
            Assert.Null(roleName);
            Assert.Null(roleInstance);
        }
Example #14
0
 public void GetMessagingUrl_Success()
 {
     Assert.Equal("test", AzureMonitorConverter.GetMessagingUrl(new Dictionary <string, string> {
         [SemanticConventions.AttributeMessagingUrl] = "test"
     }));
     Assert.Null(AzureMonitorConverter.GetMessagingUrl(new Dictionary <string, string> {
         [SemanticConventions.AttributeMessagingUrl] = null
     }));
 }
        public void LinksAreTruncatedWhenCannotFitInMaxLength(string telemetryType)
        {
            using ActivitySource activitySource = new ActivitySource(ActivitySourceName);
            List <ActivityLink> links = new List <ActivityLink>();

            int numberOfLinks = 150; //arbitrary number > 100

            for (int i = 0; i < numberOfLinks; i++)
            {
                ActivityLink activityLink = new ActivityLink(new ActivityContext(
                                                                 ActivityTraceId.CreateRandom(),
                                                                 ActivitySpanId.CreateRandom(),
                                                                 ActivityTraceFlags.None), null);
                links.Add(activityLink);
            }

            string expectedMSlinks = GetExpectedMSlinks(links.GetRange(0, MaxLinksAllowed));
            string actualMSlinks   = null;

            using var activity = activitySource.StartActivity(
                      ActivityName,
                      ActivityKind.Client,
                      parentContext: default,
                      null,
                      links,
                      startTime: DateTime.UtcNow);

            var monitorTags = AzureMonitorConverter.EnumerateActivityTags(activity);

            if (telemetryType == "RequestData")
            {
                var telemetryPartBRequestData = TelemetryPartB.GetRequestData(activity, ref monitorTags);
                Assert.True(telemetryPartBRequestData.Properties.TryGetValue(msLinks, out actualMSlinks));
            }
            if (telemetryType == "RemoteDependencyData")
            {
                var telemetryPartBRemoteDependencyData = TelemetryPartB.GetRemoteDependencyData(activity, ref monitorTags);
                Assert.True(telemetryPartBRemoteDependencyData.Properties.TryGetValue(msLinks, out actualMSlinks));
            }

            // Check for valid JSON string
            try
            {
                JsonDocument document = JsonDocument.Parse(actualMSlinks);
            }
            catch (Exception)
            {
                Assert.True(false, "_MSlinks should be a JSON formatted string");
            }

            Assert.True(actualMSlinks.Length <= MaxLength);
            Assert.Equal(actualMSlinks, expectedMSlinks);
        }
Example #16
0
        public void GeneratePartAEnvelope_DefaultActivity()
        {
            var activity      = CreateTestActivity();
            var telemetryItem = AzureMonitorConverter.GeneratePartAEnvelope(activity);

            Assert.Equal("RemoteDependency", telemetryItem.Name);
            Assert.Equal(activity.StartTimeUtc.ToString(CultureInfo.InvariantCulture), telemetryItem.Time);
            Assert.Null(telemetryItem.Tags[ContextTagKeys.AiCloudRole.ToString()]);
            Assert.Null(telemetryItem.Tags[ContextTagKeys.AiCloudRoleInstance.ToString()]);
            Assert.NotNull(telemetryItem.Tags[ContextTagKeys.AiOperationId.ToString()]);
            Assert.NotNull(telemetryItem.Tags[ContextTagKeys.AiInternalSdkVersion.ToString()]);
            Assert.Throws <KeyNotFoundException>(() => telemetryItem.Tags[ContextTagKeys.AiOperationParentId.ToString()]);
        }
Example #17
0
        public void GeneratePartAEnvelope_ActivityWithRoleInformation()
        {
            var activity = CreateTestActivity(
                resource: Resources.CreateServiceResource("BusyWorker", "TEST3650724"));

            var telemetryItem = AzureMonitorConverter.GeneratePartAEnvelope(activity);

            Assert.Equal("RemoteDependency", telemetryItem.Name);
            Assert.Equal(activity.StartTimeUtc.ToString(CultureInfo.InvariantCulture), telemetryItem.Time);
            Assert.Equal("BusyWorker", telemetryItem.Tags[ContextTagKeys.AiCloudRole.ToString()]);
            Assert.Equal("TEST3650724", telemetryItem.Tags[ContextTagKeys.AiCloudRoleInstance.ToString()]);
            Assert.Equal(activity.TraceId.ToHexString(), telemetryItem.Tags[ContextTagKeys.AiOperationId.ToString()]);
            Assert.Equal(SdkVersionUtils.SdkVersion, telemetryItem.Tags[ContextTagKeys.AiInternalSdkVersion.ToString()]);
            Assert.Throws <KeyNotFoundException>(() => telemetryItem.Tags[ContextTagKeys.AiOperationParentId.ToString()]);
        }
        public void AiUserAgentIsNullByDefault()
        {
            using ActivitySource activitySource = new ActivitySource(ActivitySourceName);
            using var activity = activitySource.StartActivity(
                      ActivityName,
                      ActivityKind.Server,
                      null,
                      startTime: DateTime.UtcNow);
            var resource = CreateTestResource();

            var monitorTags = AzureMonitorConverter.EnumerateActivityTags(activity);

            var telemetryItem = TelemetryPartA.GetTelemetryItem(activity, ref monitorTags, resource, null);

            Assert.Null(telemetryItem.Tags["ai.user.userAgent"]);
        }
        public void RoleInstanceIsSetToHostNameByDefault()
        {
            using ActivitySource activitySource = new ActivitySource(ActivitySourceName);
            using var activity = activitySource.StartActivity(
                      ActivityName,
                      ActivityKind.Server,
                      null,
                      startTime: DateTime.UtcNow);
            var resource = CreateTestResource();

            var monitorTags = AzureMonitorConverter.EnumerateActivityTags(activity);

            var telemetryItem = TelemetryPartA.GetTelemetryItem(activity, ref monitorTags, resource, null);

            Assert.Equal(Dns.GetHostName(), telemetryItem.Tags[ContextTagKeys.AiCloudRoleInstance.ToString()]);
        }
        public void RoleInstanceIsNotOverwrittenIfSetViaServiceInstanceId()
        {
            using ActivitySource activitySource = new ActivitySource(ActivitySourceName);
            using var activity = activitySource.StartActivity(
                      ActivityName,
                      ActivityKind.Server,
                      null,
                      startTime: DateTime.UtcNow);
            var resource = CreateTestResource(null, null, "serviceinstance");

            var monitorTags = AzureMonitorConverter.EnumerateActivityTags(activity);

            var telemetryItem = TelemetryPartA.GetTelemetryItem(activity, ref monitorTags, resource, null);

            Assert.Equal("serviceinstance", telemetryItem.Tags[ContextTagKeys.AiCloudRoleInstance.ToString()]);
        }
Example #21
0
        public void DependencyTypeisSetToInProcForInternalSpanWithParent()
        {
            using ActivitySource activitySource = new ActivitySource(ActivitySourceName);
            using var parentActivity            = activitySource.StartActivity("ParentActivity", ActivityKind.Internal);
            using var childActivity             = activitySource.StartActivity("ChildActivity", ActivityKind.Internal);

            var monitorTagsParent = AzureMonitorConverter.EnumerateActivityTags(parentActivity);

            var remoteDependencyDataTypeForParent = TelemetryPartB.GetRemoteDependencyData(parentActivity, ref monitorTagsParent).Type;

            Assert.Null(remoteDependencyDataTypeForParent);

            var monitorTagsChild = AzureMonitorConverter.EnumerateActivityTags(childActivity);

            var remoteDependencyDataTypeForChild = TelemetryPartB.GetRemoteDependencyData(childActivity, ref monitorTagsChild).Type;

            Assert.Equal("InProc", remoteDependencyDataTypeForChild);
        }
Example #22
0
        public void ValidateDBDependencyType(string dbSystem)
        {
            using ActivitySource activitySource = new ActivitySource(ActivitySourceName);
            using var activity = activitySource.StartActivity(
                      ActivityName,
                      ActivityKind.Server,
                      parentContext: new ActivityContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.Recorded),
                      startTime: DateTime.UtcNow);

            activity.SetTag(SemanticConventions.AttributeDbSystem, dbSystem);

            var monitorTags = AzureMonitorConverter.EnumerateActivityTags(activity);

            var remoteDependencyDataType = TelemetryPartB.GetRemoteDependencyData(activity, ref monitorTags).Type;
            var expectedType             = TelemetryPartB.SqlDbs.Contains(dbSystem) ? "SQL" : dbSystem;

            Assert.Equal(expectedType, remoteDependencyDataType);
        }
        public void ActivityNameIsUsedByDefaultForRequestOperationName()
        {
            using ActivitySource activitySource = new ActivitySource(ActivitySourceName);
            using var activity = activitySource.StartActivity(
                      ActivityName,
                      ActivityKind.Server,
                      null,
                      startTime: DateTime.UtcNow);
            var resource = CreateTestResource();

            activity.DisplayName = "displayname";

            var monitorTags = AzureMonitorConverter.EnumerateActivityTags(activity);

            var telemetryItem = TelemetryPartA.GetTelemetryItem(activity, ref monitorTags, resource, null);

            Assert.Equal("displayname", telemetryItem.Tags[ContextTagKeys.AiOperationName.ToString()]);
        }
        public void AiLocationIpisSetAsNetPeerIpForServerSpans()
        {
            using ActivitySource activitySource = new ActivitySource(ActivitySourceName);
            using var activity = activitySource.StartActivity(
                      ActivityName,
                      ActivityKind.Server,
                      null,
                      startTime: DateTime.UtcNow);
            var resource = CreateTestResource();

            activity.SetTag(SemanticConventions.AttributeNetPeerIp, "127.0.0.1");

            var monitorTags = AzureMonitorConverter.EnumerateActivityTags(activity);

            var telemetryItem = TelemetryPartA.GetTelemetryItem(activity, ref monitorTags, resource, null);

            Assert.Equal("127.0.0.1", telemetryItem.Tags[ContextTagKeys.AiLocationIp.ToString()]);
        }
Example #25
0
        public void HttpDependencyNameIsActivityDisplayNameByDefault()
        {
            using ActivitySource activitySource = new ActivitySource(ActivitySourceName);
            using var activity = activitySource.StartActivity(
                      ActivityName,
                      ActivityKind.Client,
                      parentContext: new ActivityContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.Recorded),
                      startTime: DateTime.UtcNow);

            activity.SetTag(SemanticConventions.AttributeHttpMethod, "GET");

            activity.DisplayName = "HTTP GET";

            var monitorTags = AzureMonitorConverter.EnumerateActivityTags(activity);

            var remoteDependencyDataName = TelemetryPartB.GetRemoteDependencyData(activity, ref monitorTags).Name;

            Assert.Equal(activity.DisplayName, remoteDependencyDataName);
        }
Example #26
0
        public void ValidateHttpRequestDataResponseCode(string httpStatusCode)
        {
            using ActivitySource activitySource = new ActivitySource(ActivitySourceName);
            using var activity = activitySource.StartActivity(
                      ActivityName,
                      ActivityKind.Server,
                      parentContext: new ActivityContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.Recorded),
                      startTime: DateTime.UtcNow);

            var httpResponseCode = httpStatusCode ?? "0";

            activity.SetTag(SemanticConventions.AttributeHttpUrl, "https://www.foo.bar/search");
            activity.SetTag(SemanticConventions.AttributeHttpStatusCode, httpStatusCode);

            var monitorTags = AzureMonitorConverter.EnumerateActivityTags(activity);

            var requestData = TelemetryPartB.GetRequestData(activity, ref monitorTags);

            Assert.Equal(httpResponseCode, requestData.ResponseCode);
        }
        public void HttpMethodAndActivityNameIsUsedForHttpRequestOperationName()
        {
            using ActivitySource activitySource = new ActivitySource(ActivitySourceName);
            using var activity = activitySource.StartActivity(
                      ActivityName,
                      ActivityKind.Server,
                      null,
                      startTime: DateTime.UtcNow);
            var resource = CreateTestResource();

            activity.DisplayName = "/getaction";

            activity.SetTag(SemanticConventions.AttributeHttpMethod, "GET");

            var monitorTags = AzureMonitorConverter.EnumerateActivityTags(activity);

            var telemetryItem = TelemetryPartA.GetTelemetryItem(activity, ref monitorTags, resource, null);

            Assert.Equal("GET /getaction", telemetryItem.Tags[ContextTagKeys.AiOperationName.ToString()]);
        }
        public void AiUserAgentisSetAsHttpUserAgent()
        {
            using ActivitySource activitySource = new ActivitySource(ActivitySourceName);
            using var activity = activitySource.StartActivity(
                      ActivityName,
                      ActivityKind.Server,
                      null,
                      startTime: DateTime.UtcNow);
            var resource = CreateTestResource();

            var userAgent = "Mozilla / 5.0(Windows NT 10.0;WOW64) AppleWebKit / 537.36(KHTML, like Gecko) Chrome / 91.0.4472.101 Safari / 537.36";

            activity.SetTag(SemanticConventions.AttributeHttpUserAgent, userAgent);

            var monitorTags = AzureMonitorConverter.EnumerateActivityTags(activity);

            var telemetryItem = TelemetryPartA.GetTelemetryItem(activity, ref monitorTags, resource, null);

            Assert.Equal(userAgent, telemetryItem.Tags["ai.user.userAgent"]);
        }
Example #29
0
        public void ValidateSuccessForRequestAndRemoteDependency(string activityStatusCode, string activityStatusDescription)
        {
            using ActivitySource activitySource = new ActivitySource(ActivitySourceName);
            using var activity = activitySource.StartActivity(
                      ActivityName,
                      ActivityKind.Server,
                      parentContext: new ActivityContext(ActivityTraceId.CreateRandom(), ActivitySpanId.CreateRandom(), ActivityTraceFlags.Recorded),
                      startTime: DateTime.UtcNow);

            activity.SetTag("otel.status_code", activityStatusCode);
            activity.SetTag("otel.status_description", activityStatusDescription);

            activity.SetTag(SemanticConventions.AttributeHttpUrl, "https://www.foo.bar/search");

            var monitorTags = AzureMonitorConverter.EnumerateActivityTags(activity);

            var requestData          = TelemetryPartB.GetRequestData(activity, ref monitorTags);
            var remoteDependencyData = TelemetryPartB.GetRequestData(activity, ref monitorTags);

            Assert.Equal(activity.GetStatus().StatusCode != StatusCode.Error, requestData.Success);
            Assert.Equal(activity.GetStatus().StatusCode != StatusCode.Error, remoteDependencyData.Success);
        }
        public void TelemetryPartBPropertiesDoesNotContainMSLinksWhenActivityHasNoLinks(string telemetryType)
        {
            using ActivitySource activitySource = new ActivitySource(ActivitySourceName);
            using var activity = activitySource.StartActivity(
                      ActivityName,
                      ActivityKind.Client,
                      parentContext: default,
                      startTime: DateTime.UtcNow);

            var monitorTags = AzureMonitorConverter.EnumerateActivityTags(activity);

            if (telemetryType == "RequestData")
            {
                var telemetryPartBRequestData = TelemetryPartB.GetRequestData(activity, ref monitorTags);
                Assert.False(telemetryPartBRequestData.Properties.TryGetValue(msLinks, out var mslinks));
            }
            if (telemetryType == "RemoteDependencyData")
            {
                var telemetryPartBRemoteDependencyData = TelemetryPartB.GetRemoteDependencyData(activity, ref monitorTags);
                Assert.False(telemetryPartBRemoteDependencyData.Properties.TryGetValue(msLinks, out var mslinks));
            }
        }