未验证 提交 762cd261 编写于 作者: R Rikki Gibson 提交者: GitHub

Merge pull request #45151 from ryzngard/issue/telemetry_determinism

Fix possible problem with TelemetryId
// 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 Microsoft.CodeAnalysis.Editor.Shared.Extensions;
using Xunit;
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Extensions
{
public class TelemetryExtensionTests
{
[Fact]
public void TestConstantTelemetryId()
{
var expected = Guid.Parse("00000000-0000-0000-c4c5-914100000000");
var actual = typeof(TelemetryExtensionTests).GetTelemetryId();
var actualBytes = actual.ToByteArray();
// The first 4 bytes are using platform dependent hashcode and
// are not deterministic. This is a known limitation and corrected
// with the last 8 bytes of the GUID
for (int i = 0; i < 4; i++)
{
actualBytes[i] = 0;
}
// If the assertion fails then telemetry ids could be changing
// making them hard to track. It's important to not regress
// the ability to track telemetry across versions of Roslyn.
Assert.Equal(new Guid(actualBytes), expected);
}
}
}
......@@ -12,14 +12,31 @@ namespace Microsoft.CodeAnalysis.Editor.Shared.Extensions
internal static class TelemetryExtensions
{
public static Guid GetTelemetryId(this Type type, short scope = 0)
=> new Guid(type.GetTelemetryPrefix(), scope, 0, 0, 0, 0, 0, 0, 0, 0, 0);
public static int GetTelemetryPrefix(this Type type)
{
type = GetTypeForTelemetry(type);
// AssemblyQualifiedName will change across version numbers, FullName won't
return type.FullName.GetHashCode();
// GetHashCode on string is not stable. From documentation:
// The hash code itself is not guaranteed to be stable.
// Hash codes for identical strings can differ across .NET implementations, across .NET versions,
// and across .NET platforms (such as 32-bit and 64-bit) for a single version of .NET. In some cases,
// they can even differ by application domain.
// This implies that two subsequent runs of the same program may return different hash codes.
//
// As such, we keep the original prefix that was being used for legacy purposes, but
// use a stable hashing algorithm (FNV) that doesn't depend on platform
// or .NET implementation. We can map the prefix across legacy versions, but
// as we support more platforms and variations of builds the suffix will be constant
// and usable
var prefix = type.FullName.GetHashCode();
var suffix = Roslyn.Utilities.Hash.GetFNVHashCode(type.FullName);
// Suffix is the remaining 8 bytes, and the hash code only makes up 4. Pad
// the remainder with an empty byte array
var suffixBytes = BitConverter.GetBytes(suffix).Concat(new byte[4]).ToArray();
return new Guid(prefix, scope, 0, suffixBytes);
}
public static Type GetTypeForTelemetry(this Type type)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册