Posts Tagged by Golang

git bisect run – example

Git bisect is a great tool for finding bugs in a program. But many examples show manual uses of git bisect – here’s an example of automating the process using git bisect run.

tl;dr

Using git bisect run is easy if you’ve make small atomic commits and you have good tests. run makes a large debug easier (compared to manually doing git bisect good and git bisect bad) – you’re less likely to make errors due to boredom. And run means you can use an iterative process – use rebase to split bad commits then just run again.

Example

So I had an elusive bug in a long running process (an snmp poller, calculator and aggregator for a large network). I had a point where the program was good, but I’d added more features since good and now results were bad. The first step was to write a shell script to be called from git bisect run:

% cat bisect.sh
#!/bin/bash
# copy this to ~ before running with `git bisect run ~/bisect.sh`

cp ~/Makefile .
make clean

# make modifies manpage output, so stash after build
if make &> /dev/null ; then
	git stash
	git stash clear
else
	git stash
	git stash clear
	exit 125
fi

sudo cat /var/tmp/empty > /var/log/abc/abc-poller.log
sudo ./abc-poller --tmp --once -d 2 -c 150 || exit 125
echo "=== poller finished"

percent=`godir=/var/tmp/data/abcmon/poll_queue/new ~/checker | \
  tail -1 | awk '{print $5}' | awk -F. '{print $1}'`
echo "=== percent is $percent"
(( percent < 5 ))

Things that make writing the test script easier:

  • first get it working outside of git bisect run – usually means echoing results along the way
  • already having a test suite that produces a quantified pass/fail output, In my case the I had already written the checker program, whose last line of output contained a “percentage failure” figure

Next step was having an abbreviated log of commits to refer to:

% git log --oneline
f00f232 sql.go - better debugging       # bad                                                                                                                                                        
9780d44 dummy .gitignore, so out dir preserved
0de0796 Makefile for nsch1abcs01
a2f6c96 defaults - 20 workers, udp 15
b8ee3d9 GOMAXPROCS()
04f21ba start v0.0.2
dbc6a60 Makefile: Jenkins as default for env vars
557a5e3 more work on stats
ef6a453 remove excessive debugging
ccc4644 remove file buffering - wasn't writing..???
98bf4b1 stats write failing
9a9682d move type queue_t struct
467aeed buffered writes for queue file
148a8cc stats: + device_run, device_ok
c61be42 done chan *Stats_t; calculate_value() bool
0e41461 debugging - print out device_id as %5s
7cbe167 default workers 5000, correct stop/start commands
544e8d7 gather statistics
6990cf2 rename data chan to device_id
5e8562b rename sql -> sqlconn; global var
fd52d89 remove dead code
4d7b9b1 device_for() - err if count != 1
6ceb305 deb: fail if version main.go isn't same changelog
5ce1855 deb: rules producing abc-poller_0.0.1_amd64.deb
db5bff4 deb: cleaned up Makefile, roffs
76674c2 JSON -> SQL; version 0.0.1
4cf198e deb: basic removal of 64 references
d980f26 deb: rename 64 to vanilla
b933570 deb: remove 32 bit stuff
970bd82 current debug level is 2; adjust output
70f8921 Revert "deb build - don't init, cron while testing"
855ce00 default debug is 2; misc tidy
f3d80e1 remove timeoutOpt - no longer used
48ced38 misc tidys before release
a3fe13c runonceOpt, revert cycling code  # good
24cd998 use passed in udpOpt
5ca1830 remove stash/sender.old.go
06b9566 remove gsnmpgo; use gosnmp
bffd430 rules: add note about "too many open files"

Mark bad and good, start the run, go and have a coffee :-)

% git bisect start f00f232 a3fe13c
% git bisect run ~/bisect.sh
# lots of output

I get the result that the ominously named 557a5e3 more work on stats is the first bad commit – I remember it as one of those large “kitchen sink” commits done at the end of the day. So “first rule of fightclub git” remembered – always do small atomic commits.

I have a useful shell function gri() – I used that to interactively rebase and break up 557a5e3 into many small commits:

gri () {
  git rebase -i HEAD~${1:-7}
}

After rebasing git log looked like this – notice the many small commits named “bisect1″ etc:

