Beispiel #1
0
        private static IConnectionStringParser GetConnectionParser(DatastoreVendor vendor, string connectionString)
        {
            switch (vendor)
            {
            case DatastoreVendor.MSSQL:
                return(new MsSqlConnectionStringParser(connectionString));

            case DatastoreVendor.MySQL:
                return(new MySqlConnectionStringParser(connectionString));

            case DatastoreVendor.Postgres:
                return(new PostgresConnectionStringParser(connectionString));

            case DatastoreVendor.Oracle:
                return(new OracleConnectionStringParser(connectionString));

            case DatastoreVendor.IBMDB2:
                return(new IbmDb2ConnectionStringParser(connectionString));

            case DatastoreVendor.Redis:
                return(new StackExchangeRedisConnectionStringParser(connectionString));

            default:
                return(null);
            }
        }
Beispiel #2
0
        /// <summary>
        /// Heursitical crawl through a database command to find features suitable for making metric names.
        /// This uses linear search through the regexp patterns.
        /// </summary>
        /// <returns>A ParsedDatabaseStatement if some heuristic matches; otherwise null</returns>
        public static ParsedSqlStatement GetParsedDatabaseStatement(DatastoreVendor datastoreVendor, CommandType commandType, string commandText)
        {
            try
            {
                switch (commandType)
                {
                case CommandType.TableDirect:
                    return(new ParsedSqlStatement(datastoreVendor, commandText, "select"));

                case CommandType.StoredProcedure:
                    return(new ParsedSqlStatement(datastoreVendor, StringsHelper.FixDatabaseObjectName(commandText), "ExecuteProcedure"));
                }
                // Remove comments.
                var statement = CommentPattern.Replace(commandText, string.Empty).TrimStart();

                if (!IsSingleSqlStatement(statement))
                {
                    // Remove leading SET commands

                    // Trimming any trailing semicolons is necessary to avoid having the LeadingSetPattern
                    // match a SQL statement that ONLY contains SET commands, which would leave us with nothing
                    statement = statement.TrimEnd(SemiColon);
                    statement = LeadingSetPattern.Replace(statement, string.Empty).TrimStart();
                }

                return(_statementParser(datastoreVendor, commandType, commandText, statement));
            }
            catch
            {
                return(new ParsedSqlStatement(datastoreVendor, null, null));
            }
        }
Beispiel #3
0
 protected override ParsedSqlStatement CreateParsedDatabaseStatement(DatastoreVendor vendor, string model)
 {
     if (model.Length > 50)
     {
         model = model.Substring(0, 50);
     }
     return(new ParsedSqlStatement(vendor, model, "show"));
 }
Beispiel #4
0
 public static ConnectionInfo FromConnectionString(DatastoreVendor vendor, string connectionString)
 {
     return(_connectionInfoCache.GetOrAdd(connectionString, () =>
     {
         IConnectionStringParser parser = GetConnectionParser(vendor, connectionString);
         return parser?.GetConnectionInfo() ?? Empty;
     }));
 }
Beispiel #5
0
 /// <summary>
 /// Construct a summarized SQL statement.
 ///
 /// Examples:
 ///   select * from dude ==> ParsedDatabaseStatement("dude", "select");
 ///   set @foo=17 ==> ParsedDatabaseStatement("foo", "set")
 ///
 /// See DatabaseStatementParserTest for additional examples.
 ///
 /// </summary>
 /// <param name="model">What the statement is operating on, eg the "direct object" of the operation.</param>
 /// <param name="operation">What the operation is doing.</param>
 public ParsedSqlStatement(DatastoreVendor datastoreVendor, string model, string operation)
 {
     Model           = model;
     Operation       = operation ?? "other";
     DatastoreVendor = datastoreVendor;
     _asString       = $"{Model}/{Operation}";
     DatastoreStatementMetricName = $"Datastore/statement/{EnumNameCache<DatastoreVendor>.GetName(datastoreVendor)}/{_asString}";
 }
        /// <summary>
        /// SQL obfuscation is expensive. It is performed when a transaction has ended in the creation of SQL traces and transaction traces.
        /// Whether we obfuscate SQL for traces depends on configuration. We reduce the number of times SQL obfuscation is performed by caching
        /// results.
        /// </summary>
        /// <param name="sql"></param>
        /// <returns></returns>
        private string GetObfuscatedSqlFromCache(string sql, DatastoreVendor vendor)
        {
            return(_cache.GetOrAdd(vendor, sql, ObfuscateSql));

            string ObfuscateSql()
            {
                return(SqlObfuscator.GetObfuscatingSqlObfuscator().GetObfuscatedSql(sql, vendor));
            }
        }
