Beispiel #1
0
        public TupleList <decimal, Metric> CalculateMetrics <TCurrent>(List <TCurrent> telemetryTuples)
            where TCurrent : ITelemetry
        {
            var result = new TupleList <decimal, Metric>();

            var totalRequestRate = telemetryTuples
                                   .Where(t => t.MetricName.Equals(MetricConstants.TotalRequestsMetricName, StringComparison.OrdinalIgnoreCase))
                                   .Select(
                t =>
            {
                var newMetric = new Tuple <decimal, Metric>(
                    Math.Round((t.Value * 60) / monitoringIntervalInSeconds, 3),
                    TotalRequestsRateMetric);

                return(newMetric);
            });

            result.AddRange(totalRequestRate);

            var failedRequestRate = telemetryTuples
                                    .Where(t => t.MetricName.Equals(MetricConstants.FailedRequestsMetricName, StringComparison.OrdinalIgnoreCase))
                                    .Select(
                t =>
            {
                var newMetric = new Tuple <decimal, Metric>(
                    Math.Round((t.Value * 60) / monitoringIntervalInSeconds, 3),
                    FailedRequestsRateMetric);

                return(newMetric);
            });

            result.AddRange(failedRequestRate);

            return(result);
        }
Beispiel #2
0
        public TupleList <decimal, Metric> CalculateMetrics <TCurrent>(List <TCurrent> telemetry)
            where TCurrent : ITelemetry
        {
            var result = new TupleList <decimal, Metric>();


            var totalRequests = telemetry.FirstOrDefault(t => t.MetricName.Equals(MetricConstants.TotalRequestsMetricName, StringComparison.OrdinalIgnoreCase));

            if (totalRequests != null)
            {
                var totalRequestsCount = totalRequests.Value;

                result.AddRange(
                    telemetry
                    .Where(t => Regex.IsMatch(t.MetricName, MetricConstants.HttpStatusCodeReqeustsMetricRegularExpression, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant))
                    .Select(
                        t =>
                {
                    decimal value = 0;
                    if (totalRequestsCount != 0)
                    {
                        value = Math.Round(t.Value * 100 / totalRequestsCount, 3);
                    }

                    var newMetric = new Tuple <decimal, Metric>(
                        value,
                        GetHttpStatusCodeRatioMetric(t.MetricName));

                    return(newMetric);
                }));
            }

            return(result);
        }
Beispiel #3
0
        private TupleList <TCurrent, Metric> GenerateMetrics <TCurrent>(
            MetricType type,
            List <TCurrent> telemetry,
            Func <string, DateTime, Metric, decimal, TCurrent> createNewMetric)
            where TCurrent : ITelemetry
        {
            var calculatedMetrics  = new TupleList <TCurrent, Metric>();
            var filteredStrategies = strategies.Where(s => s.Type == type).ToArray();

            var telemetryGroups = telemetry.GroupBy(t => t.GroupId);

            foreach (var telemetryGroup in telemetryGroups)
            {
                var allMetrics = telemetryGroup.ToList();
                var timestamp  = allMetrics.First().Timestamp;
                foreach (var strategy in filteredStrategies)
                {
                    var newMetricValueTuples = strategy.CalculateMetrics(allMetrics);
                    var newMetrics           = newMetricValueTuples.Select(
                        nmvt => new Tuple <TCurrent, Metric>(
                            createNewMetric(telemetryGroup.Key, timestamp, nmvt.Item2, nmvt.Item1),
                            nmvt.Item2));

                    allMetrics.AddRange(newMetrics.Select(nmvt => nmvt.Item1));
                    calculatedMetrics.AddRange(newMetrics);
                }
            }

            return(calculatedMetrics);
        }
