SQL Mail Logs

This morning, a CS Rep was asked by a customer to find out who may have placed an order in our system in March of last year. Whenever an order is placed via our web site, we send a payment confirmation email to the person that made the payment. We do this using SQL Mail. What’s nice about SQL Mail is that when the database sends an email, or is requested to send an email, a row is saved in the system database with relevant information pertaining to the request and/or action.

So if you use SQL Mail to send mail from your web application, and you need to find an old email that has some important information in it, you simply query the System Table

sysmail_mailitems

which resides in the System Database

msdb

like so:

select * from sysmail_mailitems where [conditions]

 

In this case I was able to find the recipient’s email address, which then allowed the customer to determine who had placed the order within their organization.


This entry was posted in Tech and tagged , , , on by .

Show latest blog post to any web page using Javascript

Here is a simple way to show blog content on a web page using some Javascript and the Google AJAX Feed API. To start, you need to include the API and the latest version of jQuery to your page, thusly:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript" src="http://www.google.com/jsapi"> </script>

 

And then you will need to load the Feed API:

<script type="text/javascript">
    google.load("feeds", "1")
</script>

 

Now you will need to create an element to insert the feed contents.

<div id="latest-post" ></div>

 

Now we are ready to show some entries on our page. You will see that I am only showing the latest entry, but you can set the number of entries to list with the

Feed.setNumEntries(int)

method.

<div id="latest-post" ></div>
     <script type="text/javascript">
         var feedUrl				= "http://www.yellowpagesunited.co/feed/";
         var latestpost	= document.getElementById("latest-post");

         $(document).ready(function() {
             var feed = new google.feeds.Feed(feedUrl);
             feed.setNumEntries(1);
             feed.load( function(result) {
                 postData = "";
                 if (!result.error){
                     var posts=result.feed.entries;
                     for (var i = 0; i < posts.length; i++) {
																									var postDesc = posts[i].contentSnippet.replace(posts[i].title,"");
																									postDesc = postDesc.replace('Yellow Pages United Blog', '');
                         postData+="<span class='post-title'>" + posts[i].title + "</span><br/><span class='post-desc'>"+ postDesc +"</span> <a class='post-link' href='" + posts[i].link + "'target=_blank'" + "'>read more</a><br/>";
                     }
                     latestpost.innerHTML = postData;
                 }
                 else {
                     latestpost.innerHTML = "Unable to fetch feed from " + feedUrl;
                 }
             });
         });
     </script>

 

Using the code above, you will see the post title, followed by a short description, and a read more link. It is important to note that

 contentSnippet 

will show the blog post title, blog name, and a short snippet of the post. To keep things simple and styled properly, I used the

 replace() 

method in Javascript to strip out the blog name and post title from the snippet. Here’s my result:

blog-post-1

Manage Disk space usage on Softlayer

In an update to the last post, deleting millions of rows from our page_views table did free up quite a bit of space, but more work needed to be done. I had searched almost every folder I could think of via the command line, but with my limited knowledge of a Debian Linux filesystem, I really couldn’t find much to delete to free up space. This is why I downloaded and installed WinSCP on my WMWare windows server.

I simply opened WinSCP and connected to my server as the root user, and looked for files we no longer needed. It wasn’t long until I found the mother lode, which on our server instance was found here:

/backups/mysql

There was over 200 GB worth of mysql backups in that folder dating all the way back to 2010, when we first migrated over to SoftLayer. After deleting all of that data, our server instance (and I) can breathe a huge sigh of relief.


This entry was posted in Tech and tagged , , , on by .

A lesson in MySQL: Deleting large amounts of data

Last week, a table in one of our applications became full, and our disk space usage on the server was at 100%. Enter disaster mode. I scrambled to remove as much as I could from the server, and to my relief, I was able to get down to about 78% space usage on the box. While this was good, there was still more to be done. In this particular application, page views are recorded and saved to a MySQL DB table every time any page in the application is viewed. The application has been running for several years now, and we have in the past cleared old data, but this is my first crack at it, personally.

My first idea was to just delete the records that were more than 2 years old, and be done with it. Simple enough, right? Not so much. My project manager wanted to keep the old data, an idea with which I agreed. That old data could come in handy some day. So now my plan was to export the entire page_views table to a .sql file and copy it down to my machine, and then delete the old page views from the table. No problem! Hahahahahha oh man was I wrong. I got the data file exported and copied down to my local machine (the page_views table was 26 gigs with around 147,000,000 records in it) at about 3 gigabytes, a process that took upwards of 5 hours. I then removed the .sql file and we were still looking good as far as disk space goes. I was quite happy with that result, and I was ready to delete the old data.

Without any reading or research, I just assumed that running this command (which would effectively delete about 30,000,000 records from the page_views table):

mysql> DELETE FROM page_views WHERE created_at < NOW() - INTERVAL 2 YEAR;

would accomplish my goals in short order and I would be free to go about the rest of my business. I couldn't have been more wrong. I let that query run for over an hour until I realized that something wasn't quite right. I began my quest to learn more about MySQL and how it really works. As I continued to find, the query above would take an absurd amount of time. Here's why: Every single record in the DELETE query is scanned, then marked for deletion, and logged. All of this has to happen before a record is deleted. And to make matters worse, when a record is finally deleted, the table is rescanned again because of the indexes AFTER EVERY RECORD. That is just awful. Now I know.

But my optimistic self decided to let the query run over night, and I naively expected the operation to be completed the next morning. Not even close. A single record had yet to be deleted. :epic face palm: Armed with that knowledge, and with the knowledge that MySQL would be able to roll back the command, I killed the query. The rollback process took less than 24 hours, and this morning I began the process of deleting large amounts of MySQL data the right way:

CREATE TABLE page_views_new LIKE page_views;
LOCK TABLES page_views_new WRITE, page_views READ;
INSERT INTO page_views_new SELECT * FROM page_views WHERE created_at > NOW() - INTERVAL 2 YEAR;
UNLOCK TABLES;
RENAME TABLE page_views TO page_views_old;
RENAME TABLE page_views_new TO page_views;
DROP TABLE page_views_old;

That's pretty much it, though I am still learning the in's and out's of fine tuning large queries in MySQL.

You know what they say, better late than never!


This entry was posted in Tech and tagged , , on by .

Verify Google Search Results with C#

Recently I was approached by one of our CS Reps with a request to see some of our customers that are successfully being placed on page one of Google via a variety of search parameters. To do this, I used our Google Analytics data that is being loaded into our database via their easy to use API. In C# I simply created a reader for the data that I wanted (current customers with the most visits to their pages), and bound the data to a selectable datagrid. Upon selecting a row in the grid, a search form is populated with relavant data. In this case, we are using Company Name, Heading, City, and State. A CS Rep can use any or all of these fields in their query. The CS Rep then submits the search form, and I send the parameters to google, and return a result, thusly:

private void GoogleVerify(string sSearchValues)
{
 Uri url = new Uri("http://www.google.com/search?q="+sSearchValues+"");

 //Create Request Object
 HttpWebRequest objRequest = (HttpWebRequest)HttpWebRequest.Create(url);

 //Get response from requested url
 HttpWebResponse objResponse = (HttpWebResponse)objRequest.GetResponse();

 //Read response in stream reader
 StreamReader reader = new StreamReader(objResponse.GetResponseStream());
 string tmp = reader.ReadToEnd();

 objResponse.Close();

 if(tmp.IndexOf("bizyellow") != -1)
  lblGoogleResult.Text = "<p>This listing appears on page one of Google. <a target="_blank" href="http://www.google.com/search?q="+sSearchValues+"">Verify</a></p>";
 else
  lblGoogleResult.Text = "<p>No results on page one of Google. Please adjust your search.</p>";

 reader.Close();
}

 

Pretty sweet!


This entry was posted in Tech and tagged , , , on by .

Redirect non WWW requests with nginx on EY Cloud

If you only want to serve up the www version of your domain with nginx on Engine Yard Cloud, you will need to add this rewrite to your custom.conf file. As of this posting, here is where ours was:

/etc/nginx/servers/app_name/custom.conf

 

And here is the rewrite:

if ($host != "www.site-name.com") {
    rewrite ^(.*)$ http://www.site-name.com permanent;
  }

 

I hope this helps someone, because it was a pain for me to figure out.

Extract Alt Text from a web page using PHP

I’ve been writing a custom web spider for Surflab the past week or two, and so far things have been very easy, thanks to PHP Simple HTML DOM Parser. I couldn’t figure out how to extract the alt text from an image until this afternoon. It was another one of those ‘It ended up being so simple it was hard’ kind of scenarios. Anyways, let’s get to it.

<?php
include_once('simple_html_dom.php');
$html       = file_get_html('http://www.surflabhq.com');
$alt_text   = $html->find('img[alt]');

if(empty($alt_text)){
 echo "<p class=crawl-results><div class=crawl-col-left>Alt Text:</div><div class=no-data>No Data</div></p>";
}
else{
 echo "<p class=crawl-results><div class=crawl-col-left>Alt Text:</div><div class=crawl-col-right id=alt-text>";
 $numOfItems = count($alt_text);
 $counter = 0;
  foreach($alt_text as $item){
   $counter += 1;
    if ($counter <> $numOfItems){
      echo $item->alt.", ";
     } else {
       echo $item->alt;
     }
    }
    echo "</div></p>";
?>

 

Easy enough.


This entry was posted in Tech and tagged , , , , on by .

The Latest and Greatest

We have finally launched our lastest and greatest product: Surf Lab recently and we couldn’t be happier with the results. Surf Lab is our latest venture into the internet, where we will use our skills to help businesses make more money by promoting their businesses on line the right way. You can get all of that information on the Surf Lab site, but here are the particulars about the build:

Designer: Clay Kromberg
Developer: That’s me!

The site was built using HTML5, CSS, CSS3, jQuery, Javascript, and some PHP here and there. It was one of the funnest builds I’ve had yet, and I can’t wait for another one.

IE7 not respecting image size with Facebox

If you are trying to show an image in a facebox and it appears that the image is breaking outside of the facebox in IE7, well, technically it is. Edit the facebook.css that came with your version of facebox to relieve this issue. Specifically the .content class definition as follows:

#facebox .content {
  display:table;
  width: 370px;
  padding: 10px;
  background: #fff;
  -webkit-border-radius:4px;
  -moz-border-radius:4px;
  border-radius:4px;
}

 

Remove the width declaration and you’re all set.


This entry was posted in Tech and tagged , , on by .

Debug VS 2003 .NET Apps in Windows 7

First off, follow the instructions on this outstanding blog post by Brian Booth. From here you should be able to at least start your project in VS 2003 without debugging. You will, however, get an error if you try to debug the project in VS 2003. That is, unless you right click the VS 2003 icon in Windows 7, and select ‘Run as Administrator’. You must, of course, be an administrator of your machine for this to work.

It only took me two days to get this up and running. Hopefully this post will help you to get up and running in a much shorter time.