Here are six essential string functions to extend the functions for strings in javascript. If you are already using a major javascript framework like MooTools or Prototype, you may find many of these redundant with your javascript framework. In our case, we used YUI to develop our Trendics Control Panel and YUI didn’t include these type of string prototype functions (similar functions are available in YAHOO.lang but these are not as convenient to call)…

// Returns the string with all the beginning
// and ending whitespace removed
String.prototype.trim = function() {
  return this.replace(/^\s+/, '').replace(/\s+$/, '');
};

// Returns the left x characters of the string
String.prototype.left = function(count) {
  if (this.length>count) {
    return this.substring(0, count);
  }
  else {
    return this;
  }
}

// Returns the right x characters of the string
String.prototype.right = function(count) {
  if (this.length>count) {
    return this.substring(this.length-count, this.length);
  }
  else {
    return this;
  }
}

// Returns true if the string begins with value
String.prototype.startsWith = function(value) {
  if (this.length<value.length) {
    return false;
  }
  else {
    return this.substring(0, value.length)===value;
  }
}

// Returns true if the string ends with value
String.prototype.endsWith = function(value) {
   if (this.length<value.length) {
    return false;
  }
  else {
    return this.substring(this.length-value.length, this.length)===value;
  }
}

// Returns a shortened version of the string
// suffixed with "..." if characters are truncated
// from the original string
String.prototype.shorten = function(maxLength) {
  if (!this) {
    result = null;
  }
  else if (this.length>maxLength) {
    preferredSize = maxLength-'...'.length;
    if (preferredSize>0) {
      result = this.left(preferredSize) + '...';
    }
    else {
      result = this.left(maxLength);
    }
  }
  else {
    result = this;
  }
  return result;
}

The functions above can be invoked on any javascript string like this…

alert(" Hello ".trim());

var message = "This is a longer sentence.";
alert(message.shorten(10));

Hope this helps.

Comments 4 Comments »

We’ve launched status badges that allow you to display the status of any alert rule on your own website. So, you might create this display on your own website…

Server HTTP POP3 FTP
Jupiter
Saturn
Venus

To embed the alert rule statuses in your pages, you can get the Status Badge HTML simply by…

  1. Logging in at https://cp.trendics.com
  2. Clicking Devices in the top navigation bar
  3. Clicking on Manage Status Badge
  4. Copying the displayed Badge HTML

You can also customize the images used for the status on the same Manage Status Badge form. Enjoy!

Comments No Comments »

I recently spent 3 hours pulling my hair out trying to fix a MySQL stored procedure that wasn’t working as expected. I’ve boiled the ultimate problem down to a simple example below. Can you spot the problem?

# First, let's create some sample data
CREATE TABLE TrendicsTest (
DateTime DATETIME NOT NULL,
Value INT NOT NULL,
UNIQUE KEY DateTime (DateTime)
);
INSERT INTO TrendicsTest VALUES ('2008-01-01 01:00', 1);
INSERT INTO TrendicsTest VALUES ('2008-01-01 02:00', 2);

# Next, lets' define a stored procedure to query the sample data
DELIMITER |
DROP PROCEDURE IF EXISTS summarizeTrendicsTest|
CREATE PROCEDURE summarizeTrendicsTest(dateTime DATETIME)
BEGIN
SELECT @endDateTime := DATE_ADD(dateTime, INTERVAL 1 HOUR);
SELECT * FROM TrendicsTest WHERE DateTime=@endDateTime;
END;
|
DELIMITER ;

# Now, let's call the stored procedure and expect
# to get back the first row of data
call summarizeTrendicsTest('2008-01-01 00:00');

What the hell? The first SELECT that sets @endDateTime variable echoes a result but the main SELECT returns an empty set. Just to check our query, let's make sure the query runs ok...

# Add one hour to the time just like the stored procedure
SELECT * FROM TrendicsTest WHERE DateTime='2008-01-01 01:00';

Yes, running the query returns data so why doesn't the stored procedure return any data that appears to be running the same SELECT? Evidently, using "dateTime" for the stored procedure param and using "DateTime" for the field in the WHERE clause confuses MySQL. The stored procedure can be fixed by renaming the param name to something else...

