AppBeat Blog

Perfect Monitoring for Your Cloud

Detailed website monitoring logging

On September 8th we deployed AppBeat 1.4.3 which brings you more detailed logging for your web monitors. If error occurs we will save server response (HTTP body with header) and send you unique link where you or your support team can view it. Previously you would receive just HTTP status code.

Detailed logs can now help you to diagnose root cause of problem more quickly. They also allow you to keep historic track of incidents (please see note below about how long we keep your detailed logs).

List of all changes are:

  • improved logging for all web checks created after August 9, 2016 - when check changes state from good to non-good we now save detailed error message with response body and header (if available). Older web checks will be migrated to new model gradually.
    Note: we will keep your detailed server response for limited time, based on your subscription level:
    • Free: 1 day
    • Basic: 7 days
    • Starter: 1 month
    • Standard: 3 months
    • Advanced: 6 months
    • Enterprise: 1 year
  • adding or editing checks: you can now select service by entering service name (especially useful if you have large number of services)
  • downtime calculation returned error if user previously edited check and changed service
  • other minor improvements

Happy monitoring!

 

Statistics & Performance charts, analyse your monitoring logs

We are continuing with our rapid development and last week new version was published (1.4.2).

In this version we introduced new powerful report - Logs & Performance, and published final version of downtime report. Here are some screenshots of new features.

Performance statistics & hourly averaged response time chart for your periodic check:

Filtering monitoring logs:

As you may noticed, we now also allow you to filter logs and calculate downtime reports by "service group". Service groups are optional groups useful especially for larger organizations. It allows you to group any combination of your services into its own group. Those groups can then be used to assign email/SMS contacts for error notifications (contacts can be members of service groups), or they can be used for filtering data in reports.

List of all changes in version 1.4.2:

  • improved "Downtime overview" report (added downtime tooltips to timeline, added aggregated check report in service details). It is now out of beta.
  • new added "Reports / Logs & Performance" module for more powerful log analysis (you can drill down your data to lowest check level)
  • removed removed "Reports / Statistics & Logs" (replaced by new, more powerful reports)
  • update simplified "Live status" tiles & optimizations
  • update other minor improvements

We are already working on some new useful features for next version! Stay tuned...

Service downtime timeline

Yesterday we published new AppBeat version with improved downtime report. We also added service timeline where you can visually track details about downtimes:

List of all changes for version 1.4.1:

  • improved "Downtime overview" report (added more filters and options, added uptime/downtime timeline, more accurate service downtime calculation - if multiple checks on same service fail at same time, we now automatically exclude overlapping intervals)
  • update "Service groups" tab moved to "Services & Checks"
  • removed removed "Uptime" component from "Statistics & Logs" (replaced by more powerful "Downtime overview" report)
    bug fix context menu could not be entirely visible if item was clicked in bottom or right part of browser window
  • bug fix some dialogs did not display vertical scrollbar if there were too many items
  • update other minor improvements

In next version we plan to release final version of downtime report and then we will continue with new "Log and Performance" report, which will be much more improved version of current log report.

Stay tuned!

We simply love LINQ!

It is true! It is so powerful and useful feature that we use it as much as possible.

Here is recent code snippet which uses "Linq magic", resulting in much smaller and more readable code:

Thank you LINQ team!

Advanced website monitoring added in latest release

Yesterday we rolled out new version of AppBeat which brings fully customizable website monitoring (as promised in previous post):

List of all changes:

  • more friendly wizard for creating new checks
  • update web monitor is now fully customizable (you can post data, change protocol version, IP version, send custom headers, ...)
  • update DNS monitor can now accept IPv4 or IPv6 address of DNS server used for querying
  • removed "Automated Web Testing" early preview is now removed from UI because we received enough initial feedback. Thanks to all who participated in this preview!
  • update other minor improvements

If you find any issues or have questions, please let us know!

Happy monitoring!

Fully customizable web monitor

We are currently actively testing advanced web monitor which will allow you to:

  • select HTTP method (GET, POST, PUT, DELETE, HEAD, TRACE)
  • select HTTP protocol version (1.0, 1.1 or newest HTTP 2)
  • select IP version which should be used when sending request to server (IPv4 or IPv6)
  • specify custom headers (you will be able to set custom user agent, ...)
  • define custom payload (for example for JSON POST, ...)

Stay tuned!

How to detect if Azure SQL database is in primary or secondary role?

If you want to have highly available Azure SQL Database it is highly recommended that you configure Active Geo-Replication (this feature is available for all databases in all service tiers).

Active Geo-Replication consists of two (or more) databases in different regions, where one database is primary (read + write operations) and all other databases are secondaries (allowed only read operations). Secondary databases are automatically synced with changes in your primary database.

Failover event can be triggered manually or if disastrous event happens in one of Azure datacenters. In this case your primary database goes into secondary mode and one of your secondaries becomes new primary database. If you are accessing your databases directly by using connection string, you will have to update it to reflect primary / secondary database switch.

Of course, we want to update our connection string automatically and we will show you two C# code snippets how to detect which database is currently primary (in our examples we operate with one primary and one secondary database).

Example 1

Run special query on each database to determine if it is in primary or secondary role:

public static async Task<string> GetPrimaryConnectionString()
{
	bool? isPrimary = await IsPrimaryAsync(YOUR_CONNECTION_STRING_DB1);
	if (isPrimary == true)
	{
		return YOUR_CONNECTION_STRING_DB1;
	}
	
	isPrimary = await IsPrimaryAsync(YOUR_CONNECTION_STRING_DB2);
	if (isPrimary == true)
	{
		return YOUR_CONNECTION_STRING_DB2;
	}
	
	//could not determine which database is primary
	return null;
}

private static async Task<bool?> IsPrimaryAsync(string connectionString)
{
	try
	{
		using (var conn = new SqlConnection(connectionString))
		{
			if (conn.State != System.Data.ConnectionState.Open)
			{
				await conn.OpenAsync();
			}

			using (var cmd = conn.CreateCommand())
			{
				cmd.CommandText = "SELECT role FROM sys.dm_geo_replication_link_status";
				var res = await cmd.ExecuteScalarAsync();
				return Convert.ToInt32(res) == 0;
			}
		}
	}
	catch (Exception ex)
	{
		//handle exception
		return null;
	}
}

Example 2

If you try to update database which is currently in secondary role you will get following SqlException: Failed to update database "YOUR_DB_NAME" because the database is read-only.

You can use this information to update your connection string:

try
{
	//your code
}
catch (SqlException sqlException)
{
	if (IsReadOnlyDatabase(sqlException) == true)
	{
		//current connection string probably points to secondary database (sqlException.Server)
		//update your connection string to your other database
	}
}

private static bool? IsReadOnlyDatabase(SqlException se)
{
	if (se?.Errors == null) return null;

	foreach (SqlError error in se.Errors)
	{
		if (error.Number == 3906)
		{
			return true;
		}
	}

	return false;
}