Analysis-Services/AsXEventSample/TracingSample/Program.cs

219 строки
9.8 KiB
C#
Исходник Постоянная ссылка Ответственный История

Этот файл содержит невидимые символы Юникода!

Этот файл содержит невидимые символы Юникода, которые могут быть отображены не так, как показано ниже. Если это намеренно, можете спокойно проигнорировать это предупреждение. Используйте кнопку Экранировать, чтобы показать скрытые символы.

/*============================================================================
Summary: Contains class implementiong xEvent data logging for Azure Analysis Services
Copyright (C) Microsoft Corporation.
This source code is intended only as a supplement to Microsoft
Development Tools and/or on-line documentation.
THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.
============================================================================*/
using System;
using System.Xml;
using System.Threading;
using System.IO;
using System.Text;
using Microsoft.AnalysisServices;
using Microsoft.AnalysisServices.AdomdClient;
using Microsoft.SqlServer.XEvent.Linq; // Referenced from the GAC version of Microsoft.SqlServer.XEvent.Linq
namespace TracingSample
{
public class Worker
{
private string UserName;
private string AsServer;
private string AsDatabase;
private string eventTmsl;
private string logFile;
public Worker(string user, string server, string db, string events, string log)
{
UserName = user;
AsServer = server;
AsDatabase = db;
eventTmsl = events;
logFile = log;
}
// This method will be called when the thread is started. 
public void DoWork()
{
try
{
using (Server server = new Server())
{
//Connect and get main objects
string serverConnectionString;
// Assume integratedAuth
// otherwise serverConnectionString = $"Provider=MSOLAP;Data Source={AsServer};User ID={UserName};Password={Password};Impersonation Level=Impersonate;";
serverConnectionString = $"Provider=MSOLAP;Data Source={AsServer};Integrated Security=SSPI";
server.Connect(serverConnectionString);
Database database = server.Databases.FindByName(AsDatabase);
if (database == null)
{
throw new Microsoft.AnalysisServices.ConnectionException($"Could not connect to database {AsDatabase}.");
}
//Register the events you want to trace
string queryString = System.IO.File.ReadAllText(eventTmsl);
server.Execute(queryString);
// Now you need to subscribe to the xEvent stream and execute a data reader
// You need to have the same name as in the TMSL file!
// NOTE calls to the reader will block until new values show up!
string sessionId = "SampleXEvents";
AdomdConnection conn = new AdomdConnection(serverConnectionString);
conn.Open();
var cmd = conn.CreateCommand();
cmd.CommandType = System.Data.CommandType.Text;
cmd.CommandText =
"<Subscribe xmlns=\"http://schemas.microsoft.com/analysisservices/2003/engine\">" +
"<Object xmlns=\"http://schemas.microsoft.com/analysisservices/2003/engine\">" +
"<TraceID>" + sessionId + "</TraceID>" +
"</Object>" +
"</Subscribe>";
XmlReader inputReader = XmlReader.Create(cmd.ExecuteXmlReader(), new XmlReaderSettings() { Async = true });
//Connect to this with QueryableXEventData
using (QueryableXEventData data =
new QueryableXEventData(inputReader, EventStreamSourceOptions.EventStream, EventStreamCacheOptions.CacheToDisk))
{
using (FileStream fs = new FileStream(logFile, FileMode.Create, FileAccess.Write, FileShare.None))
{
//Write out the data in a long format for illustration
// this could would be adpated for your specific needs
foreach (PublishedEvent evt in data)
{
StringBuilder s = new StringBuilder();
s.Append($"Event: {evt.Name}\t");
s.Append(Environment.NewLine);
s.Append($"Timestamp: {evt.Timestamp}\t");
s.Append(Environment.NewLine);
foreach (PublishedEventField fld in evt.Fields)
{
s.Append($"Field: {fld.Name} = {fld.Value}\t");
s.Append(Environment.NewLine);
}
foreach (PublishedAction act in evt.Actions)
{
s.Append($"Action: {act.Name} = {act.Value}\t");
s.Append(Environment.NewLine);
}
s.Append(Environment.NewLine);
//Write the data to a log file
// the format and sink should be changed for your proposes
byte[] bytes = Encoding.ASCII.GetBytes(s.ToString().ToCharArray());
fs.Write(bytes, 0, s.Length);
if (_shouldStop == true)
{
break;
}
// Writing a . to show progress
Console.Write(".");
//Uncomment this to output to the Console
//Console.WriteLine(s);
}
//TODO stop the trace !
fs.Close();
}
conn.Close();
//clean up the trace on exit -- or you can keep it running
//var stopCommand = conn.CreateCommand();
//stopCommand.CommandType = System.Data.CommandType.Text;
var stopCommand =
"<Execute xmlns = \"urn:schemas-microsoft-com:xml-analysis\">" +
"<Command>" +
"<Batch …>" +
"<Delete …>" +
// You need to have the same name as in the TMSL file!
"<Object><TraceID>"+sessionId+"</TraceID></Object>" +
"</Delete>" +
"<Batch …>" +
"<Command>" +
"<Properties></Properties>" +
"</Execute>";
server.Execute(queryString);
server.Disconnect();
}
}
}
catch (Exception e)
{
//TODO: handle exceptions :-)
Console.WriteLine(e.ToString());
Console.WriteLine("There was an error. Verify the command-line parmaters. Press any key to exit.");
}
//Worker thread: terminating gracefully.
}
public void RequestStop()
{
_shouldStop = true;
}
// Volatile is used as hint to the compiler that this data 
// member will be accessed by multiple threads. 
private volatile bool _shouldStop;
}
class Program
{
static void Main(string[] args)
{
string UserName = "user@contoso.com";
string AsServer = "asazure://region.asazure.windows.net/myinstance";
string AsDatabase = "SalesBI";
string eventTmsl = @"C:\AsXEventSample\eventTmsl.xmla"; // location of the xEvents TMSL file you want to collect, you can create this with SSMS script out
string logFile = @"C:\AsXEventSample\aslog.txt"; //location of the outputfile
// Using a thread here as data comes in asychronously
// Create the thread object. This does not start the thread.
Worker workerObject = new Worker(UserName, AsServer, AsDatabase, eventTmsl, logFile);
Thread workerThread = new Thread(workerObject.DoWork);
// Start the worker thread.
workerThread.Start();
// For monitoring, this would be upgraded to a windows service
Console.WriteLine("Listening for trace events which are sent when there is trace activity.");
Console.WriteLine("Type the letter q and enter to quit. The process will exit after the next trace event is received.");
bool cont = true;
while (cont)
{
Thread.Sleep(1);
if (ConsoleKey.Q == Console.ReadKey().Key)
{
workerObject.RequestStop();
Console.WriteLine("\nStopping reader on next trace event received...");
cont = false;
}
}
//wait for the worker to exit
workerThread.Join();
Console.WriteLine($"File is stored at: {logFile}");
}
}
}