Debugging tools

Tagged debugging, dstat, ngrep, perf, strace, tcpdump, wireshark, netcat, netstat, dtrace, dtruss  Languages bash

IO and system calls

  • dstat

Monitor network and disk IO:

dstat -t
  • dtrace / dtruss (OSX)

To get the list of available system calls use:

sudo dtrace -ln 'syscall:::entry'

Find which files a program is opening (same as strace -f -p $PID -e open):

sudo dtruss -t open_nocancel -p $PID

Also see ls /usr/bin/.d*

  • strace (Linux)

Monitor system calls made by an app:

strace ruby app.rb

Writes all system calls made by SSH, and subprocesses (-f), to a file named ssh.txt:

strace -f -o ssh.txt ssh jebus.com

Spy on all ‘open’ system calls made by a process:

strace -f -p $PID -e open

Use these commands to see a list of all available system calls (Linux only):

man syscalls
  • opensnoop

Monitor what files are being opened:

opensnoop -p $PID
strace -e open -p $PID

Networking

  • netcat

Pipe/copy data over a network:

cat request.txt | nc metafilter.com 80
  • netstat

Find which programs are listening to which port:

sudo netstat -tunapl
lsof -i -P # OSX
  • ngrep

Listen to traffic containing the string “localhost” on any network interface:

sudo ngrep -d any localhost
  • tcpdump

Listen to traffic containing the string “localhost” on any network interface:

sudo tcpdump port 80 -w http.pcap

Writes a pcap file that can be analyzed with Wireshark.

  • Wireshark

Analyze pcap files from ngrep, tcpdump, etc:

wireshark http.pcap

CPU (Linux)

  • perf

Run perf, a sampling profiler, to see where your application is spending its time:

sudo perf record ruby app.rb

Find out what the program using the most CPU time is doing:

sudo perf top

Find out if an app is using the L1 cache which is ~200 times faster than RAM:

sudo perf stat -e L1-dcache-load-misses my_golang_app

References

How to make Vim yank to the OSX clipboard

Tagged clipboard, osx, vim, yank  Languages 

Add this to .vimrc:

set clipboard=unnamed

Do NOT use something like this because it doesn’t work perfectly:

function! ClipboardYank()
  call system('pbcopy', @@)
endfunction
function! ClipboardPaste()
  let @@ = system('pbpaste')
endfunction

vnoremap <silent> y y:call ClipboardYank()<cr>
vnoremap <silent> d d:call ClipboardYank()<cr>
nnoremap <silent> p :call ClipboardPaste()<cr>p

How to get rid of Gulp, Grunt, and <your favorite JS build tool>

Tagged babel, browserify, build, grunt, gulp, npm  Languages bash

I would happily pay 50-100€ for a build tool that would help me get rid of Gulp, Grunt, etc, and save me from hours of unproductive fighting with unreliable tools.

The following snippet is not quite a full solution for getting rid of Gulp/Grunt.

Installation

npm install -g node-sass browserify babelify uglify-js

Usage

# Compile JS modules into one file
browserify js/app.js -o dist/js/app.js -t [ babelify --presets [ es2015 ] ]
# Compile CSS/SASS modules into one file
node-sass css/app.scss --output-style compressed --include-path node_modules/bootstrap-sass/assets/stylesheets dist/css/app.css
# Minify JS
uglifyjs --compress --mangle -o dist/js/app.js -- dist/js/app.js

Note:

See How to Use npm as a Build Tool.

Mithril button example with debounce

Tagged debounce, mithril  Languages javascript

Live example: https://jsfiddle.net/ah0pt5r3/

Javascript

// Source: https://davidwalsh.name/javascript-debounce-function
var debounce = function(func, wait, immediate) {
  var timeout;
  return function() {
    var context = this,
      args = arguments;
    var later = function() {
      timeout = null;
      if (!immediate) func.apply(context, args);
    };
    var callNow = immediate && !timeout;
    clearTimeout(timeout);
    timeout = setTimeout(later, wait);
    if (callNow) func.apply(context, args);
  };
};

// Widget model
Widget = function(data) {
  data = data || {}
  this.id = m.prop(data.id)
  this.name = m.prop(data.name)
  this.clicked = m.prop(0)
}

