2010-09-13 2 views
2

D'un autre fil qui m'a donné les informations sur la façon d'ajouter la surveillance à un serveur SQL ...Surveillance SQL et Interjection

See SQL From EntityFramework with Collection-like Queries

Cela fonctionne bien, mais je veux prendre un peu plus loin. J'aimerais pouvoir ajouter des commentaires dans le journal lorsque des transactions sont en cours.

Je veux être capable d'écrire des commentaires dans les choses, mais, qui va entrer dans l'enregistrement SQL. Donc, comme je peux faire une requête, et appelez Debugger.Logger.Write ("Une sorte de commentaire"), donc je sais ce que c'est. Je ne connais pas très bien le SQL, alors j'essaie de comprendre ce qui se passe et où.

Toute aide est grandement appréciée. Je suppose que je devrais exécuter une autre requête SQL pour 'insérer' le commentaire dans le flux de la requête.

Je conçois mon contexte de données (DbContext)

using(var context = new SampleDataContext(dbModel)) 
{ 
// ... 
      // prepare a logging model. 
      if (Debugger.SetupLog(context)) 
       Console.WriteLine("Logging Enabled..."); 
      // open up the debugger log 
      Debugger.Open(); 
} 

public class SampleDataContext: DbContext, IDisposable 
    { 
     public new void Dispose() 
     { 
      Debugger.Log(this); 

      base.Dispose(); 
     } 
    } 

Puis la classe Debugger ..

public static class Debugger 
{ 
    public static System.IO.TextWriter File 
    { 
     get; 
     set; 
    } 
    public static void Open() 
    { 
     // open a file for storing SQL results from queries 
     File = new System.IO.StreamWriter("results.sql", false); 
    } 

    public static void Write(string text) 
    { 
     File.WriteLine(text); 
    } 

    public static bool Log(SampleDataContext context) 
    { 
     var results = context.Database.Connection.CreateCommand(); 
     results.CommandText = Sql.Review; 
     context.Database.Connection.Open(); 

     System.Data.Common.DbDataReader resultsReader; 
     do 
     { 
      resultsReader = results.ExecuteReader(); 
     } 
     while (resultsReader == null); 

     Console.WriteLine("Discovered a Data Reader"); 

     // Retrieves the schema of the table. 
     var dtSchema = resultsReader.GetSchemaTable(); 

     string strRow; // represents a full row 
     // Reads the rows one by one from the SqlDataReader 
     // transfers them to a string with the given separator character and 
     // writes it to the file. 
     while (resultsReader.Read()) 
     { 
      Console.WriteLine("Reading Data Reader... "); 

      strRow = ""; 
      for (int i = 0; i < resultsReader.FieldCount; i++) 
      { 
       strRow += resultsReader.GetValue(i).ToString(); 
       if (i < resultsReader.FieldCount - 1) 
       { 
        strRow += " "; 
       } 
      } 

      Sql.Text.Lexer lexer = new Sql.Text.Lexer(); 
      lexer.Enscribe(); 

      var matches = lexer.Tokenize(strRow); 
      matches.ForEach(x => 
           { 
            strRow = strRow.Replace(x.Value, Environment.NewLine); 
           }); 

      File.WriteLine(strRow); 
     } 

     File.Close(); 
     context.Database.Connection.Close(); 

     return false; 
    } 

    public static bool SetupLog(SampleDataContext context) 
    { 
     var command = context.Database.Connection.CreateCommand(); 
     command.CommandText = Sql.Record; 

     context.Database.Connection.Open(); 
     command.ExecuteNonQuery(); 
     context.Database.Connection.Close(); 

     return true; 
    } 
} 

J'ai essentiellement inséré l'instruction SQL suivante dans une ressource en C# ...

Ceci est "Project.SQL.Record".

IF EXISTS(SELECT * FROM sys.server_event_sessions WHERE name='test_trace') 
    DROP EVENT SESSION [test_trace] ON SERVER; 
CREATE EVENT SESSION [test_trace] 
ON SERVER 
ADD EVENT sqlserver.sp_statement_completed(
    ACTION (package0.callstack, sqlserver.session_id, sqlserver.sql_text) 
    -- WHERE (([sqlserver].[username]='Domain\Username')) 
    ), 
ADD EVENT sqlserver.sql_statement_completed(
    ACTION (package0.callstack, sqlserver.session_id, sqlserver.sql_text) 
    --WHERE (([sqlserver].[username]='Domain\Username')) 
    ) 
ADD TARGET package0.ring_buffer 
WITH (MAX_MEMORY = 4096KB, EVENT_RETENTION_MODE = ALLOW_SINGLE_EVENT_LOSS, 
MAX_DISPATCH_LATENCY = 1 SECONDS, MAX_EVENT_SIZE = 0KB, 
MEMORY_PARTITION_MODE = NONE, TRACK_CAUSALITY = OFF, STARTUP_STATE = OFF) 

ALTER EVENT SESSION [test_trace] ON SERVER STATE = START 

Puis j'ai un autre, "Project.SQL.Review".

DECLARE 
    @session_name VARCHAR(200) = 'test_trace' 

SELECT 
    pivoted_data.* 
