maandag 14 maart 2011

BizTalk monitoring, PART 1: BTS services and configurations

For the monitoring of the BizTalk Server we've programmed a simple application that will send an email if a certain port or orchestration will be disabled... or even worse, when a BizTalk Service is stopped.
The configuration for the app is done in an external XML file.

Below is the code that is used to check the BTS status, the method will return a boolean that indicates if all is running or not.


   1:  /// <summary>
   2:          /// Checks the BizTalk Status for BTS Service, Orchestrations, Send Ports, Receive Locations
   3:          /// And send a mail on not running of any instance
   4:          /// </summary>
   5:          /// <returns>True if all is running</returns>
   6:          public Boolean CheckBTSStatus()
   7:          {
   8:              //Constant Values
   9:              String ErrorMessage = "&nbsp;&nbsp;&nbsp;&nbsp;{0} '{1}' is {2}!<BR>";
  10:              String ErrorServicesHeader = "<FONT color=\"#C11B17\"><strong>CRITICAL ISSUE: BTS SERVICE IS STOPPED</strong></FONT><BR><BR>";
  11:              String ErrorReceiveLocationsHeader = "<BR><strong>WARNING: Receive Location issue(s)</strong><BR><BR>";
  12:              String ErrorSendportsHeader = "<BR><strong>WARNING: Send Port issue(s)</strong><BR><BR>";
  13:              String ErrorOrchestrationsHeader = "<BR><strong>WARNING: Orchestration issue(s)</strong><BR><BR>";
  14:              String MailSubject = "URGENT: BizTalk issue(s) on " + Dns.GetHostName();
  15:   
  16:              // separate ERROR StringBuilders
  17:              StringBuilder services = new StringBuilder();
  18:              StringBuilder sendports = new StringBuilder();
  19:              StringBuilder receiveLocations = new StringBuilder();
  20:              StringBuilder orchestrations = new StringBuilder();
  21:              Boolean allRunning = true;
  22:   
  23:              foreach (String service in BTSService)
  24:              {
  25:                  ServiceController sc = new ServiceController(service);
  26:   
  27:                  if (sc.Status != ServiceControllerStatus.Running && sc.Status != ServiceControllerStatus.StartPending)
  28:                  {
  29:                      services.AppendLine(String.Format(ErrorMessage, "Service", service, sc.Status));
  30:                      allRunning = false;
  31:                  }
  32:              }
  33:              
  34:              String connectionString = "Data Source=" + dBServer + ";Initial Catalog=" + dB + ";";
  35:              if (!String.IsNullOrEmpty(userName) && !String.IsNullOrEmpty(password))
  36:                  connectionString += "User Id=" + userName + ";Password=" + password + ";";
  37:              else
  38:                  connectionString += "Integrated Security=SSPI;";
  39:   
  40:              BtsCatalogExplorer catalog = new BtsCatalogExplorer();
  41:              catalog.ConnectionString = connectionString;
  42:   
  43:              foreach (Application app in catalog.Applications)
  44:              {
  45:                  if (app.Status != Status.Started && app.Status != Status.NotApplicable)
  46:                  {
  47:                      foreach (SendPort send in app.SendPorts)
  48:                      {
  49:                          if (send.Status != PortStatus.Started)
  50:                          {
  51:                              sendports.AppendLine(String.Format(ErrorMessage, "Send Port", send.Name, send.Status == PortStatus.Bound ? "Unenlisted" : send.Status.ToString()));
  52:                              allRunning = false;
  53:                          }
  54:                      }
  55:                      foreach (ReceivePort receive in app.ReceivePorts)
  56:                      {
  57:                          foreach (ReceiveLocation location in receive.ReceiveLocations)
  58:                          {
  59:                              if (!location.Enable)
  60:                              {
  61:                                  receiveLocations.AppendLine(String.Format(ErrorMessage, "Receive Location", location.Name, "Disabled"));
  62:                                  allRunning = false;
  63:                              }
  64:                          }
  65:                      }
  66:                      foreach (BtsOrchestration orch in app.Orchestrations)
  67:                      {
  68:                          if (orch.Status != OrchestrationStatus.Started)
  69:                          {
  70:                              orchestrations.AppendLine(String.Format(ErrorMessage, "Orchestration", orch.FullName, orch.Status));
  71:                              allRunning = false;
  72:                          }
  73:                      }
  74:                  }
  75:              }
  76:              
  77:              if(!allRunning)
  78:              {
  79:                  if(!String.IsNullOrEmpty(services.ToString()))
  80:                      services.Insert(0, ErrorServicesHeader);
  81:                  if (!String.IsNullOrEmpty(sendports.ToString()))
  82:                      sendports.Insert(0, ErrorSendportsHeader);
  83:                  if (!String.IsNullOrEmpty(receiveLocations.ToString()))
  84:                      receiveLocations.Insert(0, ErrorReceiveLocationsHeader);
  85:                  if (!String.IsNullOrEmpty(orchestrations.ToString()))
  86:                      orchestrations.Insert(0, ErrorOrchestrationsHeader);
  87:   
  88:                  String body = services.ToString() + receiveLocations.ToString()
  89:                      + sendports.ToString() + orchestrations.ToString();
  90:   
  91:                  Helper.SendMail(body, MailSubject, sendMailAddress, receiveMailAddress, SMTP);
  92:              }
  93:              return allRunning;
  94:          }