DELIMITER |
DROP PROCEDURE IF EXISTS summarizeTrendicsTest|
CREATE PROCEDURE summarizeTrendicsTest(dateTimeXyz DATETIME)
BEGIN
SELECT @endDateTime := DATE_ADD(dateTimeXyz, INTERVAL 1 HOUR);
SELECT * FROM TrendicsTest WHERE DateTime=@endDateTime;
END;
|
DELIMITER ;

# Now, let's call the stored procedure and expect
# to get back the second row of data
call summarizeTrendicsTest('2008-01-01 00:00');

Bah, in a complex stored procedure that is really not so easy to figure out. So, be careful with your choice of stored procedure parameter names — avoid using a parameter name that is the same as a field name in your tables. Seems like the MySQL stored procedure compiler should at least warn you when this happens if not throw an error.

Comments 1 Comment »

We’ve launched a Live Chat Provider Uptime and Latency section and a Shopping Cart Provider Uptime and Latency section at http://tools.trendics.com today.

Both sections have limited data initially but we’ll continue to gather data on major live chat providers and major shopping cart providers to compare their uptimes and latencies over longer and longer periods of time.

In addition, we decided to split out email hosting from web hosting at http://tools.trendics.com.

Let us know if there are other categories of online service providers you would like to see us launch.

Comments No Comments »

Users are more likely to complete your web forms if you provide a simple help system to answer common questions to complete each input. There are a couple of common techniques to provide help for individual form inputs…

  • Help text under the form inputs - often too limited in space and/or clutters the form too much to provide detailed help
  • Clickable help icons next to the form elements - can either show the help when moused over or when clicked but either way require an additional action from the user to see the help

I prefer to show a help tooltip automatically to the right of the input when an input gains the focus. Unlike normal tooltips, the tooltip remains visible as long as the input has the focus allowing the user to refer back to the tooltip as needed while entering the input. Tab through each field in the form below to see this in action…

The tooltips in the form above are implemented using YUI in a Javascript class call YFormTip. Both the formtip-example.html and the yformtip.js are available to download free of course.

None of this is rocket science but it is my $0.02 on providing context sensitive help for web forms.

Comments 2 Comments »

Today, we launched a couple of new features designed to help troubleshoot intermittent connectivity problems…

  • The new Auto Trace Route feature will automatically perform a trace route after a ping test fails.  The trace route output can be reviewed within the Alert History section of the Trendics Control Panel.
  • The new Selectable Monitor Aggregation feature allows choosing within an Alert Rule how all the monitor results are summarized to compare to the alert trigger.  Users can now choose to perform a Median, Average, All, or Any calculation across the monitor results within the Alert Rule.  The Any calculation is the most sensitive triggering alerts when any failure is detected from any monitoring location and the All calculation forces all monitors to report a problem before an alert is triggered.  In most cases the Median calculation is the best compromise as this effectively requires at least 50% of the monitors to detect a problem before an alert is triggered.

In a follow-up post, we’ll discuss how to combine these features to troubleshoot intermittent connectivity problems.

Comments 1 Comment »

Today, we launched DNS and FTP Connection tests.  Within the Devices section of the Trendics Control Panel, you can now choose Add DNS Test or Add FTP Connection Test in the device action menus.

The DNS Test allows specifying a name server to be tested, a query to execute, and an answer to verify the result.  This DNS Test can check if a DNS server is responding and can also confirm that a domain continues to resolve correctly.

The FTP Connection Test allows specifying a host, a port, and receive text to confirm an FTP server is responding properly to connection requests.

Comments No Comments »

You can do a find and replace on files from the Linux shell using the find and sed commands. The first example below shows doing a find and replace only in the current directory while the second example below shows doing a find and replace recursing into subdirectories…

  1. Replace “www.trendics.com” with “tools.trendics.com” in all html files in the current directory…
  2. find . -maxdepth 1 -name "*.html" -type f -exec sed -i 's/www.trendics.com/tools.trendics.com/' {} \;

  3. Replace “www.trendics.com” with “tools.trendics.com” in all text files and all subdirectories…
  4. find . -name "*.txt" -type f -exec sed -i 's/www.trendics.com/tools.trendics.com/' {} \;