Beispiel #7
0
        private Segment GetSegment(DatastoreVendor vendor, string operation, string model)
        {
            var data    = new DatastoreSegmentData(_databaseService, new ParsedSqlStatement(vendor, model, operation));
            var segment = new Segment(TransactionSegmentStateHelpers.GetItransactionSegmentState(), new MethodCallData("foo", "bar", 1));

            segment.SetSegmentData(data);

            return(segment);
        }
Beispiel #8
0
        private Segment GetSegment(DatastoreVendor vendor, string operation, string model, double duration, CrossApplicationResponseData catResponseData = null, string host = null, string portPathOrId = null)
        {
            var methodCallData = new MethodCallData("foo", "bar", 1);
            var data           = new DatastoreSegmentData(_databaseService, new ParsedSqlStatement(vendor, model, operation), null, new ConnectionInfo(host, portPathOrId, null));
            var segment        = new Segment(TransactionSegmentStateHelpers.GetItransactionSegmentState(), methodCallData);

            segment.SetSegmentData(data);

            return(segment.CreateSimilar(new TimeSpan(), TimeSpan.FromSeconds(duration), null));
        }
Beispiel #9
0
            public ParsedSqlStatement ParseStatement(DatastoreVendor vendor, CommandType commandType, string commandText, string statement)
            {
                var matcher = SelectMatcher.Match(statement);

                if (matcher.Success)
                {
                    return(FromMatcher.Match(statement).Success ? new ParsedSqlStatement(vendor, "(subquery)", "select") : new ParsedSqlStatement(vendor, "VARIABLE", "select"));
                }
                return(null);
            }
Beispiel #10
0
        public ParsedSqlStatement ParseDatabaseStatement(DatastoreVendor datastoreVendor, CommandType commandType, string sql)
        {
            switch (commandType)
            {
            case CommandType.TableDirect:
            case CommandType.StoredProcedure:
                return(SqlParser.GetParsedDatabaseStatement(datastoreVendor, commandType, sql));

            default:
                return(_cache.GetOrAdd(datastoreVendor, sql, () => SqlParser.GetParsedDatabaseStatement(datastoreVendor, commandType, sql)));
            }
        }
        private Segment BuildSegment(DatastoreVendor vendor, string model, string commandText, TimeSpan startTime = new TimeSpan(), TimeSpan?duration = null, string name = "", MethodCallData methodCallData = null, IEnumerable <KeyValuePair <string, object> > parameters = null, string host = null, string portPathOrId = null, string databaseName = null)
        {
            var data = new DatastoreSegmentData(_databaseService, new ParsedSqlStatement(vendor, model, null), commandText,
                                                new ConnectionInfo(host, portPathOrId, databaseName));

            methodCallData = methodCallData ?? new MethodCallData("typeName", "methodName", 1);

            var segment = new Segment(TransactionSegmentStateHelpers.GetItransactionSegmentState(), methodCallData);

            segment.SetSegmentData(data);

            return(new Segment(startTime, duration, segment, parameters));
        }
        public void TestConnectionStringParsing(DatastoreVendor vendor, string expectedHost, string expectedPathPortOrId, string expectedDatabaseName, string expectedInstanceName, string connectionString)
        {
            if (expectedHost == "hostname_of_localhost")
            {
                expectedHost = Dns.GetHostName();
            }

            var connectionInfo = ConnectionInfoParser.FromConnectionString(vendor, connectionString);

            Assert.True(connectionInfo.Host == expectedHost);
            Assert.True(connectionInfo.PortPathOrId == expectedPathPortOrId);
            Assert.True(connectionInfo.DatabaseName == expectedDatabaseName);
            Assert.True(connectionInfo.InstanceName == expectedInstanceName);
        }
Beispiel #13
0
            public virtual ParsedSqlStatement ParseStatement(DatastoreVendor vendor, CommandType commandType, string commandText, string statement)
            {
                if (!string.IsNullOrEmpty(_shortcut) && !statement.StartsWith(_shortcut, StringComparison.CurrentCultureIgnoreCase))
                {
                    return(null);
                }

                var matcher = _pattern.Match(statement);

                if (!matcher.Success)
                {
                    return(null);
                }

                var model = "unknown";

                foreach (Group g in matcher.Groups)
                {
                    var str = g.ToString();
                    if (!string.IsNullOrEmpty(str))
                    {
                        model = str;
                    }
                }

                if (string.Equals(model, "select", StringComparison.CurrentCultureIgnoreCase))
                {
                    model = "(subquery)";
                }
                else
                {
                    model = StringsHelper.FixDatabaseObjectName(model);
                    if (!IsValidModelName(model))
                    {
                        model = "ParseError";
                    }
                }
                return(CreateParsedDatabaseStatement(vendor, model));
            }
