//----------------------------------------------------------------------------- // // Copyright 2016 Amazon.com, Inc. or its affiliates. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"). // You may not use this file except in compliance with the License. // A copy of the License is located at // // http://aws.amazon.com/apache2.0 // // or in the "license" file accompanying this file. This file is distributed // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either // express or implied. See the License for the specific language governing // permissions and limitations under the License. // //----------------------------------------------------------------------------- using System; using System.Globalization; using System.Numerics; using Amazon.XRay.Recorder.Core.Internal.Utils; namespace Amazon.XRay.Recorder.Core.Internal.Entities { /// /// Provides utilities to manipulate trace id. /// public static class TraceId { // Trace id contains three elements in a dash separated hex encoded string // 1. 4 bit version. Initially the only supported value is 1. // 2. Time as an integer number of seconds since the Epoch. // 3. 96 bit random number. // // Example: // 1-5759e988-bd862e3fe1be46a994272793 // | | | // | | random number // | epoch // | // version private const int Version = 1; private const int ElementsCount = 3; private const int RandomNumberHexDigits = 24; // 96 bits private const int EpochHexDigits = 8; // 32 bits private const int VersionDigits = 1; private const int TotalLength = RandomNumberHexDigits + EpochHexDigits + VersionDigits + ElementsCount - 1; private const char Delimiter = '-'; /// /// Randomly generate a new trace id /// /// A new random trace id public static string NewId() { // Get epoch second as 32bit integer int epoch = (int)DateTime.UtcNow.ToUnixTimeSeconds(); // Get a 96 bit random number string randomNumber = ThreadSafeRandom.GenerateHexNumber(RandomNumberHexDigits); string[] arr = { Version.ToString(CultureInfo.InvariantCulture), epoch.ToString("x", CultureInfo.InvariantCulture), randomNumber }; // Concatenate elements with dash return string.Join(Delimiter.ToString(), arr); } /// /// Check whether the trace id is valid /// /// The trace id /// True if the trace id is valid public static bool IsIdValid(string traceId) { // Is the input valid? if (string.IsNullOrWhiteSpace(traceId)) { return false; } // Is the total length valid? if (traceId.Length != TotalLength) { return false; } string[] elements = traceId.Split(Delimiter); // Is the number of elements valid? if (elements.Length != ElementsCount) { return false; } // Is the version a valid integer? if (!int.TryParse(elements[0], out int idVersion)) { return false; } // Is the version supportted? if (Version != idVersion) { return false; } var idEpoch = elements[1]; var idRand = elements[2]; // Is the size of epoch and random number valid? if (idEpoch.Length != EpochHexDigits || idRand.Length != RandomNumberHexDigits) { return false; } // Is the epoch a valid 32bit hex number? if (!int.TryParse(idEpoch, NumberStyles.HexNumber, null, out _)) { return false; } // Is the random number a valid hex number? if (!BigInteger.TryParse(idRand, NumberStyles.HexNumber, null, out _)) { return false; } return true; } } }