Here is how this works…

  • The dot after the find command specifies to start in the current directory
  • The -maxdepth 1 specifies to only include the current directory
  • The -name "*.txt" switch specifies to only find txt files
  • The -type f specifies to only match files
  • The -exec xyz {} \; specifies to execute xyz for each file where xyz is a sed command specifying to substitute “tools.trendics.com” for “www.trendics.com”

Refer to the documentation on the find and sed for additional options.

Before you run this on your important files, I’d recommend backing up your important files and I’d recommend testing your modified find command in a subdirectory with test files to ensure your find command is working as expected.

Comments 11 Comments »

Is someone establishing an excessive number of connections to your Linux server? Here are the commands I like to run to analyze connection usage.

First, let’s just store off the netstat output so we don’t have to retrieve it repeatedly…

echo "Saving current connections..."
netstat -nta > /tmp/netstat.txt

Next, let’s see the number of connections per IP address by extracting the IP address from the netstat output, counting the number of times each IP address was listed in the netstat output, and printing the top 10 (adjust head -10 appropriately if you’d like to see more than the top 10)…

echo "Number of connections per IP..."
cut -b 49-75 /tmp/netstat.txt | grep -o -P "\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b" | sort | uniq -c | sort -n -r -k 1,7 | head -10

If there is an excessive number of connections from a single IP, you may want to take action to block this IP.

Next, let’s see the number of connections in different states by extracting the state from the netstat output, and counting the number of times each state was listed in the netstat output…

echo "States of connections..."
cut -b 77-90 /tmp/netstat.txt | sort | uniq -c

The key reason to run this is to understand if you might be under a syn-flood attack. If you see an excessive number of connections in the SYN_RECV state, you may be under a syn-flood attack. It is normally unusual to see a high percentage of connections in a SYN_RECV state.

Next, let’s see the IP addresses generating connections currently in the SYN_RECV state by grepping the netstat output appropriately, counting the number of times each IP address was listed in the netstat output, and printing the top 10 (adjust head -10 appropriately if you’d like to see more than the top 10)…

echo "Number of SYN_RECV connections per IP..."
fgrep "SYN_RECV" /tmp/netstat.txt | cut -b 49-75 | cut -d ':' -f1 | sort | uniq -c | sort -n -r -k 1,7 | head -10

If the above command does not return any output, you simply do not have any connections in the SYN_RECV state which is good.

With all the above commands, we’ve analyzed the current connections to the server; however, this is not enough as you may not see IP addresses establishing lots of short connections. To analyze the number of new connections established to your server, you can execute this…

echo "Count number of new connection requests over the next 100 packets..."
time tcpdump -ns 200 -c 100 '(dst port http or dst port https) and tcp[13] & 2!=0' | grep -o -P '\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}.\d{1,5}\s\>' | cut -d '.' -f 1-4 | sort | uniq -c | sort -n -r -k 1,7 | head -25

For this command, the -c parameter specified how many packets to analyze. Generally, I like to have this command run for about 30 seconds and I adjust the -c parameter to make it run over 30 seconds (very busy servers will need a much larger -c value and very light servers will need a much smaller -c value).

If the above command doesn’t ever return data, you have the -c parameter too high — basically the command blocks until the number of specified packets is received and your server has not yet received that number of packets.

In addition, the command above is only analyzing http/https connections; however, you can change the dst port http or dst port https to check other types of connections (consult the tcpdump documentation).

Also, it is useful to run all the commands above under normal conditions so you have a baseline to compare against when something abnormal occurs.

Comments 7 Comments »

So, you’ve filled up a directory with so many files that executing a rm -f * tells you Argument list too long. Now what? You can run this to remove the files in a directory too full to use rm -f *

# Don't forget to execute this in the right directory!
cd /the-right-directory

# Let's preview what will get deleted just to be sure
find . -maxdepth 1 -name "*" -type f -exec echo {} \;

# OK, let's do this
find . -maxdepth 1 -name "*" -type f -exec rm -v {} \;

What is this last find doing? The dot after find says to do this in the current directory, the -maxdepth 1 parameter says not to recurse into subdirectories, the -name "*" parameter says to match any file, the -type f parameter says to do this only on files, and the -exec xyz \; says to execute xyz for each file where xyz is a rm -v command with {} being the name of the current file.

Important: This is doing a permanent wildcard delete in a directory. Double check you understand what you are doing before you execute this command.

Comments 4 Comments »