Beispiel #4
0
        public void SubmitsTraces(string packageVersion)
        {
            using var telemetry = this.ConfigureTelemetry();
            using (var agent = EnvironmentHelper.GetMockAgent())
                using (RunSampleAndWaitForExit(agent, arguments: $"{TestPrefix}", packageVersion: packageVersion))
                {
                    // note: ignore the INFO command because it's timing is unpredictable (on Linux?)
                    var spans = agent.WaitForSpans(11)
                                .Where(s => s.Type == "redis" && s.Resource != "INFO" && s.Resource != "ROLE" && s.Resource != "QUIT")
                                .OrderBy(s => s.Start)
                                .ToList();

                    var host = Environment.GetEnvironmentVariable("SERVICESTACK_REDIS_HOST") ?? "localhost:6379";
                    var port = host.Substring(host.IndexOf(':') + 1);
                    host = host.Substring(0, host.IndexOf(':'));

                    foreach (var span in spans)
                    {
                        Assert.Equal("redis.command", span.Name);
                        Assert.Equal("Samples.ServiceStack.Redis-redis", span.Service);
                        Assert.Equal(SpanTypes.Redis, span.Type);
                        Assert.Equal(host, DictionaryExtensions.GetValueOrDefault(span.Tags, "out.host"));
                        Assert.Equal(port, DictionaryExtensions.GetValueOrDefault(span.Tags, "out.port"));
                        Assert.False(span.Tags?.ContainsKey(Tags.Version), "External service span should not have service version tag.");
                    }

                    var expectedFromOneRun = new TupleList <string, string>
                    {
                        { "SET", $"SET {TestPrefix}ServiceStack.Redis.INCR 0" },
                        { "PING", "PING" },
                        { "DDCUSTOM", "DDCUSTOM COMMAND" },
                        { "ECHO", "ECHO Hello World" },
                        { "SLOWLOG", "SLOWLOG GET 5" },
                        { "INCR", $"INCR {TestPrefix}ServiceStack.Redis.INCR" },
                        { "INCRBYFLOAT", $"INCRBYFLOAT {TestPrefix}ServiceStack.Redis.INCR 1.25" },
                        { "TIME", "TIME" },
                        { "SELECT", "SELECT 0" },
                    };

                    var expected = new TupleList <string, string>();
                    expected.AddRange(expectedFromOneRun);
                    expected.AddRange(expectedFromOneRun);
#if NETCOREAPP3_1 || NET5_0
                    expected.AddRange(expectedFromOneRun); // On .NET Core 3.1 and .NET 5 we run the routine a third time
#endif

                    Assert.Equal(expected.Count, spans.Count);

                    for (int i = 0; i < expected.Count; i++)
                    {
                        var e1 = expected[i].Item1;
                        var e2 = expected[i].Item2;

                        var a1 = i < spans.Count
                                 ? spans[i].Resource
                                 : string.Empty;
                        var a2 = i < spans.Count
                                 ? DictionaryExtensions.GetValueOrDefault(spans[i].Tags, "redis.raw_command")
                                 : string.Empty;

                        Assert.True(e1 == a1, $@"invalid resource name for span #{i}, expected ""{e1}"", actual ""{a1}""");
                        Assert.True(e2 == a2, $@"invalid raw command for span #{i}, expected ""{e2}"" != ""{a2}""");
                    }

                    telemetry.AssertIntegrationEnabled(IntegrationId.ServiceStackRedis);
                }
        }
        public void SubmitsTraces()
        {
            int agentPort = TcpPortProvider.GetOpenPort();

            using (var agent = new MockTracerAgent(agentPort))
                using (var processResult = RunSampleAndWaitForExit(agent.Port, arguments: $"StackExchange {TestPrefix}"))
                {
                    Assert.True(processResult.ExitCode >= 0, $"Process exited with code {processResult.ExitCode}");

                    var expected = new TupleList <string, string>
                    {
                        { "SET", $"SET {TestPrefix}StackExchange.Redis.INCR" },
                        { "PING", "PING" },
                        { "DDCUSTOM", "DDCUSTOM" },
                        { "ECHO", "ECHO" },
                        { "SLOWLOG", "SLOWLOG" },
                        { "INCR", $"INCR {TestPrefix}StackExchange.Redis.INCR" },
                        { "INCRBYFLOAT", $"INCRBYFLOAT {TestPrefix}StackExchange.Redis.INCR" },
                        { "GET", $"GET {TestPrefix}StackExchange.Redis.INCR" },
                        { "TIME", "TIME" },
                    };

                    var batchPrefix = $"{TestPrefix}StackExchange.Redis.Batch.";
                    expected.AddRange(new TupleList <string, string>
                    {
                        { "DEBUG", $"DEBUG {batchPrefix}DebugObjectAsync" },
                        { "DDCUSTOM", $"DDCUSTOM" },
                        { "GEOADD", $"GEOADD {batchPrefix}GeoAddAsync" },
                        { "GEODIST", $"GEODIST {batchPrefix}GeoDistanceAsync" },
                        { "GEOHASH", $"GEOHASH {batchPrefix}GeoHashAsync" },
                        { "GEOPOS", $"GEOPOS {batchPrefix}GeoPositionAsync" },
                        { "GEORADIUSBYMEMBER", $"GEORADIUSBYMEMBER {batchPrefix}GeoRadiusAsync" },
                        { "ZREM", $"ZREM {batchPrefix}GeoRemoveAsync" },
                        { "HINCRBYFLOAT", $"HINCRBYFLOAT {batchPrefix}HashDecrementAsync" },
                        { "HDEL", $"HDEL {batchPrefix}HashDeleteAsync" },
                        { "HEXISTS", $"HEXISTS {batchPrefix}HashExistsAsync" },
                        { "HGETALL", $"HGETALL {batchPrefix}HashGetAllAsync" },
                        { "HINCRBYFLOAT", $"HINCRBYFLOAT {batchPrefix}HashIncrementAsync" },
                        { "HKEYS", $"HKEYS {batchPrefix}HashKeysAsync" },
                        { "HLEN", $"HLEN {batchPrefix}HashLengthAsync" },
                        { "HMSET", $"HMSET {batchPrefix}HashSetAsync" },
                        { "HVALS", $"HVALS {batchPrefix}HashValuesAsync" },
                        { "PFADD", $"PFADD {batchPrefix}HyperLogLogAddAsync" },
                        { "PFCOUNT", $"PFCOUNT {batchPrefix}HyperLogLogLengthAsync" },
                        { "PFMERGE", $"PFMERGE {batchPrefix}HyperLogLogMergeAsync" },
                        { "PING", $"PING" },
                        // { "DEL", $"DEL key" },
                        { "DUMP", $"DUMP key" },
                        { "EXISTS", $"EXISTS key" },
                        { "PEXPIREAT", $"PEXPIREAT key" },
                        { "MOVE", $"MOVE key" },
                        { "PERSIST", $"PERSIST key" },
                        { "RANDOMKEY", $"RANDOMKEY" },
                        { "RENAME", "RENAME key1" },
                        { "RESTORE", "RESTORE key" },
                        { "TYPE", "TYPE key" },
                        { "LINDEX", "LINDEX listkey" },
                        { "LINSERT", "LINSERT listkey" },
                        { "LINSERT", "LINSERT listkey" },
                        { "LPOP", "LPOP listkey" },
                        { "LPUSH", "LPUSH listkey" },
                        { "LLEN", "LLEN listkey" },
                        { "LRANGE", "LRANGE listkey" },
                        { "LREM", "LREM listkey" },
                        { "RPOP", "RPOP listkey" },
                        { "RPOPLPUSH", "RPOPLPUSH listkey" },
                        { "RPUSH", "RPUSH listkey" },
                        { "LSET", "LSET listkey" },
                        { "LTRIM", "LTRIM listkey" },
                        { "GET", "GET listkey" },
                        { "SET", "SET listkey" },
                        { "PUBLISH", "PUBLISH channel" },
                        { "SADD", "SADD setkey" },
                        { "SUNIONSTORE", "SUNIONSTORE setkey" },
                        { "SUNION", "SUNION setkey1" },
                        { "SISMEMBER", "SISMEMBER setkey" },
                        { "SCARD", "SCARD setkey" },
                        { "SMEMBERS", "SMEMBERS setkey" },
                        { "SMOVE", "SMOVE setkey1" },
                        { "SPOP", "SPOP setkey1" },
                        { "SRANDMEMBER", "SRANDMEMBER setkey" },
                        { "SRANDMEMBER", "SRANDMEMBER setkey" },
                        { "SREM", "SREM setkey" },
                        { "SORT", "SORT setkey" },
                        { "SORT", "SORT setkey" },
                        { "ZADD", "ZADD ssetkey" },
                        { "ZUNIONSTORE", "ZUNIONSTORE ssetkey1" },
                        { "ZINCRBY", "ZINCRBY ssetkey" },
                        { "ZINCRBY", "ZINCRBY ssetkey" },
                        { "ZCARD", "ZCARD ssetkey" },
                        { "ZLEXCOUNT", "ZLEXCOUNT ssetkey" },
                        { "ZRANGE", "ZRANGE ssetkey" },
                        { "ZRANGE", "ZRANGE ssetkey" },
                        { "ZRANGEBYSCORE", "ZRANGEBYSCORE ssetkey" },
                        { "ZRANGEBYSCORE", "ZRANGEBYSCORE ssetkey" },
                        { "ZRANGEBYLEX", "ZRANGEBYLEX ssetkey" },
                        { "ZRANK", "ZRANK ssetkey" },
                        { "ZREM", "ZREM ssetkey" },
                        { "ZREMRANGEBYRANK", "ZREMRANGEBYRANK ssetkey" },
                        { "ZREMRANGEBYSCORE", "ZREMRANGEBYSCORE ssetkey" },
                        { "ZREMRANGEBYLEX", "ZREMRANGEBYLEX ssetkey" },
                        { "ZSCORE", "ZSCORE ssestkey" },
                        { "APPEND", "APPEND ssetkey" },
                        { "BITCOUNT", "BITCOUNT ssetkey" },
                        { "BITOP", "BITOP" },
                        { "BITPOS", "BITPOS ssetkey1" },
                        { "INCRBYFLOAT", "INCRBYFLOAT key" },
                        { "GET", "GET key" },
                        { "GETBIT", "GETBIT key" },
                        { "GETRANGE", "GETRANGE key" },
                        { "GETSET", "GETSET key" },
                        { "INCR", "INCR key" },
                        { "STRLEN", "STRLEN key" },
                        { "SET", "SET key" },
                        { "SETBIT", "SETBIT key" },
                        { "SETRANGE", "SETRANGE key" },
                    });

                    var dbPrefix = $"{TestPrefix}StackExchange.Redis.Database.";
                    expected.AddRange(new TupleList <string, string>
                    {
                        { "DEBUG", $"DEBUG {dbPrefix}DebugObject" },
                        { "DDCUSTOM", $"DDCUSTOM" },
                        { "GEOADD", $"GEOADD {dbPrefix}Geo" },
                        { "GEODIST", $"GEODIST {dbPrefix}Geo" },
                        { "GEOHASH", $"GEOHASH {dbPrefix}Geo" },
                        { "GEOPOS", $"GEOPOS {dbPrefix}Geo" },
                        { "GEORADIUSBYMEMBER", $"GEORADIUSBYMEMBER {dbPrefix}Geo" },
                        { "ZREM", $"ZREM {dbPrefix}Geo" },
                        { "HINCRBYFLOAT", $"HINCRBYFLOAT {dbPrefix}Hash" },
                        { "HDEL", $"HDEL {dbPrefix}Hash" },
                        { "HEXISTS", $"HEXISTS {dbPrefix}Hash" },
                        { "HGET", $"HGET {dbPrefix}Hash" },
                        { "HGETALL", $"HGETALL {dbPrefix}Hash" },
                        { "HINCRBY", $"HINCRBY {dbPrefix}Hash" },
                        { "HKEYS", $"HKEYS {dbPrefix}Hash" },
                        { "HLEN", $"HLEN {dbPrefix}Hash" },
                        // { "HSCAN", $"HSCAN {dbPrefix}Hash" },
                        { "HMSET", $"HMSET {dbPrefix}Hash" },
                        { "HVALS", $"HVALS {dbPrefix}Hash" },
                        { "PFADD", $"PFADD {dbPrefix}HyperLogLog" },
                        { "PFCOUNT", $"PFCOUNT {dbPrefix}HyperLogLog" },
                        { "PFMERGE", $"PFMERGE {dbPrefix}HyperLogLog2" },
                        // { "DEL", $"DEL {dbPrefix}Key" },
                        { "DUMP", $"DUMP {dbPrefix}Key" },
                        { "EXISTS", $"EXISTS {dbPrefix}Key" },
                        { "PEXPIREAT", $"PEXPIREAT {dbPrefix}Key" },
                        { "MIGRATE", $"MIGRATE {dbPrefix}Key" },
                        { "MOVE", $"MOVE {dbPrefix}Key" },
                        { "PERSIST", $"PERSIST {dbPrefix}Key" },
                        { "RANDOMKEY", $"RANDOMKEY" },
                        { "RENAME", $"RENAME {dbPrefix}Key" },
                        { "RESTORE", $"RESTORE {dbPrefix}Key" },
                        { "PTTL", $"PTTL {dbPrefix}Key" },
                        { "TYPE", $"TYPE {dbPrefix}Key" },
                        { "LINDEX", $"LINDEX {dbPrefix}List" },
                        { "LINSERT", $"LINSERT {dbPrefix}List" },
                        { "LINSERT", $"LINSERT {dbPrefix}List" },
                        { "LPOP", $"LPOP {dbPrefix}List" },
                        { "LPUSH", $"LPUSH {dbPrefix}List" },
                        { "LLEN", $"LLEN {dbPrefix}List" },
                        { "LRANGE", $"LRANGE {dbPrefix}List" },
                        { "LREM", $"LREM {dbPrefix}List" },
                        { "RPOP", $"RPOP {dbPrefix}List" },
                        { "RPOPLPUSH", $"RPOPLPUSH {dbPrefix}List" },
                        { "RPUSH", $"RPUSH {dbPrefix}List" },
                        { "LSET", $"LSET {dbPrefix}List" },
                        { "LTRIM", $"LTRIM {dbPrefix}List" },
                        { "GET", $"GET {dbPrefix}Lock" },
                        { "SET", $"SET {dbPrefix}Lock" },
                        { "PING", $"PING" },
                        { "PUBLISH", $"PUBLISH value" },
                        { "SADD", $"SADD {dbPrefix}Set" },
                        { "SUNION", $"SUNION {dbPrefix}Set" },
                        { "SUNIONSTORE", $"SUNIONSTORE {dbPrefix}Set" },
                        { "SISMEMBER", $"SISMEMBER {dbPrefix}Set" },
                        { "SCARD", $"SCARD {dbPrefix}Set" },
                        { "SMEMBERS", $"SMEMBERS {dbPrefix}Set" },
                        { "SMOVE", $"SMOVE {dbPrefix}Set" },
                        { "SPOP", $"SPOP {dbPrefix}Set" },
                        { "SRANDMEMBER", $"SRANDMEMBER {dbPrefix}Set" },
                        { "SRANDMEMBER", $"SRANDMEMBER {dbPrefix}Set" },
                        { "SREM", $"SREM {dbPrefix}Set" },
                        { "EXEC", $"EXEC" },
                        { "SORT", $"SORT {dbPrefix}Key" },
                        { "SORT", $"SORT {dbPrefix}Key" },
                        { "ZADD", $"ZADD {dbPrefix}SortedSet" },
                        { "ZUNIONSTORE", $"ZUNIONSTORE {dbPrefix}SortedSet2" },
                        { "ZINCRBY", $"ZINCRBY {dbPrefix}SortedSet" },
                        { "ZINCRBY", $"ZINCRBY {dbPrefix}SortedSet" },
                        { "ZCARD", $"ZCARD {dbPrefix}SortedSet" },
                        { "ZLEXCOUNT", $"ZLEXCOUNT {dbPrefix}SortedSet" },
                        { "ZRANGE", $"ZRANGE {dbPrefix}SortedSet" },
                        { "ZRANGE", $"ZRANGE {dbPrefix}SortedSet" },
                        { "ZRANGEBYSCORE", $"ZRANGEBYSCORE {dbPrefix}SortedSet" },
                        { "ZRANGEBYSCORE", $"ZRANGEBYSCORE {dbPrefix}SortedSet" },
                        { "ZRANGEBYLEX", $"ZRANGEBYLEX {dbPrefix}SortedSet" },
                        { "ZRANK", $"ZRANK {dbPrefix}SortedSet" },
                        { "ZREM", $"ZREM {dbPrefix}SortedSet" },
                        { "ZREMRANGEBYRANK", $"ZREMRANGEBYRANK {dbPrefix}SortedSet" },
                        { "ZREMRANGEBYSCORE", $"ZREMRANGEBYSCORE {dbPrefix}SortedSet" },
                        { "ZREMRANGEBYLEX", $"ZREMRANGEBYLEX {dbPrefix}SortedSet" },
                        { "ZSCORE", $"ZSCORE {dbPrefix}SortedSet" },
                        { "APPEND", $"APPEND {dbPrefix}Key" },
                        { "BITCOUNT", $"BITCOUNT {dbPrefix}Key" },
                        { "BITOP", $"BITOP" },
                        { "BITPOS", $"BITPOS {dbPrefix}Key" },
                        { "INCRBYFLOAT", $"INCRBYFLOAT {dbPrefix}Key" },
                        { "GET", $"GET {dbPrefix}Key" },
                        { "GETBIT", $"GETBIT {dbPrefix}Key" },
                        { "GETRANGE", $"GETRANGE {dbPrefix}Key" },
                        { "GETSET", $"GETSET {dbPrefix}Key" },
                        { "PTTL+GET", $"PTTL+GET {dbPrefix}Key" },
                        { "STRLEN", $"STRLEN {dbPrefix}Key" },
                        { "SET", $"SET {dbPrefix}Key" },
                        { "SETBIT", $"SETBIT {dbPrefix}Key" },
                        { "SETRANGE", $"SETRANGE {dbPrefix}Key" },
                    });

                    var spans = agent.WaitForSpans(expected.Count).Where(s => s.Type == "redis").OrderBy(s => s.Start).ToList();
                    var host  = Environment.GetEnvironmentVariable("REDIS_HOST") ?? "localhost";

                    foreach (var span in spans)
                    {
                        Assert.Equal("redis.command", span.Name);
                        Assert.Equal("Samples.RedisCore-redis", span.Service);
                        Assert.Equal(SpanTypes.Redis, span.Type);
                        Assert.Equal(host, span.Tags.Get <string>("out.host"));
                        Assert.Equal("6379", span.Tags.Get <string>("out.port"));
                    }

                    var spanLookup = new Dictionary <Tuple <string, string>, int>();
                    foreach (var span in spans)
                    {
                        var key = new Tuple <string, string>(span.Resource, span.Tags.Get <string>("redis.raw_command"));
                        if (spanLookup.ContainsKey(key))
                        {
                            spanLookup[key]++;
                        }
                        else
                        {
                            spanLookup[key] = 1;
                        }
                    }

                    var missing = new List <Tuple <string, string> >();

                    foreach (var e in expected)
                    {
                        var found = spanLookup.ContainsKey(e);
                        if (found)
                        {
                            if (--spanLookup[e] <= 0)
                            {
                                spanLookup.Remove(e);
                            }
                        }
                        else
                        {
                            missing.Add(e);
                        }
                    }

                    foreach (var e in missing)
                    {
                        Assert.True(false, $"no span found for `{e.Item1}`, `{e.Item2}`, remaining spans: `{string.Join(", ", spanLookup.Select(kvp => $"{kvp.Key.Item1}, {kvp.Key.Item2}").ToArray())}`");
                    }
                }
        }