Beispiel #14
0
        /// <summary>
        /// Heursitical crawl through a database command to find features suitable for making metric names.
        /// This uses linear search through the regexp patterns.
        /// </summary>
        /// <returns>A ParsedDatabaseStatement if some heuristic matches; otherwise null</returns>
        public static ParsedSqlStatement GetParsedDatabaseStatement(DatastoreVendor datastoreVendor, CommandType commandType, string commandText)
        {
            try
            {
                switch (commandType)
                {
                case CommandType.TableDirect:
                    return(new ParsedSqlStatement(datastoreVendor, commandText, "select"));

                case CommandType.StoredProcedure:
                    return(new ParsedSqlStatement(datastoreVendor, StringsHelper.FixDatabaseObjectName(commandText), "ExecuteProcedure"));
                }
                // Remove comments.
                var statement = CommentPattern.Replace(commandText, string.Empty).TrimStart();

                return(_statementParser(datastoreVendor, commandType, commandText, statement));
            }
            catch
            {
                return(new ParsedSqlStatement(datastoreVendor, null, null));
            }
        }
 public ParsedSqlStatement GetParsedDatabaseStatement(DatastoreVendor vendor, CommandType commandType, string sql)
 {
     return(null);
 }
 /// <summary>
 /// If the SQL obfuscation settings are set to obfuscate, this will return the obfuscated SQL using the cache. Otherwise, it just returns
 /// the value returned from the SQL obfuscator defined by the configuration because there is no need to cache the value of the no sql and raw sql obfuscators.
 /// </summary>
 /// <param name="sql"></param>
 /// <returns></returns>
 public string GetObfuscatedSql(string sql, DatastoreVendor vendor)
 {
     return(_sqlObfuscator != SqlObfuscator.GetObfuscatingSqlObfuscator()
         ? _sqlObfuscator.GetObfuscatedSql(sql, vendor)
         : GetObfuscatedSqlFromCache(sql, vendor));
 }
        /// <summary>
        /// The generation of SQL IDs always uses obfuscation in order to normalize the SQL and generate the same ID for queries that differ only in their parameterization.
        /// </summary>
        /// <param name="sql"></param>
        /// <returns></returns>
        public long GetSqlId(string sql, DatastoreVendor vendor)
        {
            var obfuscatedSql = GetObfuscatedSqlFromCache(sql, vendor);

            return(GenerateSqlId(obfuscatedSql));
        }
Beispiel #18
0
            public override string GetObfuscatedSql(string sql, DatastoreVendor vendor = DatastoreVendor.Other)
            {
                if (sql == null)
                {
                    return(null);
                }

                StringBuilder sb     = new StringBuilder();
                int           length = sql.Length;

                for (int i = 0; i < length; i++)
                {
                    char ch = sql[i];

                    // Span across quoted strings.
                    if (ch == '\'' || ch == '"' || ch == '`')
                    {
                        char quotechar = ch;
                        sb.Append('?');
                        i += 1;  // Skip into string
                        for (; i < length; i++)
                        {
                            ch = sql[i];

                            // MS SQL Server has different escaping rules by default than most other vendors
                            // In particular, backslashes do not escape the next character, so they should not be treated specially
                            if (vendor == DatastoreVendor.MSSQL && ch == quotechar)
                            {
                                // In order to get a literal single quote inside of a single-quoted string, MSSQL uses two single quotes in a row, so we need to check for this case
                                // This implementation works no matter what the quoting character happens to be
                                if (i < length - 1 && sql[i + 1] == quotechar)
                                {
                                    i += 1;
                                    continue;
                                }
                                break;
                            }

                            if (vendor != DatastoreVendor.MSSQL && ch == '\\' && i < length - 1)
                            {
                                // Skip escaped characters
                                i += 1;
                                continue;
                            }
                            if (ch == quotechar)
                            {
                                break;
                            }
                        }
                        if (i >= length)
                        {
                            break;               // Fell off the end
                        }
                        // We've reached the termination character of the string, which we'll implicitly consume in the outer loop
                        continue;
                    }

                    // Span across numeric values, including floats.
                    // We're a little lazy here, and allow a single number to have multiple decimal points.
                    // But we know we are dealing with well formed input.
                    if (char.IsDigit(ch) || (ch == '.' && i < length - 1 && char.IsDigit(sql[i + 1])))
                    {
                        sb.Append('?');
                        for (; i < length; i++)
                        {
                            ch = sql[i];
                            if (char.IsDigit(ch) || (ch == '.'))
                            {
                                continue;
                            }
                            else
                            {
                                break;
                            }
                        }
                        if (i >= length)
                        {
                            break; // Fell off the end
                        }
                        i -= 1;    // back up to just before failure
                        continue;
                    }

                    // Span across identifiers
                    if (char.IsLetter(ch) || ch == '_')
                    {
                        for (; i < length; i++)
                        {
                            ch = sql[i];
                            if (char.IsLetter(ch) || ch == '_' || char.IsDigit(ch))
                            {
                                sb.Append(ch);
                                continue;
                            }
                            else
                            {
                                break;
                            }
                        }
                        if (i >= length)
                        {
                            break; // Fell off the end
                        }
                        i -= 1;    // back up to just before failure
                        continue;
                    }

                    // None of the above, just pass it through
                    sb.Append(ch);
                }

                return(sb.ToString(0, Math.Min(sb.Length, SqlStatementMaxLength)));
            }