FROM 
( 
SELECT MIN(event_name) AS event_name, 
    MIN(event_timestamp) AS event_timestamp, 
    unique_event_id, 
    CONVERT (BIGINT, MIN (
     CASE 
      WHEN d_name = 'cpu' 
      AND d_package IS NULL 
      THEN d_value 
     END)) AS [cpu], 
    CONVERT (BIGINT, MIN (
     CASE 
      WHEN d_name = 'duration' 
      AND d_package IS NULL 
      THEN d_value 
     END)) AS [duration], 
    CONVERT (BIGINT, MIN (
     CASE 
      WHEN d_name = 'object_id' 
      AND d_package IS NULL 
      THEN d_value 
     END)) AS [object_id], 
    CONVERT (INT, MIN (
     CASE 
      WHEN d_name = 'object_type' 
      AND d_package IS NULL 
      THEN d_value 
     END)) AS [object_type], 
    CONVERT (DECIMAL(28,0), MIN (
     CASE 
      WHEN d_name = 'reads' 
      AND d_package IS NULL 
      THEN d_value 
     END)) AS [reads], 
    CONVERT (VARCHAR(MAX), MIN (
     CASE 
      WHEN d_name = 'session_id' 
      AND d_package IS NOT NULL 
      THEN d_value 
     END)) AS [session_id], 
    CONVERT (INT, MIN (
     CASE 
      WHEN d_name = 'source_database_id' 
      AND d_package IS NULL 
      THEN d_value 
     END)) AS [source_database_id], 
    CAST((SELECT CONVERT (VARCHAR(MAX), MIN (
     CASE 
      WHEN d_name = 'sql_text' 
      AND d_package IS NOT NULL 
      THEN d_value 
     END)) AS [processing-instruction(x)] FOR XML PATH('')) AS XML) AS [sql_text], 
    CONVERT (DECIMAL(28,0), MIN (
     CASE 
      WHEN d_name = 'writes' 
      AND d_package IS NULL 
      THEN d_value 
     END)) AS [writes] 
FROM 
    ( 
     SELECT 
      *, 
      CONVERT(VARCHAR(400), NULL) AS attach_activity_id 
     FROM 
     ( 
      SELECT 
       event.value('(@name)[1]', 'VARCHAR(400)') as event_name, 
       event.value('(@timestamp)[1]', 'DATETIME') as event_timestamp, 
       DENSE_RANK() OVER (ORDER BY event) AS unique_event_id, 
       n.value('(@name)[1]', 'VARCHAR(400)') AS d_name, 
       n.value('(@package)[1]', 'VARCHAR(400)') AS d_package, 
       n.value('((value)[1]/text())[1]', 'VARCHAR(MAX)') AS d_value, 
       n.value('((text)[1]/text())[1]', 'VARCHAR(MAX)') AS d_text 
      FROM 
      ( 
       SELECT 
        ( 
         SELECT 
          CONVERT(xml, target_data) 
         FROM sys.dm_xe_session_targets st 
         JOIN sys.dm_xe_sessions s ON 
          s.address = st.event_session_address 
         WHERE 
          s.name = @session_name 
          AND st.target_name = 'ring_buffer' 
        ) AS [x] 
       FOR XML PATH(''), TYPE 
      ) AS the_xml(x) 
      CROSS APPLY x.nodes('//event') e (event) 
      CROSS APPLY event.nodes('*') AS q (n) 
     ) AS data_data 
    ) AS activity_data 
    GROUP BY 
     unique_event_id 
) AS pivoted_data; 

Ma première pensée était de faire une méthode comme celui-ci ..

public static void WriteSql(SampleDataContext context, string text) 
    { 
     var command = context.Database.Connection.CreateCommand(); 
     command.Parameters.Add(new System.Data.SqlClient.SqlParameter("@Comment",System.Data.SqlDbType.VarChar)); 
     command.Parameters["@Comment"].Value = String.Format("--{0}", text); 
     command.CommandText = String.Format("PRINT '{0}'", text.Replace("'", "''")); 
     context.Database.Connection.Open(); 
     command.ExecuteNonQuery(); 
     context.Database.Connection.Close(); 
    } 

Il devrait exécuter le commentaire comme une requête, qui devrait apparaître dans l'examen, non? Eh bien, ça n'a pas marché. Donc je suis ouvert à d'autres idées ...

Répondre

1

Vous pourriez probablement utiliser une instruction PRINT pour cela. Utilisez une requête avec paramétrés un paramètre appelé @Comment puis exécutez

PRINT @Comment 

Si les commentaires doivent être facilement distingués des requêtes régulières, vous pouvez ajouter un nouvel événement

, 
ADD EVENT sqlserver.error_reported(
    ACTION (sqlserver.sql_text) 
    WHERE (([severity]=(1)))) 

et utiliser RAISERROR(@Comment,1,1) à la place.

+0

J'ai modifié le dernier morceau de mon code pour refléter votre suggestion, mais tout ce qu'il montre est le SQL brut « PRINT @Comment » dans la sortie. Des idées où je me trompe? – Ciel

+0

Non. Essayez peut-être d'utiliser 'varchar' plutôt que du texte comme paramètre. 'text' est un type de données LOB donc peut ne pas fonctionner avec print. Si cela ne je suppose que vous pouvez simplement utiliser fonctionne pas alors quelque chose comme 'Command.CommandText = String.Format (« IMPRIMER « {0} » », text.Replace (« ' », « « » »));' comme c'est votre code qui crée les commentaires et vous n'avez pas à vous soucier de l'injection SQL. –

+0

J'ai mis à jour mon code ci-dessus dans la méthode WriteSql et toujours aucun dé. Il ne montre rien dans la sortie Sql. – Ciel