Beispiel #6
0
        public void SubmitsTraces(string packageVersion, string tagCommands)
        {
            int agentPort = TcpPortProvider.GetOpenPort();
            var envVars   = ZipkinEnvVars;

            envVars["SIGNALFX_INSTRUMENTATION_REDIS_TAG_COMMANDS"] = tagCommands;

            using (var agent = new MockZipkinCollector(agentPort))
                using (var processResult = RunSampleAndWaitForExit(agent.Port, arguments: $"{TestPrefix}", packageVersion: packageVersion, envVars: envVars))
                {
                    Assert.True(processResult.ExitCode >= 0, $"Process exited with code {processResult.ExitCode}");

                    var expected = new TupleList <string, string>
                    {
                        { "SET", $"SET {TestPrefix}StackExchange.Redis.INCR" },
                        { "PING", "PING" },
                        { "INCR", $"INCR {TestPrefix}StackExchange.Redis.INCR" },
                        { "INCRBYFLOAT", $"INCRBYFLOAT {TestPrefix}StackExchange.Redis.INCR" },
                        { "GET", $"GET {TestPrefix}StackExchange.Redis.INCR" },
                        { "DDCUSTOM", "DDCUSTOM" },
                        { "ECHO", "ECHO" },
                        { "SLOWLOG", "SLOWLOG" },
                        { "TIME", "TIME" },
                    };

                    if (string.IsNullOrEmpty(packageVersion) || packageVersion.CompareTo("1.2.2") < 0)
                    {
                        expected.Remove(new Tuple <string, string>("DDCUSTOM", "DDCUSTOM"));
                        expected.Remove(new Tuple <string, string>("ECHO", "ECHO"));
                        expected.Remove(new Tuple <string, string>("SLOWLOG", "SLOWLOG"));
                        expected.Remove(new Tuple <string, string>("TIME", "TIME"));
                    }

                    var batchPrefix = $"{TestPrefix}StackExchange.Redis.Batch.";
                    expected.AddRange(new TupleList <string, string>
                    {
                        { "DEBUG", $"DEBUG {batchPrefix}DebugObjectAsync" },
                        { "DDCUSTOM", $"DDCUSTOM" },                                               // Only present on 1.2.2+
                        { "GEOADD", $"GEOADD {batchPrefix}GeoAddAsync" },                          // Only present on 1.2.0+
                        { "GEODIST", $"GEODIST {batchPrefix}GeoDistanceAsync" },                   // Only present on 1.2.0+
                        { "GEOHASH", $"GEOHASH {batchPrefix}GeoHashAsync" },                       // Only present on 1.2.0+
                        { "GEOPOS", $"GEOPOS {batchPrefix}GeoPositionAsync" },                     // Only present on 1.2.0+
                        { "GEORADIUSBYMEMBER", $"GEORADIUSBYMEMBER {batchPrefix}GeoRadiusAsync" }, // Only present on 1.2.0+
                        { "ZREM", $"ZREM {batchPrefix}GeoRemoveAsync" },                           // Only present on 1.2.0+
                        { "HINCRBYFLOAT", $"HINCRBYFLOAT {batchPrefix}HashDecrementAsync" },
                        { "HDEL", $"HDEL {batchPrefix}HashDeleteAsync" },
                        { "HEXISTS", $"HEXISTS {batchPrefix}HashExistsAsync" },
                        { "HGETALL", $"HGETALL {batchPrefix}HashGetAllAsync" },
                        { "HINCRBYFLOAT", $"HINCRBYFLOAT {batchPrefix}HashIncrementAsync" },
                        { "HKEYS", $"HKEYS {batchPrefix}HashKeysAsync" },
                        { "HLEN", $"HLEN {batchPrefix}HashLengthAsync" },
                        { "HMSET", $"HMSET {batchPrefix}HashSetAsync" },
                        { "HVALS", $"HVALS {batchPrefix}HashValuesAsync" },
                        { "PFADD", $"PFADD {batchPrefix}HyperLogLogAddAsync" },        // Only present on 1.0.242+
                        { "PFCOUNT", $"PFCOUNT {batchPrefix}HyperLogLogLengthAsync" }, // Only present on 1.0.242+
                        { "PFMERGE", $"PFMERGE {batchPrefix}HyperLogLogMergeAsync" },  // Only present on 1.0.242+
                        { "PING", $"PING" },
                        // { "DEL", $"DEL key" },
                        { "DUMP", $"DUMP key" },
                        { "EXISTS", $"EXISTS key" },
                        { "PEXPIREAT", $"PEXPIREAT key" },
                        { "MOVE", $"MOVE key" },
                        { "PERSIST", $"PERSIST key" },
                        { "RANDOMKEY", $"RANDOMKEY" },
                        { "RENAME", "RENAME key1" },
                        { "RESTORE", "RESTORE key" },
                        { "TYPE", "TYPE key" },
                        { "LINDEX", "LINDEX listkey" },
                        { "LINSERT", "LINSERT listkey" },
                        { "LINSERT", "LINSERT listkey" },
                        { "LPOP", "LPOP listkey" },
                        { "LPUSH", "LPUSH listkey" },
                        { "LLEN", "LLEN listkey" },
                        { "LRANGE", "LRANGE listkey" },
                        { "LREM", "LREM listkey" },
                        { "RPOP", "RPOP listkey" },
                        { "RPOPLPUSH", "RPOPLPUSH listkey" },
                        { "RPUSH", "RPUSH listkey" },
                        { "LSET", "LSET listkey" },
                        { "LTRIM", "LTRIM listkey" },
                        { "GET", "GET listkey" },
                        { "SET", "SET listkey" },
                        { "PUBLISH", "PUBLISH channel" },
                        { "SADD", "SADD setkey" },
                        { "SUNIONSTORE", "SUNIONSTORE setkey" },
                        { "SUNION", "SUNION setkey1" },
                        { "SISMEMBER", "SISMEMBER setkey" },
                        { "SCARD", "SCARD setkey" },
                        { "SMEMBERS", "SMEMBERS setkey" },
                        { "SMOVE", "SMOVE setkey1" },
                        { "SPOP", "SPOP setkey1" },
                        { "SRANDMEMBER", "SRANDMEMBER setkey" },
                        { "SRANDMEMBER", "SRANDMEMBER setkey" },
                        { "SREM", "SREM setkey" },
                        { "SORT", "SORT setkey" },                 // Only present on 1.0.206+
                        { "SORT", "SORT setkey" },                 // Only present on 1.0.206+
                        { "ZUNIONSTORE", "ZUNIONSTORE ssetkey1" }, // Only present on 1.0.206+
                        { "ZADD", "ZADD ssetkey" },
                        { "ZINCRBY", "ZINCRBY ssetkey" },
                        { "ZINCRBY", "ZINCRBY ssetkey" },
                        { "ZCARD", "ZCARD ssetkey" },
                        { "ZRANGE", "ZRANGE ssetkey" },
                        { "ZRANGE", "ZRANGE ssetkey" },
                        { "ZRANGEBYSCORE", "ZRANGEBYSCORE ssetkey" },
                        { "ZRANGEBYSCORE", "ZRANGEBYSCORE ssetkey" },
                        { "ZRANK", "ZRANK ssetkey" },
                        { "ZREM", "ZREM ssetkey" },
                        { "ZREMRANGEBYRANK", "ZREMRANGEBYRANK ssetkey" },
                        { "ZREMRANGEBYSCORE", "ZREMRANGEBYSCORE ssetkey" },
                        { "ZSCORE", "ZSCORE ssestkey" },
                        { "ZLEXCOUNT", "ZLEXCOUNT ssetkey" },           // Only present on 1.0.273+
                        { "ZRANGEBYLEX", "ZRANGEBYLEX ssetkey" },       // Only present on 1.0.273+
                        { "ZREMRANGEBYLEX", "ZREMRANGEBYLEX ssetkey" }, // Only present on 1.0.273+
                        { "APPEND", "APPEND ssetkey" },
                        { "BITCOUNT", "BITCOUNT ssetkey" },
                        { "BITOP", "BITOP" },
                        { "BITPOS", "BITPOS ssetkey1" },
                        { "INCRBYFLOAT", "INCRBYFLOAT key" },
                        { "GET", "GET key" },
                        { "GETBIT", "GETBIT key" },
                        { "GETRANGE", "GETRANGE key" },
                        { "GETSET", "GETSET key" },
                        { "INCR", "INCR key" },
                        { "STRLEN", "STRLEN key" },
                        { "SET", "SET key" },
                        { "SETBIT", "SETBIT key" },
                        { "SETRANGE", "SETRANGE key" },
                    });

                    FilterExpectedResultsByApiVersion(expected, packageVersion);

                    var dbPrefix = $"{TestPrefix}StackExchange.Redis.Database.";
                    expected.AddRange(new TupleList <string, string>
                    {
                        { "DEBUG", $"DEBUG {dbPrefix}DebugObject" },
                        { "DDCUSTOM", $"DDCUSTOM" },                                 // Only present on 1.2.2+
                        { "GEOADD", $"GEOADD {dbPrefix}Geo" },                       // Only present on 1.2.0+
                        { "GEODIST", $"GEODIST {dbPrefix}Geo" },                     // Only present on 1.2.0+
                        { "GEOHASH", $"GEOHASH {dbPrefix}Geo" },                     // Only present on 1.2.0+
                        { "GEOPOS", $"GEOPOS {dbPrefix}Geo" },                       // Only present on 1.2.0+
                        { "GEORADIUSBYMEMBER", $"GEORADIUSBYMEMBER {dbPrefix}Geo" }, // Only present on 1.2.0+
                        { "ZREM", $"ZREM {dbPrefix}Geo" },                           // Only present on 1.2.0+
                        { "HINCRBYFLOAT", $"HINCRBYFLOAT {dbPrefix}Hash" },
                        { "HDEL", $"HDEL {dbPrefix}Hash" },
                        { "HEXISTS", $"HEXISTS {dbPrefix}Hash" },
                        { "HGET", $"HGET {dbPrefix}Hash" },
                        { "HGETALL", $"HGETALL {dbPrefix}Hash" },
                        { "HINCRBY", $"HINCRBY {dbPrefix}Hash" },
                        { "HKEYS", $"HKEYS {dbPrefix}Hash" },
                        { "HLEN", $"HLEN {dbPrefix}Hash" },
                        // { "HSCAN", $"HSCAN {dbPrefix}Hash" },
                        { "HMSET", $"HMSET {dbPrefix}Hash" },
                        { "HVALS", $"HVALS {dbPrefix}Hash" },
                        { "PFADD", $"PFADD {dbPrefix}HyperLogLog" },      // Only present on 1.0.242+
                        { "PFCOUNT", $"PFCOUNT {dbPrefix}HyperLogLog" },  // Only present on 1.0.242+
                        { "PFMERGE", $"PFMERGE {dbPrefix}HyperLogLog2" }, // Only present on 1.0.242+
                        // { "DEL", $"DEL {dbPrefix}Key" },
                        { "DUMP", $"DUMP {dbPrefix}Key" },
                        { "EXISTS", $"EXISTS {dbPrefix}Key" },
                        { "PEXPIREAT", $"PEXPIREAT {dbPrefix}Key" },
                        { "MIGRATE", $"MIGRATE {dbPrefix}Key" }, // Only present on 1.0.297+
                        { "MOVE", $"MOVE {dbPrefix}Key" },
                        { "PERSIST", $"PERSIST {dbPrefix}Key" },
                        { "RANDOMKEY", $"RANDOMKEY" },
                        { "RENAME", $"RENAME {dbPrefix}Key" },
                        { "RESTORE", $"RESTORE {dbPrefix}Key" },
                        { "PTTL", $"PTTL {dbPrefix}Key" },
                        { "TYPE", $"TYPE {dbPrefix}Key" },
                        { "LINDEX", $"LINDEX {dbPrefix}List" },
                        { "LINSERT", $"LINSERT {dbPrefix}List" },
                        { "LINSERT", $"LINSERT {dbPrefix}List" },
                        { "LPOP", $"LPOP {dbPrefix}List" },
                        { "LPUSH", $"LPUSH {dbPrefix}List" },
                        { "LLEN", $"LLEN {dbPrefix}List" },
                        { "LRANGE", $"LRANGE {dbPrefix}List" },
                        { "LREM", $"LREM {dbPrefix}List" },
                        { "RPOP", $"RPOP {dbPrefix}List" },
                        { "RPOPLPUSH", $"RPOPLPUSH {dbPrefix}List" },
                        { "RPUSH", $"RPUSH {dbPrefix}List" },
                        { "LSET", $"LSET {dbPrefix}List" },
                        { "LTRIM", $"LTRIM {dbPrefix}List" },
                        { "GET", $"GET {dbPrefix}Lock" },
                        { "SET", $"SET {dbPrefix}Lock" },
                        { "PING", $"PING" },
                        { "PUBLISH", $"PUBLISH value" },
                        { "SADD", $"SADD {dbPrefix}Set" },
                        { "SUNION", $"SUNION {dbPrefix}Set" },
                        { "SUNIONSTORE", $"SUNIONSTORE {dbPrefix}Set" },
                        { "SISMEMBER", $"SISMEMBER {dbPrefix}Set" },
                        { "SCARD", $"SCARD {dbPrefix}Set" },
                        { "SMEMBERS", $"SMEMBERS {dbPrefix}Set" },
                        { "SMOVE", $"SMOVE {dbPrefix}Set" },
                        { "SPOP", $"SPOP {dbPrefix}Set" },
                        { "SRANDMEMBER", $"SRANDMEMBER {dbPrefix}Set" },
                        { "SRANDMEMBER", $"SRANDMEMBER {dbPrefix}Set" },
                        { "SREM", $"SREM {dbPrefix}Set" },
                        { "EXEC", $"EXEC" },
                        { "SORT", $"SORT {dbPrefix}Key" },                      // Only present on 1.0.206+
                        { "SORT", $"SORT {dbPrefix}Key" },                      // Only present on 1.0.206+
                        { "ZUNIONSTORE", $"ZUNIONSTORE {dbPrefix}SortedSet2" }, // Only present on 1.0.206+
                        { "ZADD", $"ZADD {dbPrefix}SortedSet" },
                        { "ZINCRBY", $"ZINCRBY {dbPrefix}SortedSet" },
                        { "ZINCRBY", $"ZINCRBY {dbPrefix}SortedSet" },
                        { "ZCARD", $"ZCARD {dbPrefix}SortedSet" },
                        { "ZRANGE", $"ZRANGE {dbPrefix}SortedSet" },
                        { "ZRANGE", $"ZRANGE {dbPrefix}SortedSet" },
                        { "ZRANGEBYSCORE", $"ZRANGEBYSCORE {dbPrefix}SortedSet" },
                        { "ZRANGEBYSCORE", $"ZRANGEBYSCORE {dbPrefix}SortedSet" },
                        { "ZRANK", $"ZRANK {dbPrefix}SortedSet" },
                        { "ZREM", $"ZREM {dbPrefix}SortedSet" },
                        { "ZREMRANGEBYRANK", $"ZREMRANGEBYRANK {dbPrefix}SortedSet" },
                        { "ZREMRANGEBYSCORE", $"ZREMRANGEBYSCORE {dbPrefix}SortedSet" },
                        { "ZSCORE", $"ZSCORE {dbPrefix}SortedSet" },
                        { "ZLEXCOUNT", $"ZLEXCOUNT {dbPrefix}SortedSet" },           // Only present on 1.0.273+
                        { "ZRANGEBYLEX", $"ZRANGEBYLEX {dbPrefix}SortedSet" },       // Only present on 1.0.273+
                        { "ZREMRANGEBYLEX", $"ZREMRANGEBYLEX {dbPrefix}SortedSet" }, // Only present on 1.0.273+
                        { "APPEND", $"APPEND {dbPrefix}Key" },
                        { "BITCOUNT", $"BITCOUNT {dbPrefix}Key" },
                        { "BITOP", $"BITOP" },
                        { "BITPOS", $"BITPOS {dbPrefix}Key" },
                        { "INCRBYFLOAT", $"INCRBYFLOAT {dbPrefix}Key" },
                        { "GET", $"GET {dbPrefix}Key" },
                        { "GETBIT", $"GETBIT {dbPrefix}Key" },
                        { "GETRANGE", $"GETRANGE {dbPrefix}Key" },
                        { "GETSET", $"GETSET {dbPrefix}Key" },
                        { "PTTL+GET", $"PTTL+GET {dbPrefix}Key" },
                        { "STRLEN", $"STRLEN {dbPrefix}Key" },
                        { "SET", $"SET {dbPrefix}Key" },
                        { "SETBIT", $"SETBIT {dbPrefix}Key" },
                        { "SETRANGE", $"SETRANGE {dbPrefix}Key" },
                    });

                    FilterExpectedResultsByApiVersion(expected, packageVersion);

                    // No db.statement tags should exists, so overwrite with null
                    if (!tagCommands.Equals("true"))
                    {
                        var replacement = new TupleList <string, string>();
                        foreach (var item in expected)
                        {
                            replacement.Add(new Tuple <string, string>(item.Item1, null));
                        }

                        expected = replacement;
                    }

                    var spans = agent.WaitForSpans(expected.Count).Where(s => s.Tags.GetValueOrDefault <string>("db.type") == "redis").OrderBy(s => s.Start).ToList();
                    var host  = Environment.GetEnvironmentVariable("STACKEXCHANGE_REDIS_HOST") ?? "localhost:6389";
                    var port  = host.Substring(host.IndexOf(':') + 1);
                    host = host.Substring(0, host.IndexOf(':'));

                    foreach (var span in spans)
                    {
                        Assert.Equal("Samples.StackExchange.Redis", span.Service);
                        Assert.Equal("StackExchange.Redis", span.Tags.GetValueOrDefault <string>("component"));
                        Assert.Equal(SpanKinds.Client, span.Tags.GetValueOrDefault <string>("span.kind"));
                        Assert.Equal(host, span.Tags.GetValueOrDefault <string>("peer.hostname"));
                        Assert.Equal(port, span.Tags.GetValueOrDefault <string>("peer.port"));
                    }

                    var spanLookup = new Dictionary <Tuple <string, string>, int>();
                    foreach (var span in spans)
                    {
                        var key = new Tuple <string, string>(span.Name, span.Tags.GetValueOrDefault <string>("db.statement"));
                        if (spanLookup.ContainsKey(key))
                        {
                            spanLookup[key]++;
                        }
                        else
                        {
                            spanLookup[key] = 1;
                        }
                    }

                    var missing = new List <Tuple <string, string> >();

                    foreach (var e in expected)
                    {
                        var found = spanLookup.ContainsKey(e);
                        if (found)
                        {
                            if (--spanLookup[e] <= 0)
                            {
                                spanLookup.Remove(e);
                            }
                        }
                        else
                        {
                            missing.Add(e);
                        }
                    }

                    foreach (var e in missing)
                    {
                        Assert.True(false, $"no span found for `{e.Item1}`, `{e.Item2}`, remaining spans: `{string.Join(", ", spanLookup.Select(kvp => $"{kvp.Key.Item1}, {kvp.Key.Item2}").ToArray())}`");
                    }
                }
        }
        public static async Task <Tuple <IOrganizationServiceExtented, TupleList <SelectedFile, WebResource> > > GetWebResourcesWithType(IWriteToOutput _iWriteToOutput, List <SelectedFile> selectedFiles, OpenFilesType openFilesType, ConnectionData connectionData)
        {
            IOrganizationServiceExtented service = null;

            TupleList <SelectedFile, WebResource> filesToOpen = new TupleList <SelectedFile, WebResource>();

            if (openFilesType == OpenFilesType.All)
            {
                foreach (var item in selectedFiles)
                {
                    filesToOpen.Add(item, null);
                }
            }
            else if (openFilesType == OpenFilesType.NotExistsInCrmWithoutLink ||
                     openFilesType == OpenFilesType.NotExistsInCrmWithLink
                     )
            {
                var compareResult = await FindFilesNotExistsInCrmAsync(_iWriteToOutput, selectedFiles, connectionData);

                service = compareResult.Item1;

                if (openFilesType == OpenFilesType.NotExistsInCrmWithoutLink)
                {
                    filesToOpen.AddRange(compareResult.Item2.Select(f => Tuple.Create(f, (WebResource)null)));
                }
                else if (openFilesType == OpenFilesType.NotExistsInCrmWithLink)
                {
                    filesToOpen.AddRange(compareResult.Item3.Select(f => Tuple.Create(f.Item1, f.Item2)));
                }
            }
            else if (openFilesType == OpenFilesType.EqualByText ||
                     openFilesType == OpenFilesType.NotEqualByText
                     )
            {
                var compareResult = await ComparingFilesAndWebResourcesAsync(_iWriteToOutput, selectedFiles, connectionData, false);

                service = compareResult.Item1;

                if (openFilesType == OpenFilesType.EqualByText)
                {
                    filesToOpen.AddRange(compareResult.Item2);
                }
                else if (openFilesType == OpenFilesType.NotEqualByText)
                {
                    filesToOpen.AddRange(compareResult.Item3.Select(f => Tuple.Create(f.Item1, f.Item2)));
                }
            }
            else if (openFilesType == OpenFilesType.WithInserts ||
                     openFilesType == OpenFilesType.WithDeletes ||
                     openFilesType == OpenFilesType.WithComplex ||
                     openFilesType == OpenFilesType.WithMirror ||
                     openFilesType == OpenFilesType.WithMirrorInserts ||
                     openFilesType == OpenFilesType.WithMirrorDeletes ||
                     openFilesType == OpenFilesType.WithMirrorComplex
                     )
            {
                var compareResult = await CompareController.ComparingFilesAndWebResourcesAsync(_iWriteToOutput, selectedFiles, connectionData, true);

                service = compareResult.Item1;

                if (openFilesType == OpenFilesType.WithInserts)
                {
                    filesToOpen.AddRange(compareResult.Item3.Where(s => s.Item3.IsOnlyInserts).Select(f => Tuple.Create(f.Item1, f.Item2)));
                }
                else if (openFilesType == OpenFilesType.WithDeletes)
                {
                    filesToOpen.AddRange(compareResult.Item3.Where(s => s.Item3.IsOnlyDeletes).Select(f => Tuple.Create(f.Item1, f.Item2)));
                }
                else if (openFilesType == OpenFilesType.WithComplex)
                {
                    filesToOpen.AddRange(compareResult.Item3.Where(s => s.Item3.IsComplexChanges).Select(f => Tuple.Create(f.Item1, f.Item2)));
                }
                else if (openFilesType == OpenFilesType.WithMirror)
                {
                    filesToOpen.AddRange(compareResult.Item3.Where(s => s.Item3.IsMirror).Select(f => Tuple.Create(f.Item1, f.Item2)));
                }
                else if (openFilesType == OpenFilesType.WithMirrorInserts)
                {
                    filesToOpen.AddRange(compareResult.Item3.Where(s => s.Item3.IsMirrorWithInserts).Select(f => Tuple.Create(f.Item1, f.Item2)));
                }
                else if (openFilesType == OpenFilesType.WithMirrorDeletes)
                {
                    filesToOpen.AddRange(compareResult.Item3.Where(s => s.Item3.IsMirrorWithDeletes).Select(f => Tuple.Create(f.Item1, f.Item2)));
                }
                else if (openFilesType == OpenFilesType.WithMirrorComplex)
                {
                    filesToOpen.AddRange(compareResult.Item3.Where(s => s.Item3.IsMirrorWithComplex).Select(f => Tuple.Create(f.Item1, f.Item2)));
                }
            }

            return(Tuple.Create(service, filesToOpen));
        }
