Author: mattchung

  • Teaching as a form of learning: Binary Search Trees (BST)

    Last week, an e-mail was sent out to an internal mailing list [1], looking for volunteers to lecture on data structures & algorithms topics, but nobody replied. I jumped at the opportunity. I volunteered to lecture on binary search trees, without any previous knowledge on the topic. Why in the world would I volunteer to teach something that I know nothing about ? Well, one of the best ways to learn something is attempt to teach it. I love teaching as much as I love learning; teaching forces you to deeply understand the subject, internalize the material, and requires distilling the concepts into digestible bits and pieces. Here’s Ken Thompson’s advice [2].

    But I love teaching: the hard work of the first class, the fun of the second class. Then the misery of the third.

    —Ken Thompson

    In the post, I’m covering what a binary search tree is, its structure, and the basic operations: find, insert, and delete. We also cover the three methods for traversing the tree. At the end of this post are practice problems to help drive the concepts home.

    Next is an example problem that glues the concepts together.

    Example: Badging in & out of the office

    Picture an office requiring employees to badge in and out as they enter and exit the premise. We want to keep track of the employees in the building. We also want to be check if a specific employee is currently in the building. Let’s implement a binary search tree to maintain this dataset.

    As employees badge in, we insert the Employee object (using the employee ID as the key) into the three. When employees badge out, we remove them from the tree. Occassionally, we search the database asking “Is Employee X currently in this building?”

    Tree structure and performance

    What do binary search trees offer over other data structures [3] ?

    The binary tree data structure elegantly combines the flexibility and benefits of two existing data structures: linked lists and arrays. Linked lists efficiently add and delete nodes, by updating pointers, but inefficiently search. Linked lists require iterating over every node (i.e “from the head of the list”) until the desired node is found. Arrays, on the other hand, are perfect for searching – when taking advantage of the index – but are unsuitable for insertions/deletions. When inserting at a[i], all indexes greater than i must be shifted up; when an item is deleted at a[i], all indexes greater than i must be shifted down.

    This table compares the average runtime complexity of the three data structures.

    Data Structure Search Insert Delete
    Arrays O(1) O(N) O(N)
    Linked Lists O(N) O(1) O(1)
    BSTs O(logn) O(logn) O(logn)

    Binary search trees are suitable for specific problems. Binary search trees can be used to solve problems such as runway reservations [3]. Before we dive into the structure and implement the methods, let’s cover some terminology.

    Tree Terminology

    Here’s a visual representation of a binary search tree.

        15
       /  \
      7    21
     / \
    5  10
    

    A tree consists of nodes that are connected by edges. Those lines above represent the edges.

    • Path – Walking node to node, along the edges, creates a sequence known as the path.
    • Root – The node at the very top of the tree. There is only one root in the tree.
    • Parent – Every node, except for the root, has an edge connecting to the node above it.
    • Traversechecking or performing an operation on the node
    • Leaf – a node that contains no children
    • Level – The number of generations from the root node (level 0). For example, the root’s childrens are at level 1.

    Structure & Operations

    The structure of a tree is straight forward. It contains a reference to its root node, which is an instance of the Node class. TheNode class contains two references: leftChild, rightChild. The leftChild references a node whos key (i.e “used for comparing”) is less than the current node’s key, and rightChild references a node with a key greater than the current node’s key. This ordering restriction is a property of BSTs, but not all trees.

    Here’s some sample code of the data structure:

     public class BinaryTree<E> {
         Node root;
    
         private class Node<E> {
             int key;
             E data;
             private Node leftChild;
             private Node rightChild;
    
             @Override
             public String toString(){
                 String myString = "<Node [" + this.key + "]>";
                 return myString;
             }
         }
    }
    

    Searching

    Searching for the node is quite easy. Our method, find, accepts a key parameter. We start at the root. If the key we are searcing for is less than the node’s key, continue walking along the edge connecting to the leftChild. If the key is greater than the node’s key, continue walking along the edge connecting to the rightChild. When the key we are searching for is equal to that of the node, return the node.

    public Node<E> find(int key){
        Node<E> currentNode = this.root;
        while(currentNode !=null){
            if (currentNode.key == key){
                return currentNode;
            }
    
            if (key < currentNode.key){
                currentNode = currentNode.leftChild;
            } else {
                currentNode = currentNode.rightChild;
            }
        }
    
        return currentNode;
    }
    

    Inserting

    Inserting a node is a little more involved, but not by much. We apply an algorithm similar to find but we check our base condition is when the leftChild or rightChild is null.

    public void insert(int key, E data){
        Node<E> newNode = new Node<E>();
        newNode.key = key;
        newNode.data = data;
        if(root == null){
            root = newNode;
            return;
        }else{
            Node<E> currentNode = root;
            Node<E> parent;
            while(true){
                parent = currentNode;
                if(key < currentNode.key){
                    currentNode = currentNode.leftChild;
                    if (currentNode == null){
                        parent.leftChild = newNode;
                        return;
                    }
                }else{
                    currentNode = currentNode.rightChild;
                    if (currentNode == null){
                        parent.rightChild = newNode;
                        return;
                    }
                }
    
            }
        }
    }
    

    Traversing

    There are three ways to traverse a binary tree:
    • Pre Order
    • In Order
    • Post Order

    The most common of the three is in order. In our example code, we only print the currentNode.

    public void inorder(Node<E> localRoot){
    
        if(localRoot !=null){
            Node<E> currentNode = localRoot;
            inorder(currentNode.leftChild);
            System.out.println(currentNode);
            inorder(currentNode.rightChild);
        }
    
    
    }
    
    public void preorder(Node<E> localRoot){
        if (localRoot != null){
            Node<E> currentNode = localRoot;
            System.out.println(currentNode);
            preorder(currentNode.leftChild);
            preorder(currentNode.rigthChild);
        }
    }
    
    public void postOrder(Node<E> localRoot){
        if (localRoot != null){
            Node<E> currentNode = localRoot;
            postOrder(currentNode.leftChild);
            postOrder(currentNode.rightChild);
            System.out.println(currentNode);
        }
    }
    

    Deleting

    There are three cases we must consider when deleting a node:
    • node with zero children
    • node with single child
    • node with two children

    Let’s consider the first case whend deleting a node with zero children.

     Before               After
    
        15                  15
       /  \                /  \
      7    21             7    21
     / \                   \
    5  10                   10
    

    Delete with zero children

    We maintain a reference to the deleted node’s parent. We “delete” the node by updating the parent’s pointer (leftChild or rightChild) to null. The only edge case we consider is if the deleted node is the root. In thtat case, we just update root to null.

    public boolean delete(int key){
        Node<E> currentNode = root;
        Node<E> parent = currentNode;
        boolean isLeftChild = false;
    
        while (currentNode.key != key){
            parent = currentNode;
            if (key < currentNode.key){
                isLeftChild = true;
                currentNode = currentNode.leftChild;
            } else {
                currentNode = currentNode.rightChild;
            }
            // node not found
            if (currentNode == null){
                return false;
            }
        }
        // Case 1: No children
        if (currentNode.leftChild == null && currentNode.rightChild == null){
            if (currentNode == root){
                root = null;
                return true;
            }
            else if (isLeftChild){
                parent.leftChild = null;
                return true;
            } else {
                parent.rightChild = null;
                return true;
            }
        }
        return false;
    }
    

    Delete node with single child

    We just covered how to update the tree when a node has no children. Deleting a node, with a single child, is more involved, but just a little more. There’s four cases for the deleted node:

    • it’s the leftChild of its parent and has a leftChild
    • it’s the leftChild of its parent and has a rightChild
    • it’s the rightChild of its parent and has a leftChild
    • it’s the rightChild of its parent and has a rightChild

    In the first two diagrams, we are deleting node 7. In the last two, we are deleting node 21.

         Left child with single left child
    
        15                15
       /  \              /  \
      7   21            5   21
     /
    5
    
         Left Child with a single right child
    
        15                15
       /  \              /  \
      7   21            9   21
       \
        9
    
         Right child with single left child
    
        15                15
       /  \              /  \
      7    21           7    18
          /
         18
    
         Right child with single right child
    
        15                15
       /  \              /  \
      7    21           7    25
             \
              25
    
    if (currentNode.leftChild != null && currentNode.rightChild == null){
        if(currentNode == root){
            root = currentNode.leftChild;
        }
        else if(isLeftChild){
            parent.leftChild = currentNode.leftChild;
        } else {
            parent.rightChild = currentNode.leftChild;
        }
    }
    else if(currentNode.rightChild != null && currentNode.leftChild == null){
        if (currentNode == root){
            root = currentNode.rightChild;
        }
        else if(isLeftChild){
            parent.leftChild = currentNode.rightChild;
        }
        else {
            parent.rightChild = currentNode.rightChild;
        }
    }
    
        15                15
       /  \              /  \
      7   21            8   21
     / \               / \
    5   9             5   9
       /
      8
    
        15
       /  \
      7   21
     / \
    5   9
         \
         12
        /  \
       10   14
    

    When deleting a node, we replace the node with its inorder successor. The successor is the minimum node, within the deleted node’s right child subtree. Take a moment and think about that. Why the right subtree, and not the left?

    Would the next largest number ever be to the left of the current node? No. By definition, all nodes to the left are less thanand all node to the right are greater than. Therefore, the smallest number (greater than the current node’s key) will be the minimum node, to the right.

    Once we identify the successor, we update the successor’s parent leftChild pointer with the successor’s rightChild pointer (this may be null). We finalize the connections by updating the successor’s rightChild pointer to the delete node’s rightChild.

    public Node<E> getSuccesor(Node<E> toBeDeleted){
    Node<E> parentSuccessor = toBeDeleted;
    Node<E> successor = toBeDeleted;
    Node<E> currentNode = toBeDeleted.rightChild;
    while(currentNode.leftChild != null){
        parentSuccessor = successor;
        successor = currentNode;
        currentNode = currentNode.leftChild;
    }
    if(toBeDeleted.rightChild != successor){
        parentSuccessor.leftChild = successor.rightChild;
        successor.rightChild = toBeDeleted.rightChild;
    }
    return successor;
    

    Drawbacks

    The binary search tree sounds like the dream, so why use an alternative data structure?

    My manager shared a story of an interview candidate who inserted a sequence of sorted items into a binary search tree. Pause for a moment and visualize the data structure. What do you get?

    A linked list!

    This increases the height of the tree and we lose advantage of the O(logn) performance. Binary Search tree is suited best forrandomized keys, not sorted.

    Example

    public class Employee {
        private int id;
        private String firstname;
        private String lastname;
    
        public Employee (int employeeid, String firstname, String lastname){
            this.id = employeeid;
            this.firstname = firstname;
            this.lastname = lastname;
        }
    
        @Override
        public String toString(){
            // < 05: Joe Schmoe >
            String myString = "< " + this.id + " " + this.firstname + " >";
            return myString;
        }
    
        public static void main(String[] args){
            Employee jboyd = new Employee(15, "jess", "boyd");
            Employee mstreiter = new Employee(7, "myles", "streiter");
            Employee mdavis = new Employee(21, "matt", "davis");
            Employee mmadsen= new Employee(5, "martin", "madsen");
            Employee mchung = new Employee(19, "matt", "chung");
    
            BinaryTree<Employee> employees = new BinaryTree<Employee>();
            employees.insert(jboyd.id, jboyd);
            employees.insert(mstreiter.id, mstreiter);
            employees.insert(mdavis.id, mdavis);
            employees.insert(mmadsen.id, mmadsen);
    
            // Is myles in the building?
            // returns true
            System.out.println(employees.find(mstreiter.id));
    
            // Jess clocks out
            employes.delete(jboyd.id);
    
            // Is Matt in the building?
            // returns false
            System.out.println(employees.find(mchung.id));
    
        }
    }
    

    Exercises

    1. Write a function that verifies that a binary search tree is valid.
        15
       /  \
      7   21
     / \
    5   17
    

    Acknowledgements

    Thanks to Jess Boyd for correcting my initial draft, Matt Davis for pointing out the drawbacks of BSTs, and Martin Madsen for techniques to make the post more comprehensible.

    Footnotes

    [1] In a previous post, I shared how I am teaching myself data structures and algorithms. In the breakroom work, a colleague overheard a group forming to study together – the weekend bravehearts. I was lucky enough to catch the group at the head end. We meet Friday after work, and Saturday mornings. If you live in the greater Seattle area and wanted to join, e-mail me and I’ll bring you along.
    [2] This is a quote pulled from interview, from the book “Coders at work”, with Ken Thompson
    [3] (1, 2) MIT’s lecturer presents a scheduling problem and compare the advantages and disadvatages of previously discussed datastructures (e.g “linked lists”, “arrays”, “heaps”). I recommend watching it:https://www.youtube.com/watch?v=9Jry5-82I68
  • It’s just a phase

    Look through my history, and you’ll find how infrequently I post on Facebook, however, I strongly encourage you to watch this short video clip, especially if you are approaching 30, like me, and plan on having children.

    This video poignantly touches on the issues, revolving around teenage homosexuality and bullying, that our younger generation is battling. I tend to forget, and trivialize, how difficult the teenager years were. I forget how insecure I was. I forget, partially, because the problems I now face have changed, naturally, overtime, but having younger brothers and sisters in this age range serve as an important reminder of the role we play, as adults, to the younger, impressionable, generation.

    I fought back tears watching this video and as a byproduct, I’m now questioning not only my beliefs, but the words I unconsciously elect to say day to day. For example, when referring to someone’s thoughts or actions during their teenage years: “It’s just a phase.” This seemingly innoculous selection of words bear no harm, right? But, what if the very thing they’re going through, whatever it may be, is actually NOT a phase?

    Feelings of shame.

    Through my own struggles, I’ve felt shameful I’ve learned the subtle difference between guilt, which is feeling bad about the things you do, and shame, which is feeling bad about who you are. Shame, if left unaddressed, can lead down a dark, confusing, path.

    “It is no measure of health to be well adjusted to a profoundly sick society.” – Jiddu Krishnamurti

  • Learning a new language

    I studied Spanish in high school for four years and 10 years later, I’m embarrassed that I can’t form a comprehensible or grammatically correct sentence.

    I traveled throughout Europe last Christmas and was impressed by the number of bilinguals. Most people fluently spoke a combination of English, French and German. My second language, Vietnamese, however, is barely conversational.

    My Vietnamese stagnated 15 years ago. In elementary school, I was immersed in an after school program where I learned how to read, write, and speak Vietnamese. The majority of my friends spoke the language too, which was conducive to learning the language. But now, I rarely practice and have forgotten the majority of it.

    I was motivated to improve my Vietnamese after traveling to Vietnam last year. I was disheartened by the inability to communicate with my 9 year old nephew; my weak vocabulary limited the dialoge. My cousins taught me new words but by the end of the trip, I couldn’t remember any of them.

    Learning French

    In order to improve my Vietnamese, I started learning French. I figured that if I could learn a lanuage from stratch, I could use the same principles and apply it to learning Vietnamese.

    I searched online for the best methods to learn a new language. I purposely avoided any articles/books that promised short term success (e.g “Perfect French in 30 days”). After reading reviews on Amazon, I ordered Fluent Forever.

    With the books help, I built my curriculum. It cosists of:
    • Learn the international phonetic alphabet (IPA)
    • Train my ears with minimal pair trainers
    • Daily practice with Anki
    • Learn grammar

    Reflecting back at the last 3 months, I’m proud of my progress. I’ve ritualized learning French into a daily habit. I failed in the past due to inconsistency – it was never a habit.

    First French Translation

    Here’s my first translation from the book “French, A grammar based approach“.

    La salle à manger is petite. Il y a quatre chaises et une table dans la salle à manger. Sur la table est une nappe. Elle est vert. Il y a aussi des assiettes, des couteux, des cuillers et des fourchettes.

    Est-ce qu’il y a une tasse sur la table? Oui, il y ya trois tasses et un verre. Les tasses sont petites.

    Qu’est-ce qu’il y a dans les tasses? Il y ya du café dans les tasses. Qu’est-ce qu’il y a sont les verres? Il y ya du vin. Le café est noir et le lait est blanc. Il y ya aussi de la viande sur une plat, et il y ya légumes sur une plat.

    Qu’est qu’il y ya des fleures? Oui, il y ya des fleures dans un vase. Comment est le vasse? Il est joli; il est vert et brun. De quelle couleur sont les fleures? Il y ya rouge et blanc.

    Change in mindset

    “You will never change your life until you change something you do daily. The secret of your success is found in your daily routine.”

    —John Maxwell

    I’ve reframed my expectations. Instead of expecting fluency – both Vietnamese and French – in a short period, I’m building up my vocabulary and grammar; I’m immersing myself with people, books, and videos.

    I look forward to learning more about the people, new and existing, especially my nephew.

  • A short thank you letter to my body

    I’ve been very sick this past week … coughing phelgm, swallowing pain, and battling headaches. Two nights in a row, an uncontrollable cough prevented me from sleeping.

    This morning, however, I awoke without a sore throat. It goes to show you how much I take you for granted when I’m healthy.

    My elation at regaining my health won’t be short lived. This I promise you.

    Ongoing health problems

    Despite converting to a plant based diet in 2014, we’re struggling with intermittent stomach pains. Sometimes, the excruciating pain paralyzes me into the fetal position for more than two hours. It’s the same sensation that sent us to the emergency room in 2005.

    Doctors can’t isolate the problem. Nutritionists suggest conflicting diets. It’s up to you and I to experiment and create a sustainable diet. I’ll continue to jot down foods that cause problems:
    • hummus (gas)
    • cold drinks (bladder incontinence)
    • honey / maple syrup (bladder incontinence)
    • raw lettuce (severe stomach pain)

    I’m fixing more than our diet. I reintroduced mindful eating. This means deliberately counting 60 chews before swallowing. This should help with digestion.

    All of this is going to take time. So thank you for being patient. Thank you for keeping me going. Thank you body.

  • Python progression path – quiz

    Python progression path – From apprentice to guru is a popular StackOverflow post. To categorize whether a person should take his beginner/intermediate course, one of the commentors posted this question:

    python progression quick

    I can better answer this question after reading Fluent Python. Example 1 and Example 2 deal with immutable and mutable data types – respectively. Let’s address each example individually.

    Example 1

    The id built in method returns the object’s memory address. We’ll use this to inspect the memory address for x and ythroughout the examples.

    x and y point to the same memory address when they are first assigned.

    >>> x = 42
    >>> y = x
    >>> id(x)
    4298172632
    >>> id(y)
    4298172632
    

    Because the value of x is immutable (e.g INT) and cannot be modified, by definition, a new memory address is allocated when x is modified. But, y‘s memory remains unmodified:

    >>> x = x + 1
    >>> id(x)
    4298172608
    >>> id(y)
    4298172632
    >>>
    

    Example 2

    Like Example 1, the memory address starts off the same:

    >>> x = [1,2,3]
    >>> y = x
    >>> id(x)
    4299948256
    >>> id(y)
    4299948256
    

    Now that we are dealing with mutable data types, x can be modified in place and the memory address does not change:

    >>> id(x)
    4299948256
    >>> id(y)
    4299948256
    

    Mutable default arguments

    This quiz seems trivial but it isn’t. Understanding this will prevent a novice mistake of using mutable default arguments.

    >>> def update(x, y=[]):
    ...     y.append(x)
    ...     return y
    ...
    >>> list1 = ['a', 'b', 'c']
    >>> list2 = [1, 2, 3]
    >>> update('d', list1)
    ['a', 'b', 'c', 'd']
    >>> update(4, list2)
    [1, 2, 3, 4]
    >>> list1
    ['a', 'b', 'c', 'd']
    >>> list2
    [1, 2, 3, 4]
    >>> update('a')
    ['a']
    >>> list3 = update('b')
    >>> list3
    ['a', 'b']
    >>> list4 = update('hello')
    >>> list4
    ['a', 'b', 'hello']
  • Relearning how to juggle

    I learned how to juggle 15 years ago. I remember relentlessly practicing in my room late into the night. Within a week, I was comfortably juggling three balls.

    Recently, I stumbled across YouTube video of someone juggling four balls and was very impressed. How much more difficult is juggling four balls than three, I thought to myself.

    So, I watched this YouTube tutorial and his pre-requisites to juggling four balls are:
    • Juggle three balls for 1 minute
    • Juggle two balls in each hand for 30 seconds

    In my mind, juggling two balls felt like a step backwards. So, I dismissed his prerequisites.

    I picked up four tennis balls and after 15 minutes of getting nowhere, I grew increasingly frustrated. My years of juggling three balls did not, in fact, make juggling four balls any easier. According to this video, it takes this much time to be able to juggle. Here’s what should be expected:

    • 3 Balls – Days to Weeks
    • 4 Balls – Weeks to Months
    • 5 Balls – Months to Years

    I decided to stop juggling four balls and go back to the fundamentals: two and three ball exercises. I’m glad I did. After spending the first week “starting over”, here’s my progress:

    early attempt of juggling four balls

    In a way, glad that juggling four balls didn’t come easy. Sometimes, you have to go back a few steps to move forward.

  • Belgium terrorist attack and the media

    Belgian was this morning. I send my thoughts and prayers to those in Belgium, but I’m worried about the media’s knee jerk accusations of Muslim terrorists. At the moment, there’s no concrete evidence. But why is the live feed incessantly hinting at ISIS and Muslims?

    I can’t stay updated without feeling the media is inculcating anti muslim propagnda.

    I question the media’s “experts”. The media ensures that expert testimtony aligns with its agenda. Sky News interviewedAnne Speckhard and she immediately concluded that the incident must be related to Salah Abdelslam. I’m not suggesting that it isn’t, but its too quick to point the finger without facts.

    “It’s probably the group that Salah Abdelslam is part of …. so I think they just accelerated their plans … so they wouldn’t get rounded up”, said Anne Speckhard.

    “So you think this is related to the arrest of Salah Abdelslam on Friday and that perhaps that the planned attacks have been brought forward as a result of that?”

    “Absolutely.”

    “One gunshot afterwards and there was one man speaking Arabic afterwords. And then I heard a boom, an enormous explosion”

    I’m disappointed.

  • AWS Lambda part 2 – packaging and deploying

    I received positive feedback on my AWS Lambda presentation in London. This post discusses how to package and deploy your lambda function.

    I’m sure there are other ways but I wanted something simple. This allows me to maintain separate enviroments (i.e “dev”, “production”).

    Makefile

    I use Make to create a package (i.e “sample-app.zip”). The dependencies are installed into a virtualenv which are appended to the package.

    Create the function

    make build-dev
    make create-dev
    

    Deploy the package

    make build-dev
    make update-dev
    
    PROJECT = sample-python-app
    FUNCTION = $(PROJECT)
    REGION = us-east-1
    .phony: clean
    clean:
    rm -f -r $(FUNCTION)*
    rm -f -r site-packages
    build-dev: clean
    aws s3 cp s3://$(FUNCTION)/settings-dev.yml settings.yml
    zip -r $(FUNCTION)-dev.zip . -x *.git* tests/*
    mkdir -p site-packages
    virtualenv $(FUNCTION)-dev
    . $(FUNCTION)-dev/bin/activate
    pip install -r requirements.txt
    cd site-packages; cp -r $$VIRTUAL_ENV/lib/python2.7/site-packages/ ./
    cd site-packages; zip -g -r ../$(FUNCTION)-dev.zip .
    create-dev:
    aws lambda create-function \
    –handler main.lambda_handler \
    –function-name $(FUNCTION)-dev \
    –region $(REGION) \
    –zip-file fileb://$(FUNCTION)-dev.zip \
    –role arn:aws:iam::XXXX:role/$(FUNCTION)-dev \
    –runtime python2.7 \
    –timeout 120 \
    –memory-size 512 \
    update-dev:
    aws lambda update-function-code \
    –function-name $(FUNCTION)-dev \
    –zip-file fileb://$(FUNCTION)-dev.zip \
    –publish \
    delete-dev:
    aws lambda delete-function –function-name $(FUNCTION)-dev

    Lambda deployment package

    Make sure you include all the dependencies in the package. You need to copy the contents of site-packages, NOT the directory itself. If you copy site-packages itself, lambda will not be able to find the modules.

    The contents will look something similar to:

    main.py
    netstorage/
    netstorage/__init__.py
    requests/
    requests/__init__.py

    Testing locally

    Instead of constantly deploying the function, I wanted to test my changes locally.

    When creating an AWS lambda function, you need to specify the handler gets executes. In the gist above, I specify it with –handler main.lambda_handler. So testing locally is simple as:

    if __name__ == "__main__":
        lambda_handler(None, None)
  • Monitoring background processes with SumoLogic

    This post discusses one way we monitor our background process – which is different than how we monitor our web services. It’s difficult when you can’t send a request/poll the service. I wanted something more than checking if the process is alive. One solution we came up with is is using syslog with a log aggregration service.

    Most log aggregration platforms (i.e “Splunk, Log Entries, Sumologic,”) can send an alert if some string (or regex) is found in the the logs. This is pretty common; what about alerting when logs are NOT found?

    Basic Setup

    Our process is managed by supervisor and it logs to stdout. Supervisor logging plugin sends logs to our centralized syslog collector, which forwards the logs to Sumologic. We then configure alerts based off of search results.

    Configuring the alert

    First, create your search (here’s a cheatsheet). Next, configure it:

    • Library -> Edit Search
    • Scheduled this Search
    • Number of results Equal to = 0

    Screenshot:

    Sumologic scheduled search equal to zero/0That’s it. You can integrate this with your Pager Duty account or just have it send directly to an e-mail address.

  • Getting older

    I was standing outside the car, wiping the dogs’s feet when I overheard a voice.

    “Are you a young lady or a man?”

    Did I hear him right? I continued wiping my dogs’s feet and responded:

    “Well, HER name is Metric. And SHE’S a German Shepherd.” I wanted to make it clear that that we were talking about the dog.

    “NO”, he responded confidently. “I’m asking YOU if you are a BOY or GIRL.”

    I turned to Jessica, my fiancée, who was sitting in the car, laughing uncontrollably. I started laughing too.

    You see, I suddenly realized that the the old man was confused by my long hair and it didn’t help that my back was turned to him.

    I couldn’t get mad at him. He spoke his mind – something I fervently believe in.

    Zero Inhibition

    Old people speak their minds. It’s the same for kids. In Master of None, there’s a scene where two kids enter an ice cream shop and start pointing people out by their skin color:

    “Black. White. Yellow. Black. Black.”

    Can you imagine an adult saying that (only person I can think of is my Viet Grandma).

    I am constantly trying to find the balance of thinking twice before saying something and being assertive. It’s an ongoing battle.