public override IEnumerator <Tag> GetEnumerator() { return(new List <Tag>() { Tag.Create(TagKey.Create("key"), TagValue.Create("value")) }.GetEnumerator()); }
protected internal void HandleHeapEvent(CLRRuntimeSource.HeapMetrics metrics) { StatsRecorder .NewMeasureMap() .Put(memoryUsedMeasure, metrics.TotalMemory) .Record(memoryTagValues); for (int i = 0; i < metrics.CollectionCounts.Count; i++) { var count = metrics.CollectionCounts[i]; if (previous.CollectionCounts != null && i < previous.CollectionCounts.Count) { if (previous.CollectionCounts[i] <= count) { count = count - previous.CollectionCounts[i]; } } var tagContext = Tagger .EmptyBuilder .Put(generationKey, TagValue.Create(GENERATION_TAGVALUE_NAME + i.ToString())) .Build(); StatsRecorder .NewMeasureMap() .Put(collectionCountMeasure, count) .Record(tagContext); } previous = metrics; }
public void TestRoundtrip_TagContextWithMaximumSize() { ITagContextBuilder builder = tagger.EmptyBuilder; for (int i = 0; i < SerializationUtils.TagContextSerializedSizeLimit / 8; i++) { // Each tag will be with format {key : "0123", value : "0123"}, so the length of it is 8. // Add 1024 tags, the total size should just be 8192. String str; if (i < 10) { str = "000" + i; } else if (i < 100) { str = "00" + i; } else if (i < 1000) { str = "0" + i; } else { str = "" + i; } builder.Put(TagKey.Create(str), TagValue.Create(str)); } TestRoundtripSerialization(builder.Build()); }
public void GetMetricName_ReturnsExpected() { var opts = new CloudFoundryForwarderOptions(); var stats = new OpenCensusStats(); var ep = new SpringBootMetricWriter(opts, stats); IList <ITagKey> keys = new List <ITagKey>() { TagKey.Create("status"), TagKey.Create("exception"), TagKey.Create("method"), TagKey.Create("uri") }; IList <ITagValue> values = new List <ITagValue>() { TagValue.Create("200"), TagValue.Create("None"), TagValue.Create("GET"), TagValue.Create("/foo/bar") }; var tagDict = ep.GetTagKeysAndValues(keys, values); Assert.Equal("http.server.requests.mean.GET.200.foo.bar", ep.GetMetricName("http.server.requests", "mean", tagDict)); Assert.Equal("http.server.requests.mean", ep.GetMetricName("http.server.requests", "mean", new Dictionary <string, string>())); keys = new List <ITagKey>() { TagKey.Create("foo"), TagKey.Create("bar") }; values = new List <ITagValue>() { TagValue.Create("foo"), TagValue.Create("bar") }; tagDict = ep.GetTagKeysAndValues(keys, values); Assert.Equal("http.server.requests.bar.foo", ep.GetMetricName("http.server.requests", null, tagDict)); }
public void TestSerializeTooLargeTagContext() { var builder = tagger.EmptyBuilder; for (var i = 0; i < SerializationUtils.TagContextSerializedSizeLimit / 8 - 1; i++) { // Each tag will be with format {key : "0123", value : "0123"}, so the length of it is 8. String str; if (i < 10) { str = "000" + i; } else if (i < 100) { str = "00" + i; } else if (i < 1000) { str = "0" + i; } else { str = i.ToString(); } builder.Put(TagKey.Create(str), TagValue.Create(str)); } // The last tag will be of size 9, so the total size of the TagContext (8193) will be one byte // more than limit. builder.Put(TagKey.Create("last"), TagValue.Create("last1")); var tagContext = builder.Build(); Assert.Throws <TagContextSerializationException>(() => serializer.ToByteArray(tagContext)); }
public void CreateMetrics_CountAgg_ReturnsExpected() { var opts = new CloudFoundryForwarderOptions(); var stats = new OpenCensusStats(); var tagsComponent = new TagsComponent(); var tagger = tagsComponent.Tagger; var ep = new MicrometerMetricWriter(opts, stats); IMeasureDouble testMeasure = MeasureDouble.Create("test.total", "test", MeasureUnit.Bytes); SetupTestView(stats, Count.Create(), testMeasure, "test.test1"); ITagContext context1 = tagger .EmptyBuilder .Put(TagKey.Create("a"), TagValue.Create("v1")) .Put(TagKey.Create("b"), TagValue.Create("v1")) .Put(TagKey.Create("c"), TagValue.Create("v1")) .Build(); long allKeyssum = 0; for (int i = 0; i < 10; i++) { allKeyssum = allKeyssum + i; stats.StatsRecorder.NewMeasureMap().Put(testMeasure, i).Record(context1); } var viewData = stats.ViewManager.GetView(ViewName.Create("test.test1")); Assert.NotNull(viewData); var aggMap = viewData.AggregationMap; Assert.Single(aggMap); var tagValues = aggMap.Keys.Single(); var data = aggMap.Values.Single(); Assert.NotNull(tagValues); Assert.NotNull(data); var result = ep.CreateMetrics(viewData, data, tagValues, 1L); Assert.NotNull(result); Assert.Single(result); var metric = result[0]; Assert.Equal("test.test1", metric.Name); Assert.Equal(1L, metric.Timestamp); Assert.Equal("gauge", metric.Type); Assert.Equal("bytes", metric.Unit); Assert.Equal(10, metric.Value); var tags = metric.Tags; Assert.Equal("count", tags["statistic"]); Assert.Equal("v1", tags["a"]); Assert.Equal("v1", tags["b"]); Assert.Equal("v1", tags["c"]); }
// TODO(sebright): Consider exposing a TagValue validation method to avoid needing to catch // an IllegalArgumentException here. private static ITagValue CreateTagValue(ITagKey key, String value) { try { return(TagValue.Create(value)); } catch (Exception e) { throw new TagContextDeserializationException( "Invalid tag value for key " + key + ": " + value, e); } }
public void HandleThreadsEvent_RecordsValues() { var options = new MetricsEndpointOptions(); var stats = new OpenCensusStats(); var tags = new OpenCensusTags(); var observer = new CLRRuntimeObserver(options, stats, tags, null); CLRRuntimeSource.ThreadMetrics metrics = new CLRRuntimeSource.ThreadMetrics(100, 100, 200, 200); observer.HandleThreadsEvent(metrics); var live = stats.ViewManager.GetView(ViewName.Create("clr.threadpool.active")); var aggData = MetricsHelpers.SumWithTags(live) as IMeanData; Assert.Equal(100, aggData.Mean); Assert.Equal(100, aggData.Min); Assert.Equal(100, aggData.Max); aggData = MetricsHelpers.SumWithTags(live, new List <ITagValue>() { TagValue.Create("worker") }) as IMeanData; Assert.Equal(100, aggData.Mean); Assert.Equal(100, aggData.Min); Assert.Equal(100, aggData.Max); aggData = MetricsHelpers.SumWithTags(live, new List <ITagValue>() { TagValue.Create("completionPort") }) as IMeanData; Assert.Equal(100, aggData.Mean); Assert.Equal(100, aggData.Min); Assert.Equal(100, aggData.Max); var avail = stats.ViewManager.GetView(ViewName.Create("clr.threadpool.avail")); aggData = MetricsHelpers.SumWithTags(avail) as IMeanData; Assert.Equal(100, aggData.Mean); Assert.Equal(100, aggData.Min); Assert.Equal(100, aggData.Max); aggData = MetricsHelpers.SumWithTags(avail, new List <ITagValue>() { TagValue.Create("worker") }) as IMeanData; Assert.Equal(100, aggData.Mean); Assert.Equal(100, aggData.Min); Assert.Equal(100, aggData.Max); aggData = MetricsHelpers.SumWithTags(avail, new List <ITagValue>() { TagValue.Create("completionPort") }) as IMeanData; Assert.Equal(100, aggData.Mean); Assert.Equal(100, aggData.Min); Assert.Equal(100, aggData.Max); }
public void GetTagKeysAndValues_ReturnsExpected() { var opts = new CloudFoundryForwarderOptions(); var stats = new OpenCensusStats(); var ep = new SpringBootMetricWriter(opts, stats); IList <ITagKey> keys = new List <ITagKey>() { TagKey.Create("status"), TagKey.Create("exception"), TagKey.Create("method"), TagKey.Create("uri") }; IList <ITagValue> values = new List <ITagValue>() { TagValue.Create("v1"), TagValue.Create("v2"), TagValue.Create("v3"), TagValue.Create("v4") }; var result = ep.GetTagKeysAndValues(keys, values); Assert.Equal("v1", result["status"]); Assert.Equal("v2", result["exception"]); Assert.Equal("v3", result["method"]); Assert.Equal("v4", result["uri"]); // Verify sorted var sortedKeys = result.Keys.ToList(); Assert.Equal("exception", sortedKeys[0]); Assert.Equal("method", sortedKeys[1]); Assert.Equal("status", sortedKeys[2]); Assert.Equal("uri", sortedKeys[3]); values = new List <ITagValue>() { TagValue.Create("v1"), null, null, null }; result = ep.GetTagKeysAndValues(keys, values); Assert.Equal("v1", result["status"]); Assert.Single(result); values = new List <ITagValue>() { null, TagValue.Create("v2"), null, null }; result = ep.GetTagKeysAndValues(keys, values); Assert.Equal("v2", result["exception"]); Assert.Single(result); values = new List <ITagValue>() { TagValue.Create("v1"), }; result = ep.GetTagKeysAndValues(keys, values); Assert.Empty(result); }
public void TestDeserializeOneTag() { var output = new MemoryStream(); output.WriteByte(SerializationUtils.VersionId); EncodeTagToOutPut("Key", "Value", output); var expected = tagger.EmptyBuilder.Put(TagKey.Create("Key"), TagValue.Create("Value")).Build(); Assert.Equal(expected, serializer.FromByteArray(output.ToArray())); }
public void Invoke_WithMetricsRequest_ReturnsExpected() { var opts = new MetricsEndpointOptions(); var stats = new OpenCensusStats(); var tagsComponent = new TagsComponent(); var tagger = tagsComponent.Tagger; var ep = new MetricsEndpoint(opts, stats); var testMeasure = MeasureDouble.Create("test.total", "test", MeasureUnit.Bytes); SetupTestView(stats, Sum.Create(), testMeasure, "test.test1"); var context1 = tagger .EmptyBuilder .Put(TagKey.Create("a"), TagValue.Create("v1")) .Put(TagKey.Create("b"), TagValue.Create("v1")) .Put(TagKey.Create("c"), TagValue.Create("v1")) .Build(); long allKeyssum = 0; for (var i = 0; i < 10; i++) { allKeyssum += i; stats.StatsRecorder.NewMeasureMap().Put(testMeasure, i).Record(context1); } var alltags = new List <KeyValuePair <string, string> >() { new KeyValuePair <string, string>("a", "v1"), new KeyValuePair <string, string>("b", "v1"), new KeyValuePair <string, string>("c", "v1") }; var req = new MetricsRequest("test.test1", alltags); var resp = ep.Invoke(req) as MetricsResponse; Assert.NotNull(resp); Assert.Equal("test.test1", resp.Name); Assert.NotNull(resp.Measurements); Assert.Single(resp.Measurements); var sample = resp.Measurements[0]; Assert.Equal(MetricStatistic.TOTAL, sample.Statistic); Assert.Equal(allKeyssum, sample.Value); Assert.NotNull(resp.AvailableTags); Assert.Equal(3, resp.AvailableTags.Count); req = new MetricsRequest("foo.bar", alltags); resp = ep.Invoke(req) as MetricsResponse; Assert.Null(resp); }
public void TestTagValueEquals() { var v1 = TagValue.Create("foo"); var v2 = TagValue.Create("foo"); var v3 = TagValue.Create("bar"); Assert.Equal(v1, v2); Assert.NotEqual(v1, v3); Assert.NotEqual(v2, v3); Assert.Equal(v3, v3); }
public void Create_AllowTagValueWithMaxLength() { char[] chars = new char[TagValue.MAX_LENGTH]; for (int i = 0; i < chars.Length; i++) { chars[i] = 'v'; } String value = new String(chars); Assert.Equal(value, TagValue.Create(value).AsString); }
public void Create_DisallowTagValueOverMaxLength() { char[] chars = new char[TagValue.MAX_LENGTH + 1]; for (int i = 0; i < chars.Length; i++) { chars[i] = 'v'; } String value = new String(chars); Assert.Throws <ArgumentOutOfRangeException>(() => TagValue.Create(value)); }
public void TestDeserializeDuplicateTags() { MemoryStream output = new MemoryStream(); output.WriteByte(SerializationUtils.VERSION_ID); EncodeTagToOutPut("Key1", "Value1", output); EncodeTagToOutPut("Key1", "Value1", output); ITagContext expected = tagger.EmptyBuilder.Put(TagKey.Create("Key1"), TagValue.Create("Value1")).Build(); Assert.Equal(expected, serializer.FromByteArray(output.ToArray())); }
public void GetTagValuesInColumnOrder_ReturnsExpected() { var tags = new List <KeyValuePair <string, string> >() { new KeyValuePair <string, string>("foo", "bar"), new KeyValuePair <string, string>("aaa", "bbb") }; var columns = new List <ITagKey>() { TagKey.Create("foo"), TagKey.Create("aaa") }; var opts = new MetricsEndpointOptions(); var stats = new OpenCensusStats(); var ep = new MetricsEndpoint(opts, stats); var result = ep.GetTagValuesInColumnOrder(columns, tags); Assert.NotNull(result); Assert.Equal(2, result.Count); Assert.Equal(TagValue.Create("bar"), result[0]); Assert.Equal(TagValue.Create("bbb"), result[1]); // Invalid tagkey provided columns = new List <ITagKey>() { TagKey.Create("bar"), TagKey.Create("aaa") }; result = ep.GetTagValuesInColumnOrder(columns, tags); Assert.Null(result); // aaa column not provided columns = new List <ITagKey>() { TagKey.Create("foo"), TagKey.Create("aaa"), TagKey.Create("bbb"), }; tags = new List <KeyValuePair <string, string> >() { new KeyValuePair <string, string>("foo", "bar"), new KeyValuePair <string, string>("bbb", "bbb") }; result = ep.GetTagValuesInColumnOrder(columns, tags); Assert.Equal(3, result.Count); Assert.Equal(TagValue.Create("bar"), result[0]); Assert.Null(result[1]); Assert.Equal(TagValue.Create("bbb"), result[2]); }
protected internal ITagContext GetTagContext(HttpWebRequest request, HttpStatusCode status) { var uri = request.RequestUri.ToString(); var statusCode = status.ToString(); return(Tagger .EmptyBuilder .Put(uriTagKey, TagValue.Create(uri)) .Put(statusTagKey, TagValue.Create(statusCode)) .Put(clientTagKey, TagValue.Create(request.RequestUri.Host)) .Put(methodTagKey, TagValue.Create(request.Method.ToString())) .Build()); }
public void Create_AllowTagValueWithMaxLength() { var chars = new char[TagValue.MaxLength]; for (var i = 0; i < chars.Length; i++) { chars[i] = 'v'; } var value = new String(chars); Assert.Equal(value, TagValue.Create(value).AsString); }
protected internal ITagContext GetTagContext(HttpRequestMessage request, HttpResponseMessage response, TaskStatus taskStatus) { var uri = request.RequestUri.ToString(); var statusCode = GetStatusCode(response, taskStatus); return(Tagger .EmptyBuilder .Put(uriTagKey, TagValue.Create(uri)) .Put(statusTagKey, TagValue.Create(statusCode)) .Put(clientTagKey, TagValue.Create(request.RequestUri.Host)) .Put(methodTagKey, TagValue.Create(request.Method.ToString())) .Build()); }
protected internal ITagContext GetTagContext(IOwinContext arg) { var uri = arg.Request.Path.ToString(); var statusCode = arg.Response.StatusCode.ToString(); var exception = GetException(arg); return(Tagger .EmptyBuilder .Put(uriTagKey, TagValue.Create(uri)) .Put(statusTagKey, TagValue.Create(statusCode)) .Put(exceptionTagKey, TagValue.Create(exception)) .Put(methodTagKey, TagValue.Create(arg.Request.Method)) .Build()); }
public void TestTagEquals() { var tag1 = Tag.Create(TagKey.Create("Key"), TagValue.Create("foo")); var tag2 = Tag.Create(TagKey.Create("Key"), TagValue.Create("foo")); var tag3 = Tag.Create(TagKey.Create("Key"), TagValue.Create("bar")); var tag4 = Tag.Create(TagKey.Create("Key2"), TagValue.Create("foo")); Assert.Equal(tag1, tag2); Assert.NotEqual(tag1, tag3); Assert.NotEqual(tag1, tag4); Assert.NotEqual(tag2, tag3); Assert.NotEqual(tag2, tag4); Assert.NotEqual(tag3, tag4); }
public void ParseResourceLabels_ValueWithParenthesis_StrippedValue() { // Arrange string resourceLabels = "k1=\"v1\""; // Act var tags = Resource.ParseResourceLabels(resourceLabels); // Assert Assert.NotNull(tags); Assert.NotEmpty(tags); Assert.Equal(TagKey.Create("k1"), tags[0].Key); Assert.Equal(TagValue.Create("v1"), tags[0].Value); }
public void GetMetricsForExportedViews_ReturnsExpected() { var opts = new CloudFoundryForwarderOptions() { MicrometerMetricWriter = true }; var stats = new OpenCensusStats(); var tagsComponent = new TagsComponent(); var tagger = tagsComponent.Tagger; var ep = new CloudFoundryForwarderExporter(opts, stats); IMeasureDouble testMeasure = MeasureDouble.Create("test.total", "test", MeasureUnit.Bytes); SetupTestView(stats, Sum.Create(), testMeasure, "test.test1"); ITagContext context1 = tagger .EmptyBuilder .Put(TagKey.Create("a"), TagValue.Create("v1")) .Put(TagKey.Create("b"), TagValue.Create("v1")) .Put(TagKey.Create("c"), TagValue.Create("v1")) .Build(); long allKeyssum = 0; for (int i = 0; i < 10; i++) { allKeyssum = allKeyssum + i; stats.StatsRecorder.NewMeasureMap().Put(testMeasure, i).Record(context1); } var result = ep.GetMetricsForExportedViews(stats.ViewManager.AllExportedViews, 1L); Assert.NotNull(result); Assert.Single(result); var metric = result[0]; Assert.Equal("test.test1", metric.Name); Assert.Equal(1L, metric.Timestamp); Assert.Equal("gauge", metric.Type); Assert.Equal("bytes", metric.Unit); Assert.Equal(allKeyssum, metric.Value); var tags = metric.Tags; Assert.Equal("total", tags["statistic"]); Assert.Equal("v1", tags["a"]); Assert.Equal("v1", tags["b"]); Assert.Equal("v1", tags["c"]); }
public void ParseResourceLabels_WrongKeyValueDelimiter_PairIgnored() { // Arrange string resourceLabels = "k1:v1,k2=v2"; // Act var tags = Resource.ParseResourceLabels(resourceLabels); // Assert Assert.NotNull(tags); Assert.NotEmpty(tags); Assert.Single(tags); Assert.Equal(TagKey.Create("k2"), tags[0].Key); Assert.Equal(TagValue.Create("v2"), tags[0].Value); }
internal static object Run(string projectId) { var spanExporter = new StackdriverTraceExporter(projectId); var metricExporter = new StackdriverMetricExporter( projectId, Stats.ViewManager); metricExporter.Start(); var tracerFactory = new TracerFactory(new BatchingSpanProcessor(spanExporter)); var tracer = tracerFactory.GetTracer(string.Empty); var tagContextBuilder = Tagger.CurrentBuilder.Put(FrontendKey, TagValue.Create("mobile-ios9.3.5")); var spanBuilder = tracer .SpanBuilder("incoming request") .SetRecordEvents(true) .SetSampler(Samplers.AlwaysSample); Stats.ViewManager.RegisterView(VideoSizeView); using (tagContextBuilder.BuildScoped()) { using (tracer.WithSpan(spanBuilder.StartSpan())) { tracer.CurrentSpan.AddEvent("Processing video."); Thread.Sleep(TimeSpan.FromMilliseconds(10)); StatsRecorder.NewMeasureMap() .Put(VideoSize, 25 * MiB) .Record(); } } Thread.Sleep(TimeSpan.FromMilliseconds(5100)); var viewData = Stats.ViewManager.GetView(VideoSizeViewName); Console.WriteLine(viewData); Console.WriteLine("Done... wait for events to arrive to backend!"); Console.ReadLine(); spanExporter.ShutdownAsync(CancellationToken.None).GetAwaiter().GetResult(); metricExporter.Stop(); return(null); }
public void GetTagContext_ReturnsExpected() { var options = new MetricsEndpointOptions(); var stats = new OpenCensusStats(); var tags = new OpenCensusTags(); var observer = new HttpClientDesktopObserver(options, stats, tags, null); var req = GetHttpRequestMessage(); var tagContext = observer.GetTagContext(req, HttpStatusCode.InternalServerError); var tagValues = tagContext.ToList(); tagValues.Contains(Tag.Create(TagKey.Create("clientName"), TagValue.Create("localhost:5555"))); tagValues.Contains(Tag.Create(TagKey.Create("uri"), TagValue.Create("/foo/bar"))); tagValues.Contains(Tag.Create(TagKey.Create("status"), TagValue.Create("500"))); tagValues.Contains(Tag.Create(TagKey.Create("method"), TagValue.Create("GET"))); }
public void ParseResourceLabels_CommaSeparated_MapReturned() { // Arrange string resourceLabels = "key1=val1,key2=val2"; // Act var tags = Resource.ParseResourceLabels(resourceLabels); // Assert Assert.NotNull(tags); Assert.Equal(2, tags.Length); Assert.Equal(TagKey.Create("key1"), tags[0].Key); Assert.Equal(TagKey.Create("key2"), tags[1].Key); Assert.Equal(TagValue.Create("val1"), tags[0].Value); Assert.Equal(TagValue.Create("val2"), tags[1].Value); }
public void GetTagKeysAndValues_ReturnsExpected() { var opts = new CloudFoundryForwarderOptions(); var stats = new OpenCensusStats(); var ep = new MicrometerMetricWriter(opts, stats); IList <ITagKey> keys = new List <ITagKey>() { TagKey.Create("key1"), TagKey.Create("key2") }; IList <ITagValue> values = new List <ITagValue>() { TagValue.Create("v1"), TagValue.Create("v2") }; var result = ep.GetTagKeysAndValues(keys, values); Assert.Equal("v1", result["key1"]); Assert.Equal("v2", result["key2"]); values = new List <ITagValue>() { TagValue.Create("v1"), null }; result = ep.GetTagKeysAndValues(keys, values); Assert.Equal("v1", result["key1"]); Assert.Single(result); values = new List <ITagValue>() { null, TagValue.Create("v2"), }; result = ep.GetTagKeysAndValues(keys, values); Assert.Equal("v2", result["key2"]); Assert.Single(result); values = new List <ITagValue>() { TagValue.Create("v1"), }; result = ep.GetTagKeysAndValues(keys, values); Assert.Empty(result); }
internal static object Run() { var config = new TelemetryConfiguration { InstrumentationKey = "instrumentation-key" }; SpanExporter exporter = new ApplicationInsightsTraceExporter(config); var metricExporter = new ApplicationInsightsMetricExporter(Stats.ViewManager, config); metricExporter.Start(); var tagContextBuilder = Tagger.CurrentBuilder.Put(FrontendKey, TagValue.Create("mobile-ios9.3.5")); var tracer = new Tracer(new BatchingSpanProcessor(exporter), TraceConfig.Default); var spanBuilder = tracer .SpanBuilder("incoming request") .SetRecordEvents(true) .SetSampler(Samplers.AlwaysSample); Stats.ViewManager.RegisterView(VideoSizeView); using (tagContextBuilder.BuildScoped()) { using (tracer.WithSpan(spanBuilder.StartSpan())) { tracer.CurrentSpan.AddEvent("Start processing video."); Thread.Sleep(TimeSpan.FromMilliseconds(10)); StatsRecorder.NewMeasureMap().Put(VideoSize, 25 * MiB).Record(); tracer.CurrentSpan.AddEvent("Finished processing video."); } } Thread.Sleep(TimeSpan.FromMilliseconds(5100)); var viewData = Stats.ViewManager.GetView(VideoSizeViewName); Console.WriteLine(viewData); Console.WriteLine("Done... wait for events to arrive to backend!"); Console.ReadLine(); exporter.ShutdownAsync(CancellationToken.None).GetAwaiter().GetResult(); metricExporter.Stop(); return(null); }
/// <summary> /// Creates a label/tag map from the OC_RESOURCE_LABELS environment variable. /// OC_RESOURCE_LABELS: A comma-separated list of labels describing the source in more detail, /// e.g. “key1=val1,key2=val2”. Domain names and paths are accepted as label keys. /// Values may be quoted or unquoted in general. If a value contains whitespaces, =, or " characters, it must /// always be quoted. /// </summary> /// <param name="rawEnvironmentTags">Environment tags as a raw, comma separated string</param> /// <returns>Environment Tags as a list.</returns> internal static ITag[] ParseResourceLabels(string rawEnvironmentTags) { if (rawEnvironmentTags == null) { return(new ITag[0] { }); } else { var labels = new List <ITag>(); string[] rawLabels = rawEnvironmentTags.Split(LabelListSplitter); Regex regex = new Regex("^\"|\"$", RegexOptions.Compiled); foreach (var rawLabel in rawLabels) { string[] keyValuePair = rawLabel.Split(LabelKeyValueSplitter); if (keyValuePair.Length != 2) { continue; } string key = keyValuePair[0].Trim(); string value = Regex.Replace(keyValuePair[1].Trim(), "^\"|\"$", string.Empty); if (!IsValidAndNotEmpty(key)) { Log.InvalidCharactersInResourceElement("Label key"); return(new ITag[0] { }); } if (!IsValid(value)) { Log.InvalidCharactersInResourceElement("Label key"); return(new ITag[0] { }); } labels.Add(new Tag(TagKey.Create(key), TagValue.Create(value))); } return(labels.ToArray()); } }