// A button that represents a Widget and that can be clicked.
WidgetButton = function(data) {
  var widget = new Widget(data);
  //
  // Triggered by mount.
  //
  this.controller = function() {
    // This is passed to the view
    return { "one": "two" }
  };
  //
  // Triggered after controller has finished executing.
  //
  this.view = function(ctrl) {
    // ctrl contains { "one": "two" }
    return [
      m("a.btn.btn-default.btn-sm", {
        id: "widget-" + widget.id(),
        onclick: this.onclick
      }, [
        m("span", widget.name() + " " + widget.clicked()),
      ])
    ];
  };
  //
  // Triggered when clicking the widget.
  //
  // Uses debounce timeout of 200 ms with immediate triggering.
  // In other words, only the first click in each 200 ms interval is triggered
  // instead of every click.
  //
  this.onclick = debounce(function(e) {
    widget.clicked(widget.clicked() + 1)
    console.debug("Clicked widget " + widget.id())
  }, 200, true);
}

var buttons = document.getElementsByClassName('widget-button');
for (ix in buttons) {
  var button = buttons[ix];
  m.mount(button, new WidgetButton({
    id: button.getAttribute("data-id"),
    name: button.getAttribute("data-name")
  }));
}

HTML

<div class="widget-button" data-id="1" data-name="One"></div>
<div class="widget-button" data-id="2" data-name="Two"></div>

Go and Postgres Example

Tagged example, golang, polling, postgres  Languages go
package main

import (
    "database/sql"
    _ "github.com/lib/pq"
    "log"
    "time"
)

func pollChanges() {
    var id int
    var name string
    rows, err := db.Query("SELECT id, name FROM people")
    if err != nil {
        log.Fatal(err)
    }
    defer rows.Close()
    for rows.Next() {
        err := rows.Scan(&id, &name)
        if err != nil {
            log.Fatal(err)
        }
        log.Println(id, name)
    }
    err = rows.Err()
    if err != nil {
        log.Fatal(err)
    }
}

var db *sql.DB

func main() {
    var conninfo string = "dbname=people sslmode=disable"
    var err error
    db, err = sql.Open("postgres", conninfo)
    defer db.Close()
    if err != nil {
        log.Fatal(err)
    }
    for {
        time.Sleep(1000 * time.Millisecond)
        log.Println("Polling for changes...")
        pollChanges()
    }
}

Keyword arguments in Ruby +2.1

Tagged argument, keyword, options, ruby  Languages ruby

Before keyword arguments were introduced in Ruby:

def call(options={})
  puts options[:optional_param]
  puts options.fetch(:optional_param_with_default, 'default')
  puts options.fetch(:mandatory_param)
end

After:

def call(mandatory_param:, optional_param: nil, optional_param_with_default: 'default')
  puts optional_param
  puts optional_param_with_default
  puts mandatory_param
end

Multi-tenancy in Ecto and Phoenix

Tagged ecto, elixir, multi-tenancy, postgres, phoenix  Languages bash, elixir

Creating a new tentant

A new tenant requires a namespace, which is a schema in Postgres, and a prefix in Ecto:

$ psql -U postgres database_x
> create schema aktagon; 

Querying data

import Ecto.Query
email = "christian@aktagon.com"
q = from(m in User, where: m.email == ^email)
Repo.all(%{q | prefix: "aktagon"})

Documentation: https://hexdocs.pm/ecto/Ecto.Query.html#module-query-prefix

Inserting data

Repo.insert(
  Ecto.put_meta(
   %User{ email: "christian@aktagon.com" },
   prefix: "aktagon"
  )
)

Migrations

$ mix ecto.migrate --prefix "aktagon"

Notes

  • (KeyError) key :__meta__ not found

I got this error when passing a changeset to Ecto.put_meta instead of a User struct.

How to fix "the response was already sent" error in Elixir

Tagged elixir, phoenix, plug  Languages elixir

If you get an “(Plug.Conn.AlreadySentError) the response was already sent” error:

Server: localhost:4000 (http)
Request: POST /api/v1/xxx
** (exit) an exception was raised:
    ** (Plug.Conn.AlreadySentError) the response was already sent
        (plug) lib/plug/conn.ex:332: Plug.Conn.put_status/2

Verify that you have not defined the action plug more than once:

plug :action

How to send emails with Mailgun and Elixir

Tagged elixir, httpotion, mailgun  Languages elixir

This example shows how to send emails with Mailgun and Elixir:

url = "https://api.mailgun.net/v3/xxx.mailgun.org/messages"
headers = [
  "User-Agent": "My App",
  "Content-Type": "application/x-www-form-urlencoded"
]
params = %{
  "from" => "christian@xxx.mailgun.org",
  "to" => "christian@aktagon.com",
  "subject" => "Hello Christian",
  "text" => "Hello"
}
body = URI.encode_query(params)
auth = { "api", "key-xxx" }
response = HTTPotion.post url, [body: body, headers: headers, basic_auth: auth]
if !HTTPotion.Response.success?(response) do
  throw(response.body)
end
Poison.decode!(response.body)

Replace the API key and mailgun URL with your own API key and URL.

Dependencies