the method to send an email is the following:


   1:  public static void SendMail(String body, String subject, String fromAddress, String toAddress, String SMTPAddress)
   2:          {
   3:              MailMessage msg = new MailMessage(fromAddress, toAddress);
   4:              msg.IsBodyHtml = true;
   5:              msg.Body = body;
   6:              //msg.From = new MailAddress(fromAddress);
   7:              msg.Subject = subject;
   8:   
   9:              System.Net.Mail.SmtpClient smtp = new SmtpClient(SMTPAddress);
  10:              smtp.Send(msg);
  11:              //SmtpMail.SmtpServer = SMTPAddress;
  12:              //SmtpMail.Send(msg);
  13:          }


to read the configuration out of the XML file, we've programmed following in the constructor (all is read to private class variables:


   1:  private string dBServer;
   2:          private string dB;
   3:          private string userName;
   4:          private string password;
   5:   
   6:          private List<string> BTSService;
   7:   
   8:          private string sendMailAddress;
   9:          private string receiveMailAddress;
  10:          private string SMTP;
  11:   
  12:          public Monitor()
  13:          {
  14:              XmlDocument config = new XmlDocument();
  15:              config.Load(System.IO.Directory.GetCurrentDirectory() + "/BTSMonitorConfiguration.xml");
  16:   
  17:              try
  18:              {
  19:                  dBServer = config.SelectSingleNode("CONFIGURATION/DBSETTINGS/Server").InnerText;
  20:                  dB = config.SelectSingleNode("CONFIGURATION/DBSETTINGS/DB").InnerText;
  21:                  userName = config.SelectSingleNode("CONFIGURATION/DBSETTINGS/UserName") == null ?
  22:                      "" : config.SelectSingleNode("CONFIGURATION/DBSETTINGS/UserName").InnerText;
  23:                  password = config.SelectSingleNode("CONFIGURATION/DBSETTINGS/Password") == null ?
  24:                      "" : config.SelectSingleNode("CONFIGURATION/DBSETTINGS/Password").InnerText;
  25:   
  26:                  BTSService = new List<string>();
  27:   
  28:                  foreach(XmlNode service in config.SelectNodes("CONFIGURATION/BTSSETTINGS/BTSSERVICES/BTSServiceName"))
  29:                  {
  30:                      BTSService.Add(service.InnerText);
  31:                  }
  32:   
  33:                  sendMailAddress = config.SelectSingleNode("CONFIGURATION/MAILSETTINGS/From").InnerText;
  34:                  receiveMailAddress = config.SelectSingleNode("CONFIGURATION/MAILSETTINGS/To").InnerText;
  35:                  SMTP = config.SelectSingleNode("CONFIGURATION/MAILSETTINGS/SMTP").InnerText;
  36:              }
  37:              catch (Exception e)
  38:              {
  39:                  StringBuilder error = new StringBuilder();
  40:                  error.AppendLine("not all necessary data to perform the action is provided.");
  41:                  error.AppendLine("Make sure these fields are correctly filled in in the XML File:");
  42:                  error.AppendLine("\tDBServer (server name)");
  43:                  error.AppendLine("\tDB (Database)");
  44:                  error.AppendLine("\tBTSServiceName (BTS Service Name)");
  45:                  error.AppendLine("\tFrom (sending mail address)");
  46:                  error.AppendLine("\tTo (receiveing mail address)");
  47:                  error.AppendLine("\tSMTP (SMTP host address)");
  48:                  throw (new Exception(error.ToString()));
  49:              }
  50:          }


