//----------------------------------------------------------------------------- // // 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 Amazon.Runtime.Internal.Util; using Amazon.XRay.Recorder.Core.Sampling; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Threading; using Amazon.XRay.Recorder.Core.Exceptions; namespace Amazon.XRay.Recorder.Core.Internal.Entities { /// /// A trace segment tracks a period of time associated with a computation or action, along with annotations and key / value data. /// A set of trace segments all of which share the same tracing ID form a trace. /// /// [Serializable] public class Segment : Entity { private long _size; // Total number of subsegments private Lazy> _lazyService = new Lazy>(); /// /// Initializes a new instance of the class. /// /// Name of the node or service component. /// Unique id for the trace. /// Unique id of the upstream segment. public Segment(string name, string traceId = null, string parentId = null) : base(name) { if (traceId != null) { this.TraceId = traceId; } else { this.TraceId = Entities.TraceId.NewId(); } if (parentId != null) { this.ParentId = parentId; } RootSegment = this; } /// /// Gets or Sets the User for the segment /// public string User { get; set; } /// /// Gets or sets the origin of the segment. /// public string Origin { get; set; } /// /// Gets the size of subsegments. /// public long Size { get { return Interlocked.Read(ref _size); } } /// /// Gets the service. /// public IDictionary Service { get { return _lazyService.Value; } } /// /// Gets a value indicating whether any value has been added to service. /// public bool IsServiceAdded { get { return _lazyService.IsValueCreated && !_lazyService.Value.IsEmpty; } } /// /// Increment the size count. /// public void IncrementSize() { Interlocked.Increment(ref _size); } /// /// Decrement the size count. /// public void DecrementSize() { Interlocked.Decrement(ref _size); } /// /// Release reference to this instance of segment. /// /// Reference count after release. public override long Release() { return DecrementReferenceCounter(); } /// /// Check if this segment or the root segment that this segment belongs to is ok to emit. /// /// If the segment is ready to emit. public override bool IsEmittable() { return Reference == 0; } /// /// Checks if the segment has been streamed already /// /// The segment has been already streamed and no further operation can be performed on it. private void HasAlreadyStreamed() { if(HasStreamed) { throw new AlreadyEmittedException("Segment " + Name + " has already been emitted."); } } /// /// Gets the value of the User for this segment /// public string GetUser() { return User; } /// /// Sets the User for this segment /// /// the name of the user /// The value of user cannot be null. public void SetUser(string user) { if (user == null) { throw new ArgumentNullException(nameof(user)); } HasAlreadyStreamed(); this.User = user; } } }