Slack Driven Development

_images/image_slack.png

Date: 2016-06-15

Since I am always sitting in a slack channel, I wanted to share a tool I use to track exceptions across my cloud and other environments.

This repository is an example for posting: exceptions, tracking environment errors, and sending targeted debugging messages to a Slack channel to help decrease time spent finding + fixing bugs.

I built this because I was tired of tail-ing and grep-ing through logs. Now I just wait for exceptions and errors to be published into a debugging Slack channel so I can quickly view: what environment had the error, the associated message, and the source code line number.

Setup

This repository only works with Python 2.

  1. Install the official Slack Python API

    Note

    Please refer to the official Slack repository for more information

    sudo pip install slackclient
    

Getting Started

  1. Create a Slack channel for debugging messages

    This demo uses a channel with the name: #debugging

  2. Create a named Slack bot if you do not have one already

    This demo uses a bot with the name: bugbot

  3. Record the Slack bot’s API Token

    This demo uses a bot with an API token: xoxb-51351043345-oHKTiT5sXqIAlxwYzQspae54

  4. Invite the Slack bot to your debugging channel

    Type this into the debugging channel and hit enter:

    /invite bugbot
    

    Warning

    If you do not invite the bot into the channel it can be difficult to debug

  5. Edit the configuration for your needs

    The example file slack_driven_development.py uses a configuration dictionary object where you can assign these keys based off your needs:

    Key Name Purpose and Where to find the Value
    BotName Name of the Slack bot that will post messages
    ChannelName Name of the channel where messages are posted
    NotifyUser Name of the Slack user that gets notified for messages
    Token Slack API Token for the bot
    EnvName A logical name for showing which environment had the error
  6. Test the bot works

    The included slack_driven_development.py file will throw an exception that will report the exception into the channel using the bot based off the simple dictionary configuration in the file.

    $ ./slack_driven_development.py
    Testing an Exception that shows up in Slack
    Sending an error message to Slack for Exception(name 'testing_how_this_looks_from_slack' is not defined)
    Done
    $
    
  7. Confirm the debugging message shows up in Slack channel

_images/image_07SlackDrivenDevelopmentExample.png

Screenshots for Getting Started

Here are the screenshots (as of 06-15-2016) for getting this demo integrated with your Slack channel and bot:

1. Create a new Slack App Integration

_images/image_01SlackAddANewIntegration.png

2. Build a new Integration

_images/image_02SlackBuild.png

3. Make a Custom Integration

_images/image_03SlackMakeCustomIntegration.png

4. Create a new Bot

_images/image_04SlackBotCreateNewBot.png

5. Name and Add Bot

_images/image_05SlackNameAndAddBot.png

6. Record the Bot API Token in the Dictionary Configuration

_images/image_06SlackRecordBotAPIToken.png

7. Run the Slack Driven Development Demo

_images/image_07SlackDrivenDevelopmentExample.png

How does this work?

  1. By using a try/catch block we can capture the exception, and pass it into a handler method.

    1
    2
    3
    4
    5
    6
    7
    try:
        print "Testing an Exception that shows up in Slack"
        testing_how_this_looks_from_slack
    except Exception,k:
        print "Sending an error message to Slack for the expected Exception(" + str(k) + ")"
        slack_msg.handle_send_slack_internal_ex(k)
    # end of try/ex
    
  1. Prepare the exception
  1. Inspect the exception

    Python has a great little feature where it can inspect the stacktrace from an exception outside of the calling objects and even files. Once the file with the exception has been found, we can open the file and goto the exact line that caused the exception and build an error report with the source code and the line number.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    def get_exception_error_message(self, ex, exc_type, exc_obj, exc_tb):
    
        path_to_file = str(exc_tb.tb_frame.f_code.co_filename)
        last_line = int(exc_tb.tb_lineno)
        gh_line_number = int(last_line) - 1
        file_name = str(os.path.split(exc_tb.tb_frame.f_code.co_filename)[1])
        path_to_file = str(exc_tb.tb_frame.f_code.co_filename)
        py_file = open(path_to_file).readlines()
        line = ""
        for line_idx,cur_line in enumerate(py_file):
            if line_idx == gh_line_number:
                line = cur_line
    
        if str(exc_obj.message) != "":
            ex_details_msg = str(exc_obj.message)
        else:
            ex_details_msg = str(ex)
    
        send_error_log_to_slack = ""
        if line != "":
            send_error_log_to_slack = " File: *" + str(path_to_file) + "* on Line: *" + str(last_line) + "* Code: \n```" + str(line) + "``` \n"
        else:
            send_error_log_to_slack = "Error on Line Number: " + str(last_line)
    
        return send_error_log_to_slack
    # end of get_exception_error_message
    
  1. Send the message to the Slack channel

    Post the message to the Slack channel and handle any exceptions.

    Note

    If your configuration dictionary object is misconfigured you will likely see an unauthorized error

License

This repository is licensed under the MIT license.

Thanks for reading,

Jay

Want to learn more?