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); } }
/// <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)); } }
protected override ParsedSqlStatement CreateParsedDatabaseStatement(DatastoreVendor vendor, string model) { if (model.Length > 50) { model = model.Substring(0, 50); } return(new ParsedSqlStatement(vendor, model, "show")); }
public static ConnectionInfo FromConnectionString(DatastoreVendor vendor, string connectionString) { return(_connectionInfoCache.GetOrAdd(connectionString, () => { IConnectionStringParser parser = GetConnectionParser(vendor, connectionString); return parser?.GetConnectionInfo() ?? Empty; })); }
/// <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)); } }
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); }
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)); }
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); }
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); }
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)); }
/// <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)); }
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))); }
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)); }
public static ParsedSqlStatement FromOperation(DatastoreVendor vendor, string operation) { return(new ParsedSqlStatement(vendor, null, operation)); }
public TValue GetOrAdd(DatastoreVendor vendor, TKey key, Func <TValue> valueFunc) { return(_caches[(int)vendor].GetOrAdd(key, valueFunc)); }
protected virtual ParsedSqlStatement CreateParsedDatabaseStatement(DatastoreVendor vendor, string model) { return(new ParsedSqlStatement(vendor, model.ToLower(), _key)); }
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(); }
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)); }
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)); }