Beispiel #8
0
        public void SubmitsTraces(string packageVersion)
        {
            using var telemetry = this.ConfigureTelemetry();
            using (var agent = EnvironmentHelper.GetMockAgent())
                using (RunSampleAndWaitForExit(agent, arguments: $"{TestPrefix}", packageVersion: packageVersion))
                {
                    var expected = new TupleList <string, string>
                    {
                        { "SET", $"SET {TestPrefix}StackExchange.Redis.INCR" },
                        { "PING", "PING" },
                        { "INCR", $"INCR {TestPrefix}StackExchange.Redis.INCR" },
                        { "INCRBYFLOAT", $"INCRBYFLOAT {TestPrefix}StackExchange.Redis.INCR" },
                        { "GET", $"GET {TestPrefix}StackExchange.Redis.INCR" },
                        { "DDCUSTOM", "DDCUSTOM" },
                        { "ECHO", "ECHO" },
                        { "SLOWLOG", "SLOWLOG" },
                        { "TIME", "TIME" },
                    };

                    if (string.IsNullOrEmpty(packageVersion) || packageVersion.CompareTo("1.2.2") < 0)
                    {
                        expected.Remove(new Tuple <string, string>("DDCUSTOM", "DDCUSTOM"));
                        expected.Remove(new Tuple <string, string>("ECHO", "ECHO"));
                        expected.Remove(new Tuple <string, string>("SLOWLOG", "SLOWLOG"));
                        expected.Remove(new Tuple <string, string>("TIME", "TIME"));
                    }

                    var batchPrefix = $"{TestPrefix}StackExchange.Redis.Batch.";
                    expected.AddRange(new TupleList <string, string>
                    {
                        { "DEBUG", $"DEBUG {batchPrefix}DebugObjectAsync" },
                        { "DDCUSTOM", $"DDCUSTOM" },                                               // Only present on 1.2.2+
                        { "GEOADD", $"GEOADD {batchPrefix}GeoAddAsync" },                          // Only present on 1.2.0+
                        { "GEODIST", $"GEODIST {batchPrefix}GeoDistanceAsync" },                   // Only present on 1.2.0+
                        { "GEOHASH", $"GEOHASH {batchPrefix}GeoHashAsync" },                       // Only present on 1.2.0+
                        { "GEOPOS", $"GEOPOS {batchPrefix}GeoPositionAsync" },                     // Only present on 1.2.0+
                        { "GEORADIUSBYMEMBER", $"GEORADIUSBYMEMBER {batchPrefix}GeoRadiusAsync" }, // Only present on 1.2.0+
                        { "ZREM", $"ZREM {batchPrefix}GeoRemoveAsync" },                           // Only present on 1.2.0+
                        { "HINCRBYFLOAT", $"HINCRBYFLOAT {batchPrefix}HashDecrementAsync" },
                        { "HDEL", $"HDEL {batchPrefix}HashDeleteAsync" },
                        { "HEXISTS", $"HEXISTS {batchPrefix}HashExistsAsync" },
                        { "HGETALL", $"HGETALL {batchPrefix}HashGetAllAsync" },
                        { "HINCRBYFLOAT", $"HINCRBYFLOAT {batchPrefix}HashIncrementAsync" },
                        { "HKEYS", $"HKEYS {batchPrefix}HashKeysAsync" },
                        { "HLEN", $"HLEN {batchPrefix}HashLengthAsync" },
                        { "HMSET", $"HMSET {batchPrefix}HashSetAsync" },
                        { "HVALS", $"HVALS {batchPrefix}HashValuesAsync" },
                        { "PFADD", $"PFADD {batchPrefix}HyperLogLogAddAsync" },        // Only present on 1.0.242+
                        { "PFCOUNT", $"PFCOUNT {batchPrefix}HyperLogLogLengthAsync" }, // Only present on 1.0.242+
                        { "PFMERGE", $"PFMERGE {batchPrefix}HyperLogLogMergeAsync" },  // Only present on 1.0.242+
                        { "PING", $"PING" },
                        // { "DEL", $"DEL key" },
                        { "DUMP", $"DUMP key" },
                        { "EXISTS", $"EXISTS key" },
                        { "PEXPIRE", $"PEXPIRE key" },
                        { "MOVE", $"MOVE key" },
                        { "PERSIST", $"PERSIST key" },
                        { "RANDOMKEY", $"RANDOMKEY" },
                        { "RENAME", "RENAME key1" },
                        { "RESTORE", "RESTORE key" },
                        { "TYPE", "TYPE key" },
                        { "LINDEX", "LINDEX listkey" },
                        { "LINSERT", "LINSERT listkey" },
                        { "LINSERT", "LINSERT listkey" },
                        { "LPOP", "LPOP listkey" },
                        { "LPUSH", "LPUSH listkey" },
                        { "LLEN", "LLEN listkey" },
                        { "LRANGE", "LRANGE listkey" },
                        { "LREM", "LREM listkey" },
                        { "RPOP", "RPOP listkey" },
                        { "RPOPLPUSH", "RPOPLPUSH listkey" },
                        { "RPUSH", "RPUSH listkey" },
                        { "LSET", "LSET listkey" },
                        { "LTRIM", "LTRIM listkey" },
                        { "GET", "GET listkey" },
                        { "SET", "SET listkey" },
                        { "PUBLISH", "PUBLISH channel" },
                        { "SADD", "SADD setkey" },
                        { "SUNIONSTORE", "SUNIONSTORE setkey" },
                        { "SUNION", "SUNION setkey1" },
                        { "SISMEMBER", "SISMEMBER setkey" },
                        { "SCARD", "SCARD setkey" },
                        { "SMEMBERS", "SMEMBERS setkey" },
                        { "SMOVE", "SMOVE setkey1" },
                        { "SPOP", "SPOP setkey1" },
                        { "SRANDMEMBER", "SRANDMEMBER setkey" },
                        { "SRANDMEMBER", "SRANDMEMBER setkey" },
                        { "SREM", "SREM setkey" },
                        { "SORT", "SORT setkey" },                 // Only present on 1.0.206+
                        { "SORT", "SORT setkey" },                 // Only present on 1.0.206+
                        { "ZUNIONSTORE", "ZUNIONSTORE ssetkey1" }, // Only present on 1.0.206+
                        { "ZADD", "ZADD ssetkey" },
                        { "ZINCRBY", "ZINCRBY ssetkey" },
                        { "ZINCRBY", "ZINCRBY ssetkey" },
                        { "ZCARD", "ZCARD ssetkey" },
                        { "ZRANGE", "ZRANGE ssetkey" },
                        { "ZRANGE", "ZRANGE ssetkey" },
                        { "ZRANGEBYSCORE", "ZRANGEBYSCORE ssetkey" },
                        { "ZRANGEBYSCORE", "ZRANGEBYSCORE ssetkey" },
                        { "ZRANK", "ZRANK ssetkey" },
                        { "ZREM", "ZREM ssetkey" },
                        { "ZREMRANGEBYRANK", "ZREMRANGEBYRANK ssetkey" },
                        { "ZREMRANGEBYSCORE", "ZREMRANGEBYSCORE ssetkey" },
                        { "ZSCORE", "ZSCORE ssestkey" },
                        { "ZLEXCOUNT", "ZLEXCOUNT ssetkey" },           // Only present on 1.0.273+
                        { "ZRANGEBYLEX", "ZRANGEBYLEX ssetkey" },       // Only present on 1.0.273+
                        { "ZREMRANGEBYLEX", "ZREMRANGEBYLEX ssetkey" }, // Only present on 1.0.273+
                        { "APPEND", "APPEND ssetkey" },
                        { "BITCOUNT", "BITCOUNT ssetkey" },
                        { "BITOP", "BITOP" },
                        { "BITPOS", "BITPOS ssetkey1" },
                        { "INCRBYFLOAT", "INCRBYFLOAT key" },
                        { "GET", "GET key" },
                        { "GETBIT", "GETBIT key" },
                        { "GETRANGE", "GETRANGE key" },
                        { "GETSET", "GETSET key" },
                        { "INCR", "INCR key" },
                        { "STRLEN", "STRLEN key" },
                        { "SET", "SET key" },
                        { "SETBIT", "SETBIT key" },
                        { "SETRANGE", "SETRANGE key" },
                    });

                    FilterExpectedResultsByApiVersion(expected, packageVersion);

                    var dbPrefix = $"{TestPrefix}StackExchange.Redis.Database.";
                    expected.AddRange(new TupleList <string, string>
                    {
                        { "DEBUG", $"DEBUG {dbPrefix}DebugObject" },
                        { "DDCUSTOM", $"DDCUSTOM" },                                 // Only present on 1.2.2+
                        { "GEOADD", $"GEOADD {dbPrefix}Geo" },                       // Only present on 1.2.0+
                        { "GEODIST", $"GEODIST {dbPrefix}Geo" },                     // Only present on 1.2.0+
                        { "GEOHASH", $"GEOHASH {dbPrefix}Geo" },                     // Only present on 1.2.0+
                        { "GEOPOS", $"GEOPOS {dbPrefix}Geo" },                       // Only present on 1.2.0+
                        { "GEORADIUSBYMEMBER", $"GEORADIUSBYMEMBER {dbPrefix}Geo" }, // Only present on 1.2.0+
                        { "ZREM", $"ZREM {dbPrefix}Geo" },                           // Only present on 1.2.0+
                        { "HINCRBYFLOAT", $"HINCRBYFLOAT {dbPrefix}Hash" },
                        { "HDEL", $"HDEL {dbPrefix}Hash" },
                        { "HEXISTS", $"HEXISTS {dbPrefix}Hash" },
                        { "HGET", $"HGET {dbPrefix}Hash" },
                        { "HGETALL", $"HGETALL {dbPrefix}Hash" },
                        { "HINCRBY", $"HINCRBY {dbPrefix}Hash" },
                        { "HKEYS", $"HKEYS {dbPrefix}Hash" },
                        { "HLEN", $"HLEN {dbPrefix}Hash" },
                        // { "HSCAN", $"HSCAN {dbPrefix}Hash" },
                        { "HMSET", $"HMSET {dbPrefix}Hash" },
                        { "HVALS", $"HVALS {dbPrefix}Hash" },
                        { "PFADD", $"PFADD {dbPrefix}HyperLogLog" },      // Only present on 1.0.242+
                        { "PFCOUNT", $"PFCOUNT {dbPrefix}HyperLogLog" },  // Only present on 1.0.242+
                        { "PFMERGE", $"PFMERGE {dbPrefix}HyperLogLog2" }, // Only present on 1.0.242+
                        // { "DEL", $"DEL {dbPrefix}Key" },
                        { "DUMP", $"DUMP {dbPrefix}Key" },
                        { "EXISTS", $"EXISTS {dbPrefix}Key" },
                        { "PEXPIRE", $"PEXPIRE {dbPrefix}Key" },
                        { "MIGRATE", $"MIGRATE {dbPrefix}Key" }, // Only present on 1.0.297+
                        { "MOVE", $"MOVE {dbPrefix}Key" },
                        { "PERSIST", $"PERSIST {dbPrefix}Key" },
                        { "RANDOMKEY", $"RANDOMKEY" },
                        { "RENAME", $"RENAME {dbPrefix}Key" },
                        { "RESTORE", $"RESTORE {dbPrefix}Key" },
                        { "PTTL", $"PTTL {dbPrefix}Key" },
                        { "TYPE", $"TYPE {dbPrefix}Key" },
                        { "LINDEX", $"LINDEX {dbPrefix}List" },
                        { "LINSERT", $"LINSERT {dbPrefix}List" },
                        { "LINSERT", $"LINSERT {dbPrefix}List" },
                        { "LPOP", $"LPOP {dbPrefix}List" },
                        { "LPUSH", $"LPUSH {dbPrefix}List" },
                        { "LLEN", $"LLEN {dbPrefix}List" },
                        { "LRANGE", $"LRANGE {dbPrefix}List" },
                        { "LREM", $"LREM {dbPrefix}List" },
                        { "RPOP", $"RPOP {dbPrefix}List" },
                        { "RPOPLPUSH", $"RPOPLPUSH {dbPrefix}List" },
                        { "RPUSH", $"RPUSH {dbPrefix}List" },
                        { "LSET", $"LSET {dbPrefix}List" },
                        { "LTRIM", $"LTRIM {dbPrefix}List" },
                        { "GET", $"GET {dbPrefix}Lock" },
                        { "SET", $"SET {dbPrefix}Lock" },
                        { "PING", $"PING" },
                        { "PUBLISH", $"PUBLISH value" },
                        { "SADD", $"SADD {dbPrefix}Set" },
                        { "SUNION", $"SUNION {dbPrefix}Set" },
                        { "SUNIONSTORE", $"SUNIONSTORE {dbPrefix}Set" },
                        { "SISMEMBER", $"SISMEMBER {dbPrefix}Set" },
                        { "SCARD", $"SCARD {dbPrefix}Set" },
                        { "SMEMBERS", $"SMEMBERS {dbPrefix}Set" },
                        { "SMOVE", $"SMOVE {dbPrefix}Set" },
                        { "SPOP", $"SPOP {dbPrefix}Set" },
                        { "SRANDMEMBER", $"SRANDMEMBER {dbPrefix}Set" },
                        { "SRANDMEMBER", $"SRANDMEMBER {dbPrefix}Set" },
                        { "SREM", $"SREM {dbPrefix}Set" },
                        { "EXEC", $"EXEC" },
                        { "SORT", $"SORT {dbPrefix}Key" },                      // Only present on 1.0.206+
                        { "SORT", $"SORT {dbPrefix}Key" },                      // Only present on 1.0.206+
                        { "ZUNIONSTORE", $"ZUNIONSTORE {dbPrefix}SortedSet2" }, // Only present on 1.0.206+
                        { "ZADD", $"ZADD {dbPrefix}SortedSet" },
                        { "ZINCRBY", $"ZINCRBY {dbPrefix}SortedSet" },
                        { "ZINCRBY", $"ZINCRBY {dbPrefix}SortedSet" },
                        { "ZCARD", $"ZCARD {dbPrefix}SortedSet" },
                        { "ZRANGE", $"ZRANGE {dbPrefix}SortedSet" },
                        { "ZRANGE", $"ZRANGE {dbPrefix}SortedSet" },
                        { "ZRANGEBYSCORE", $"ZRANGEBYSCORE {dbPrefix}SortedSet" },
                        { "ZRANGEBYSCORE", $"ZRANGEBYSCORE {dbPrefix}SortedSet" },
                        { "ZRANK", $"ZRANK {dbPrefix}SortedSet" },
                        { "ZREM", $"ZREM {dbPrefix}SortedSet" },
                        { "ZREMRANGEBYRANK", $"ZREMRANGEBYRANK {dbPrefix}SortedSet" },
                        { "ZREMRANGEBYSCORE", $"ZREMRANGEBYSCORE {dbPrefix}SortedSet" },
                        { "ZSCORE", $"ZSCORE {dbPrefix}SortedSet" },
                        { "ZLEXCOUNT", $"ZLEXCOUNT {dbPrefix}SortedSet" },           // Only present on 1.0.273+
                        { "ZRANGEBYLEX", $"ZRANGEBYLEX {dbPrefix}SortedSet" },       // Only present on 1.0.273+
                        { "ZREMRANGEBYLEX", $"ZREMRANGEBYLEX {dbPrefix}SortedSet" }, // Only present on 1.0.273+
                        { "APPEND", $"APPEND {dbPrefix}Key" },
                        { "BITCOUNT", $"BITCOUNT {dbPrefix}Key" },
                        { "BITOP", $"BITOP" },
                        { "BITPOS", $"BITPOS {dbPrefix}Key" },
                        { "INCRBYFLOAT", $"INCRBYFLOAT {dbPrefix}Key" },
                        { "GET", $"GET {dbPrefix}Key" },
                        { "GETBIT", $"GETBIT {dbPrefix}Key" },
                        { "GETRANGE", $"GETRANGE {dbPrefix}Key" },
                        { "GETSET", $"GETSET {dbPrefix}Key" },
                        { "PTTL+GET", $"PTTL+GET {dbPrefix}Key" },
                        { "STRLEN", $"STRLEN {dbPrefix}Key" },
                        { "SET", $"SET {dbPrefix}Key" },
                        { "SETBIT", $"SETBIT {dbPrefix}Key" },
                        { "SETRANGE", $"SETRANGE {dbPrefix}Key" },
                    });

                    FilterExpectedResultsByApiVersion(expected, packageVersion);

                    var spans = agent.WaitForSpans(expected.Count).Where(s => s.Type == "redis").OrderBy(s => s.Start).ToList();
                    var host  = Environment.GetEnvironmentVariable("STACKEXCHANGE_REDIS_HOST") ?? "localhost:6389";
                    var port  = host.Substring(host.IndexOf(':') + 1);
                    host = host.Substring(0, host.IndexOf(':'));

                    foreach (var span in spans)
                    {
                        Assert.Equal("redis.command", span.Name);
                        Assert.Equal("Samples.StackExchange.Redis-redis", span.Service);
                        Assert.Equal(SpanTypes.Redis, span.Type);
                        Assert.Equal(host, DictionaryExtensions.GetValueOrDefault(span.Tags, "out.host"));
                        Assert.Equal(port, DictionaryExtensions.GetValueOrDefault(span.Tags, "out.port"));
                        Assert.False(span.Tags?.ContainsKey(Tags.Version), "External service span should not have service version tag.");
                    }

                    var spanLookup = new Dictionary <Tuple <string, string>, int>();
                    foreach (var span in spans)
                    {
                        var key = new Tuple <string, string>(span.Resource, DictionaryExtensions.GetValueOrDefault(span.Tags, "redis.raw_command"));
                        if (spanLookup.ContainsKey(key))
                        {
                            spanLookup[key]++;
                        }
                        else
                        {
                            spanLookup[key] = 1;
                        }
                    }

                    var missing = new List <Tuple <string, string> >();

                    foreach (var e in expected)
                    {
                        var found = spanLookup.ContainsKey(e);
                        if (found)
                        {
                            if (--spanLookup[e] <= 0)
                            {
                                spanLookup.Remove(e);
                            }
                        }
                        else
                        {
                            missing.Add(e);
                        }
                    }

                    foreach (var e in missing)
                    {
                        Assert.True(false, $"no span found for `{e.Item1}`, `{e.Item2}`, remaining spans: `{string.Join(", ", spanLookup.Select(kvp => $"{kvp.Key.Item1}, {kvp.Key.Item2}").ToArray())}`");
                    }

                    telemetry.AssertIntegrationEnabled(IntegrationId.StackExchangeRedis);
                }
        }