AppBeat Blog

Perfect Monitoring for Your Cloud

Monitoring DNS records for your domain

Want to periodically monitor DNS records for your website? Here are step by step instructions how to accomplish this with AppBeat:

  • click on "Add new periodic monitor" button and select DNS agent type

  • enter domain you want to monitor

  • you can create custom regular expression rules which will be used for DNS response validation

  • optionally you can test your rules to ensure they are returning status "Good"

  • click "Finish" button

Your DNS entries will now be periodically monitored from our agents all around world - you will receive notification if anomaly is detected.

Happy monitoring!

Domain expiry monitoring with Whois

With newest version of AppBeat you can now periodically run Whois for your domain:

You can customize notification rules to receive message when domain is about to expire or set custom regular expression for Whois response:

For example, you can set regular expression to ensure correct name servers, registrant name, domain status, or any other information returned from Whois server.

Please let us know if you have any questions about this feature. Happy monitoring!

How to get notification before SSL certificate expires?

Login to your AppBeat account (or create new one if you don't have it yet).

Click "Add new periodic monitor" and select "SSL Certificate" as shown on screenshot below:

Click "Next" button and enter your URL:

Click "Next" and close wizard with "Finish".

Your certificate will now be periodically monitored and when it is about to expire (30 days or less - you can change this in check settings), you will automatically receive notification (we support email, SMS, Slack, web hooks, ...).

Simple as that!

Want less monitoring alarms? Introducing quiet hours!

In newest AppBeat version 1.7.0 you can now define quiet hours for your users, services and/or third-party integrations (I will refer to these as "resources").

Quiet hours are recurring time periods during which alerts (outgoing notifications) are muted for selected resource(s). Quiet hours does not affect monitoring, just notifications. This means that you will always be able to check log entries, even during effective quiet hours.

You can access this new feature from "Alerting" module and by clicking "Quiet hours" tab as shown below:

When you click "Add quiet hours for" button for specific resource, you will be presented with dialog similar to this:

You can add multiple quiet hours for same resource, AppBeat engine will always aggregate those entries while determining if quiet hour is effective or not.

Here are some use case examples:

  • you have service which is not operational 24/7 - now you can simply set quiet hours when service is not active so you don't receive any alerts
  • you have recurring (nightly) updates and you want to mute alerts during this period
  • you don't want to receive alerts for less important service(s) during weekend
  • your team member goes on vacation or sick leave and you don't want to bother him/her with outage alerts
  • some of your team members receive alerts only during working hours (and you have dedicated team for 24/7 operations)
  • etc.

Happy monitoring!

Receive monitoring alerts to your Workplace by Facebook

Today we published new application version with native support for Facebook Workplace.

How to enable it? Please login to your Facebook Workplace account with administrative rights.

Click on Dashboard / Integrations and click "Create App" button. Enter "App Name" (it can be AppBeat or something similar) and set minimum App Permissions to: "Read content" (needed to read group id) and "Post to groups" (needed to post alert).

Now go to AppBeat and click "Alerting" from left menu. Select "Third-Party service integration" tab, click "Add new integration" button and select "Workplace by Facebook":

Please enter following fields:

  • arbitrary integration name (seen only in AppBeat)
  • access token (you should get this when you create Workplace App as described above)
  • community id (available from Facebook Workplace Dashboard / Integrations)
  • group (group name which is available in Facebook Workplace; you can also leave default group named "General")

We suggest that you click "Test" button and check for any errors. If everything goes OK, you should see new test post in your Workplace group.

Finally, don't forget to associate your new Facebook Workplace integration with your AppBeat service. You can do this by clicking "Services & Checks" from left menu, double-click on service that you want to link, select "Notification types" tab, enable (check) your new integration and click "Save" button.

Optionally you can repeat this for multiple services.

Hopefully you will find these instructions useful. And as always - happy monitoring!

How to create status page for your app or website using your domain

AppBeat website monitoring allowed you to easily create public status page for a long time. This page is hosted on our domain by using URL in following format:

However some users wanted more:

  • hosting public status page on their own domain
  • use their own CSS styling

We are happy to announce that newest AppBeat allows you all that!

Method 1: creating public status page on your domain by using simple static HTML template and JavaScript

If you navigate to "AppBeat / Public status / Dashboard" you will be able to enable your status page from there and publish on your web server static HTML file, similar to this:

      <title>Your title</title>
      <!--Please copy css style to your web server because we could rename it in future-->
      <link rel="stylesheet" type="text/css" href="" />
      <!--AppBeat status page is rendered into element with id appbeat-status-container-->
      <div id="appbeat-status-container" class="status-layout"></div>

      <!--Load AppBeat status page script for your page and start rendering it-->
      <script src=""></script>
      <!--Tip: your script is also duplicated on which is hosted in different region-->

Every time your visitor navigates to this page it will show him/her latest status of your page.

Method 2: creating public status page on your domain by getting embeddable HTML fragment on your server side

If you don't want to use JavaScript based solution for your status page, you can call following endpoints on your web server to get HTML fragment which can be embedded in your HTTP response:

Both methods can be styled with your own CSS or you can use our default style located at:

Good thing about this solution is also, that you don't have to change DNS settings to get it to work. Simply publish static HTML file on your web server or embed our HTML fragment if you use dynamic pages. And that is it!

If you would like to try this feature, you can register for new free account and please contact us so we can enable your 14-day risk free trial.

Please note, that for limited time we offer you 60% discount on Starter plan.

How to build .NET Microservices

We would like to share with you very interesting NDC Conference session from Sydney which describes pros and cons of a microservices solution and how you can build one using .NET and a number of open source tools like EventStore, RabbitMq and Redis.

Presentation was done by Richard Banks and you can watch it on YouTube:

C# method for very fast and efficient traceroute (network diagnostic tool)

We like C#, .NET and .NET Core!

Last time we played a little bit with traceroute utility and thought, could we write something fast, efficient, and since we love Asynchronous Programming with async and await (C#), something that would include this pattern as well?

Here is what we came up with :)

using System;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.IO;
using System.Net.NetworkInformation;
using System.Text;
using System.Threading.Tasks;

namespace AppBeat.Core.Utility
    public class TraceRoute
        private const string DATA = "AppBeat Monitoring - - AppBeat Monitoring"; //60 Bytes
        private static readonly byte[] _buffer = Encoding.ASCII.GetBytes(DATA);
        private const int MAX_HOPS = 15;
        private const string STR_REQUEST_TIMEOUT = "Request timed out.";
        private const string STR_REQUEST_TIME_NA = "*";
        private const int REQUEST_TIMEOUT = 4000;

        /// <summary>
        /// Runs traceroute and writes result to console.
        /// </summary>
        public static async Task TryTraceRouteAsync(string hostNameOrAddress)

            using (var console = Console.OpenStandardOutput())
            using (var sw = new StreamWriter(console))
                await TryTraceRouteAsync(hostNameOrAddress, sw);

        /// <summary>
        /// Runs traceroute and writes result to provided stream.
        /// </summary>
        public static async Task TryTraceRouteAsync(string hostNameOrAddress, StreamWriter outputStreamWriter)
            if (outputStreamWriter == null)
                throw new ArgumentNullException(nameof(outputStreamWriter));

            await outputStreamWriter.WriteLineAsync($"traceroute to {hostNameOrAddress}, {MAX_HOPS} hops max, {_buffer.Length} byte packets");

            //dispatch parallel tasks for each hop
            var arrTraceRouteTasks = new Task<TraceRouteResult>[MAX_HOPS];
            for (int zeroBasedHop = 0; zeroBasedHop < MAX_HOPS; zeroBasedHop++)
                arrTraceRouteTasks[zeroBasedHop] = TryTraceRouteInternalAsync(hostNameOrAddress, zeroBasedHop);

            //and wait for them to finish
            await Task.WhenAll(arrTraceRouteTasks);

            //now just collect all results and write them to output stream
            for (int hop = 0; hop < MAX_HOPS; hop++)
                var traceTask = arrTraceRouteTasks[hop];
                if (traceTask.Status == TaskStatus.RanToCompletion)
                    var res = traceTask.Result;
                    await outputStreamWriter.WriteLineAsync(res.Message);

                    if (res.IsComplete)
                        //trace complete
                    await outputStreamWriter.WriteLineAsync($"Could not get result for hop #{hop + 1}");

        private static void EnsureCommonArguments(string hostNameOrAddress)
            if (hostNameOrAddress == null)
                throw new ArgumentNullException(nameof(hostNameOrAddress));

            if (string.IsNullOrWhiteSpace(hostNameOrAddress))
                throw new ArgumentException("Hostname or address is required", nameof(hostNameOrAddress));

        public class TraceRouteResult
            public TraceRouteResult(string message, bool isComplete)
                Message = message;
                IsComplete = isComplete;

            public string Message
                get; private set;

            public bool IsComplete
                get;private set;

        public static async Task<TraceRouteResult> TryTraceRouteInternalAsync(string hostNameOrAddress, int zeroBasedHop)
            using (Ping pingSender = new Ping())
                var hop = zeroBasedHop + 1;

                PingOptions pingOptions = new PingOptions();
                Stopwatch stopWatch = new Stopwatch();
                pingOptions.DontFragment = true;
                pingOptions.Ttl = hop;


                PingReply pingReply = await pingSender.SendPingAsync(


                var elapsedMilliseconds = stopWatch.ElapsedMilliseconds;

                string pingReplyAddress;
                string strElapsedMilliseconds;

                if (pingReply.Status == IPStatus.TimedOut)
                    pingReplyAddress = STR_REQUEST_TIMEOUT;
                    strElapsedMilliseconds = STR_REQUEST_TIME_NA;
                    pingReplyAddress = pingReply.Address.ToString();
                    strElapsedMilliseconds = $"{elapsedMilliseconds.ToString(System.Globalization.CultureInfo.InvariantCulture)} ms";

                var traceResults = new StringBuilder();
                traceResults.Append(hop.ToString(System.Globalization.CultureInfo.InvariantCulture).PadRight(4, ' '));
                traceResults.Append(strElapsedMilliseconds.PadRight(10, ' '));

                return new TraceRouteResult(traceResults.ToString(), pingReply.Status == IPStatus.Success);

Method above basically dispatches 15 parallel (asynchronous) tasks and waits for their result. For this reason it is really fast compared to standard implementation, which would do only one step at a time, and wait for each step (15 times in a row).

Hopefully you will find this useful :)

Better website monitoring experience for your team

We deployed our upgraded rule engine. You can now have more descriptive notifications for Warning and Error rules, by combining them together with custom note:

[trigger_rule: my notification message: why so slow???]

[trigger_rule: server X needs restart???]

If conditions for trigger are met, you will automatically receive notification with your note. This may be useful in critical situtations for your team, so they can respond more quickly!

Happy monitoring!