382b3ee defaults - 20 workers, udp 15
11db314 GOMAXPROCS()
4b547ea start v0.0.2
c92feef Makefile: Jenkins as default for env vars
8fcc595 bisect6: calc/noncalc
ad3a18f bisect5: tweak debug msgs
311bb8d bisect4: mv stats init
957c234 bisect3: remove stats from send_gosnmp()
3c01d62 bisect2: use Add(); Calcs/NonCalcs
947cb27 bisect1: move Stats_t; Add()
ef6a453 remove excessive debugging
ccc4644 remove file buffering - wasn't writing..???
98bf4b1 stats write failing

And here’s the real win of writing bisect.sh – you can just keep rebasing and running until you’ve narrowed down the bad code to a few lines:

=== poller finished
=== percent is 49
947cb27fd57642dc545ee23090d7ae8fd8b14b3f is the first bad commit
commit 947cb27fd57642dc545ee23090d7ae8fd8b14b3f
Author: Sonia Hamilton <sonia@snowfrog.net>
Date:   Thu Mar 14 10:02:42 2013 +1100

    bisect1: move Stats_t; Add()

I do another interactive rebase, fix the logic error, and then HEAD is good.

GoSnmp – SNMP for GoLang

Today I released soniah/gosnmp – an update of alouca/gosnmp.

Many, many thanks to Andreas Louca for writing alouca/gosnmp. The major difference between his version and soniah/gosnmp is that the latter has tests written. (However the code could do with refactoring). The tests were used to find and correct errors in the following SNMP BER Types:

  • Counter32
  • Gauge32
  • Counter64
  • OctetString
  • ObjectIdentifier
  • IpAddress

Also, this version contains functions for treating the returned snmp values as *big.Int (convenient, as SNMP can return int32, uint32, and uint64 values)

 

refactoring in Go – rather pleasant actually…

I’ve just finished refactoring a large Go program, and the process was rather…. pleasant.

Static typing catches all those obscure errors I wouldn’t think about in a scripting language (Python, Perl, Ruby, etc). My process is:

  • type :make in vim (I have a dummy Makefile in my Go project just for vim)
  • vim jumps cursor to error (vim quickfix list)
  • “oh, I shouldn’t do that” – fix (type type type)
  • start again

Finish rather sooner than expected, run tests, smile in knowledge program is working properly.

Update

To quickly setup the make command for Go, type this in a Vim window:

:setlocal makeprg=go\ build\ \.

Or even better configure vim via your ~/.vimrc, for example:

autocmd BufRead *_test.go setlocal makeprg=go\ test\ \.
autocmd BufRead *.go setlocal makeprg=go\ test\ \./..

Thanks Martin for the comment!

gsnmpgo – SNMP for Golang using gsnmp

Update 8/Mar/13

Work on gsnmpgo has halted. Making the gsnmp C library multithreaded was proving too time consuming. Use http://github.com/soniah/gosnmp instead.

Previously…

I recently released gsnmpgo – a Go/CGo snmp library using gsnmp. Pull requests welcome!

From the gsnmpgo documentation, here’s an example of usage:

// do an snmp get; RFC 4088 is used for uris
uri := `snmp://public@192.168.1.10//(1.3.6.1.2.1.1.1.0)`
params := gsnmpgo.NewDefaultParams(uri)
results, err := gsnmpgo.Query(params)
if err != nil {
    fmt.Println(err)
    os.Exit(1)
}

// check your results
gsnmpgo.Dump(results)

// turn on debugging
gsnmpgo.Debug = true

vim – bufexplorer

Bufexplorer – my new favourite add-on for vim.

Why do I like it? It allows you to emulate the buffer list feature of emacs, as well as switch between horizontal/vertical buffer splits and find recently edited files. All this can already be done with vim buffers, but bufexplorer makes it easy.

Why don’t I just use emacs? Because as sysadmin/devop I’m often working on other people’s servers, and I don’t want to go installing buckets of stuff everywhere – vim is usually installed.

I found the best way to use bufexplorer is to open up all possible source files (eg vim src/*.go other/*.go) at the start of an editing session, then just skip between them (shown here with the excellent xMonad window manager, GNU Screen, and Gnome Terminal):

Next Page »