Beispiel #19
0
 public override string GetObfuscatedSql(string sql, DatastoreVendor vendor = DatastoreVendor.Other)
 {
     return(null);
 }
 public static MetricName GetDatastoreInstance(DatastoreVendor vendor, string host, string portPathOrId)
 {
     return(MetricName.Create(DatastoreInstance, EnumNameCache <DatastoreVendor> .GetName(vendor), host, portPathOrId));
 }
Beispiel #21
0
 public static ParsedSqlStatement FromOperation(DatastoreVendor vendor, string operation)
 {
     return(new ParsedSqlStatement(vendor, null, operation));
 }
Beispiel #22
0
 public TValue GetOrAdd(DatastoreVendor vendor, TKey key, Func <TValue> valueFunc)
 {
     return(_caches[(int)vendor].GetOrAdd(key, valueFunc));
 }
Beispiel #23
0
 protected virtual ParsedSqlStatement CreateParsedDatabaseStatement(DatastoreVendor vendor, string model)
 {
     return(new ParsedSqlStatement(vendor, model.ToLower(), _key));
 }
Beispiel #24
0
        private void CreateATransactionWithDatastoreSegmentAndHarvest(bool instanceReportingEnabled, bool databaseNameReportingEnabled, DatastoreVendor vendor = DatastoreVendor.MSSQL, string host = "myhost", string portPathOrId = "myport", string databaseName = "mydatabase")
        {
            _compositeTestAgent.LocalConfiguration.transactionTracer.explainThreshold            = 0;
            _compositeTestAgent.LocalConfiguration.datastoreTracer.instanceReporting.enabled     = instanceReportingEnabled;
            _compositeTestAgent.LocalConfiguration.datastoreTracer.databaseNameReporting.enabled = databaseNameReportingEnabled;
            _compositeTestAgent.PushConfiguration();
            var tx = _agent.CreateTransaction(
                isWeb: true,
                category: EnumNameCache <WebTransactionType> .GetName(WebTransactionType.Action),
                transactionDisplayName: "name",
                doNotTrackAsUnitOfWork: true);
            var segment = _agent.StartDatastoreRequestSegmentOrThrow("SELECT", vendor, "Table1", "SELECT * FROM Table1", null, host, portPathOrId, databaseName);

            segment.End();
            tx.End();
            _compositeTestAgent.Harvest();
        }
Beispiel #25
0
 public abstract string GetObfuscatedSql(string sql, DatastoreVendor vendor = DatastoreVendor.Other);
 public static MetricName GetDatastoreOperation(this DatastoreVendor vendor, string operation = null)
 {
     operation = operation ?? DatastoreUnknownOperationName;
     return(_databaseVendorOperations.Invoke(vendor).Invoke(operation));
 }
 public static MetricName GetDatastoreVendorAllOther(this DatastoreVendor vendor)
 {
     return(_databaseVendorAllOther.Invoke(vendor));
 }
Beispiel #28
0
 protected override ParsedSqlStatement CreateParsedDatabaseStatement(DatastoreVendor vendor, string model)
 {
     // We drop the time string in this.model on the floor.  It may contain quotes, colons, periods, etc.
     return(new ParsedSqlStatement(vendor, "time", "waitfor"));
 }
        public static ISegment StartDatastoreRequestSegmentOrThrow(this IAgent agent, DatastoreVendor vendor, CommandType commandType, string commandText = null, MethodCall methodCall = null, string host = null, string portPathOrId = null, string databaseName = null, IDictionary <string, IConvertible> queryParameters = null)
        {
            methodCall = methodCall ?? GetDefaultMethodCall(agent);
            var parsedStatement = agent.CurrentTransaction.GetParsedDatabaseStatement(vendor, commandType, commandText);

            var segment = agent.CurrentTransaction.StartDatastoreSegment(methodCall, parsedStatement, new ConnectionInfo(host, portPathOrId, databaseName), commandText, queryParameters);

            if (segment == null)
            {
                throw new NullReferenceException("segment");
            }

            return(segment);
        }
 public static MetricName GetDatastoreStatement(DatastoreVendor vendor, string model,
                                                string operation = null)
 {
     operation = operation ?? DatastoreUnknownOperationName;
     return(MetricName.Create(DatastoreStatement, EnumNameCache <DatastoreVendor> .GetName(vendor), model, operation));
 }