and finally the created XML file:


<?xml version="1.0" encoding="utf-8" ?>
<CONFIGURATION>
  <DBSETTINGS>
    <Server>.</Server>    <!-- Server Name -->
    <DB>BizTalkMgmtDb</DB>    <!-- DataBase Name -->
    <!--<UserName>user</UserName>-->    <!-- optional -->
    <!--<Password>password</Password>-->    <!-- optional -->
  </DBSETTINGS>
  <BTSSETTINGS>
    <BTSSERVICES>
      <BTSServiceName>BizTalk Service BizTalk Group : BizTalkServerApplication</BTSServiceName>      <!-- BTS Service Name -->
      <BTSServiceName>BizTalk Service BizTalk Group : BizTalkServerApplication2</BTSServiceName>
      <!-- BTS Service Name -->
    </BTSSERVICES>
  </BTSSETTINGS>
  <MAILSETTINGS>
    <From>from@company.com</From>
    <To>to@company.com</To>
    <SMTP>smtp.company.com</SMTP>
  </MAILSETTINGS>
</CONFIGURATION>


Hope you enjoyed my post.
In my next blog I'll show you how to monitor the BizTalk Queue to receive an email with the error message of all suspended instances.

5 opmerkingen:

  1. Great post Mitch,

    Ever thought using WMI events to create custom biztalk monitoring tools? Less-poll intensive and works like a charm!

    Bye, Bart

    BeantwoordenVerwijderen
  2. Thanks Bart.

    The code only polls if the BTS application isn't completely started (so if status is partially started or stopped)... so it shouldn't be that poll intensive.

    Problem is that we had a need for this detailed info of the BTS occurences in the mail.
    So we still need to run this code on the occurence of the WMI events.

    But thanks for the tip. I'll run it through with my colleagues to see if it would give us some additional profits.

    BeantwoordenVerwijderen
  3. Hi Mitch,

    I am following your bolg regularly ...
    I am new to Biztalk but i am very much interested about tracking the messages from BTS so
    can you please explain detail where to write this code and how to do it
    Be frankly step by step ... that will be great for me and those are learning biztalk newly

    Thanks,
    kotireddy B

    BeantwoordenVerwijderen
  4. This code is used by a simple console application which is scheduled to run every hour.

    So just create a console application which calls the given methods. Then create a scheduled task with windows that will execute the created application.
    Make sure you fill in the 'Start in' option of the scheduled task, otherwise it won't find the XML configuration.

    The code given here is to monitor the BizTalk configurations, so you'll get an email when a port or orchestration isn't started anymore.
    Don't know if this is what you wanted to achieve?

    Because for monitoring messages you'll need to check out part 2 of this blog.
    Or if it is just Tracking messages in BizTalk you need, there is an option on each port in Biztalk to enable message tracking. If needed I can provide more info on this message tracking option in Biztalk as a new blog post, let me know.

    BeantwoordenVerwijderen
  5. Hi Mitchke,

    Thank you very much such a good explanation and fast response .
    In my project scenario ftp is trying to pick the files every one hour once that ftp server is not reachable the rcv locations going to be disabled in this case i want to use this coding .

    for this i am trying to create windows service.

    Thanks,
    kotireddy B

    BeantwoordenVerwijderen