diff --git a/api.go b/api.go
index 48c28d26eed08888be47eb56fd2a5e4725928833..a0bd46e0a2f903893f5fd5fa1c1093d842cf143f 100644
--- a/api.go
+++ b/api.go
@@ -27,7 +27,7 @@ func (api ConfigApi) Request(target interface{}, method string, url string, body
 		}
 	}
 
-	targetUri := api.Url+url
+	targetUri := api.Url + url
 	req, err := http.NewRequest(method, targetUri, bytes.NewBuffer(encodedBody))
 	if err != nil {
 		return MetaResponse{}, err
@@ -56,7 +56,7 @@ func (api ConfigApi) Request(target interface{}, method string, url string, body
 	}
 
 	if res.StatusCode != 200 {
-		return MetaResponse{}, errors.New(fmt.Sprintf("API Responded with non-200 status code: %d", res.StatusCode))
+		return MetaResponse{}, errors.New(fmt.Sprintf("API Responded with status code %d: %s %s", res.StatusCode, res.Request.Method, res.Request.URL))
 	}
 
 	if target != nil {
diff --git a/api_metric_points.go b/api_metric_points.go
index b25b85e97eeafd34fc699fe0aacd94aa4d192664..6b931ae0de4f4395b0e09ed87c78b652fcdd9cd0 100644
--- a/api_metric_points.go
+++ b/api_metric_points.go
@@ -28,11 +28,11 @@ func (api ConfigApi) MetricPoints(metricId int) ApiMetricPointRepo {
 	}
 }
 
-func (repo ApiMetricPointRepo) List(id int) (points []ApiMetricPoint, err error) {
+func (repo ApiMetricPointRepo) List() (points []ApiMetricPoint, err error) {
 	_, err = repo.Request(
 		&points,
 		"GET",
-		fmt.Sprintf("/metrics/%d/points/%d", repo.MetricId, id),
+		fmt.Sprintf("/metrics/%d/points", repo.MetricId),
 		nil,
 	)
 	return
diff --git a/config.go b/config.go
index cfb18f6f788dc7c8598a17e51318846c9b6729b0..160004516d84bea3871d0df6a2f37d29cb6e3eb6 100644
--- a/config.go
+++ b/config.go
@@ -38,4 +38,17 @@ type ConfigComponent struct {
 			Body       string `yaml:"body,omitempty"`
 		} `yaml:"expected,omitempty"`
 	} `yaml:"http,omitempty"`
+	Quassel struct {
+		Hostname string `yaml:"hostname,omitempty"`
+		Port     int    `yaml:"port,omitempty"`
+		Insecure bool   `yaml:"insecure,omitempty"`
+	} `yaml:"quassel,omitempty"`
+	Postgres struct {
+		Hostname string `yaml:"hostname,omitempty"`
+		Port     int    `yaml:"port,omitempty"`
+		Username string `yaml:"username,omitempty"`
+		Password string `yaml:"password,omitempty"`
+		Database string `yaml:"database,omitempty"`
+		Insecure bool   `yaml:"insecure,omitempty"`
+	} `yaml:"postgres,omitempty"`
 }
diff --git a/go.mod b/go.mod
index e123a5ba71de8025977a8840c2f8979c8f246930..c422871d895bd3e6c9e9289f8b2aaa478d91c7de 100644
--- a/go.mod
+++ b/go.mod
@@ -3,6 +3,7 @@ module git.kuschku.de/justjanne/cachet-monitor
 go 1.12
 
 require (
+	github.com/lib/pq v1.0.0
 	github.com/sirupsen/logrus v1.4.1
 	gopkg.in/yaml.v2 v2.2.2
 )
diff --git a/go.sum b/go.sum
index 3d16688ffed6c88dc68b83f9353f5429ae7f8cdb..b1a643227e50852114bffdd04320f87193a28e4d 100644
--- a/go.sum
+++ b/go.sum
@@ -1,28 +1,14 @@
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/docopt/docopt-go v0.0.0-20160216232012-784ddc588536/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
-github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ=
-github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
-github.com/miekg/dns v1.1.8 h1:1QYRAKU3lN5cRfLCkPU08hwvLJFhvjP6MqNMmQz6ZVI=
-github.com/miekg/dns v1.1.8/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
-github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
-github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A=
+github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k=
 github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
 github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
-golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a h1:Igim7XhdOpBnWPuYJ70XcNpq8q3BCACtVgNfoJxOV7g=
-golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
-golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3 h1:0GoQqolDA55aaLxZyTzK/Y2ePZzZTUrRacwib7cNsYQ=
-golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33 h1:I6FyU15t786LL7oL/hn43zqTuEGr4PN7F4XJ1p4E3Y8=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
-golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e h1:nFYrTHrdrAOpShe27kaFHjsqYSEQ0KWqdWLu3xuZJts=
-golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff --git a/main.go b/main.go
index 1fd38e371ed8da09d3ec52e877a3d210a99c4e17..17f701ef9d7355bc2d3b32a9ce47ac693e38c970 100644
--- a/main.go
+++ b/main.go
@@ -50,8 +50,11 @@ func main() {
 		setDefaultString(&config.Components[index].ThresholdDuration, "5m")
 
 		setDefaultString(&config.Components[index].Http.Method, "GET")
-
 		setDefaultInt(&config.Components[index].Http.Expected.StatusCode, 200)
+
+		setDefaultInt(&config.Components[index].Quassel.Port, 4242)
+
+		setDefaultInt(&config.Components[index].Postgres.Port, 5432)
 	}
 
 	storage := NewStorage()
@@ -61,8 +64,13 @@ func main() {
 	for index, component := range config.Components {
 		logrus.Infof("Starting Monitor #%d: %s", index, component.Name)
 		var monitor Monitor
-		if component.Type == "http" {
+		switch component.Type {
+		case "http":
 			monitor = NewHttpMonitor(component)
+		case "quassel":
+			monitor = NewQuasselMonitor(component)
+		case "postgres":
+			monitor = NewPostgresMonitor(component)
 		}
 		wrapper := NewMonitorWrapper(&config.Api, &storage, monitor)
 		monitors = append(monitors, &wrapper)
diff --git a/monitor.go b/monitor.go
index a9fbe64143ec2f6d1e0843a6ad35e62dbdb1357a..d83da3adb7b8a2488806634f7f54b3ef7f8828e4 100644
--- a/monitor.go
+++ b/monitor.go
@@ -1,8 +1,8 @@
 package main
 
 import (
-	"fmt"
 	"github.com/sirupsen/logrus"
+	"strconv"
 	"sync"
 	"time"
 )
@@ -13,10 +13,6 @@ type Datapoint struct {
 	Latency int
 }
 
-func (d Datapoint) String() string {
-	return fmt.Sprintf("Datapoint{time=%s, up=%t, latency=%d}", d.Time.Format(time.RFC3339), d.Up, d.Latency)
-}
-
 type MonitorWrapper struct {
 	api     *ConfigApi
 	storage *Storage
@@ -79,12 +75,24 @@ func (w *MonitorWrapper) tick() {
 		return
 	}
 
-	status := DetermineStatus(w.config, w.storage.Store(w.config.ComponentId, datapoint, w.thresholdDuration))
-	_, err = w.api.Components().Save(w.config.ComponentId, ApiComponentBody{
-		Status: status,
-	})
-	if err != nil {
-		logrus.Error(err.Error())
+	if w.config.ComponentId != 0 {
+		status := DetermineStatus(w.config, w.storage.Store(w.config.ComponentId, datapoint, w.thresholdDuration))
+		_, err = w.api.Components().Save(w.config.ComponentId, ApiComponentBody{
+			Status: status,
+		})
+		if err != nil {
+			logrus.Error(err.Error())
+		}
+	}
+	if w.config.MetricId != 0 {
+		_, err = w.api.MetricPoints(w.config.MetricId).Create(ApiMetricPointBody{
+			Metric:    w.config.MetricId,
+			Value:     datapoint.Latency,
+			Timestamp: strconv.FormatInt(datapoint.Time.Unix(), 10),
+		})
+		if err != nil {
+			logrus.Error(err.Error())
+		}
 	}
 }
 
diff --git a/monitor_http.go b/monitor_http.go
index 525caf3e8c5c9d4240b18548732ac84538680db3..b09a65ed81f5dbc035c7c87097f3ddd6c28e4f0d 100644
--- a/monitor_http.go
+++ b/monitor_http.go
@@ -47,7 +47,12 @@ func (m *HttpMonitor) Measure() (Datapoint, error) {
 	after := time.Now()
 	latency := int(after.Sub(before).Nanoseconds() / 1000000)
 	if err != nil {
-		return Datapoint{}, err
+		logrus.Infof("Monitor %s: %s", err.Error())
+		return Datapoint{
+			Time:    after,
+			Up:      false,
+			Latency: latency,
+		}, nil
 	}
 
 	defer resp.Body.Close()
diff --git a/monitor_postgres.go b/monitor_postgres.go
new file mode 100644
index 0000000000000000000000000000000000000000..f58c4b78057801bcad3bf99a42572d219bd9c4eb
--- /dev/null
+++ b/monitor_postgres.go
@@ -0,0 +1,58 @@
+package main
+
+import (
+	"database/sql"
+	"fmt"
+	_ "github.com/lib/pq"
+	"github.com/sirupsen/logrus"
+	"time"
+)
+
+type PostgresMonitor struct {
+	config ConfigComponent
+}
+
+func NewPostgresMonitor(config ConfigComponent) *PostgresMonitor {
+	return &PostgresMonitor{
+		config: config,
+	}
+}
+
+func (m *PostgresMonitor) Config() *ConfigComponent {
+	return &m.config
+}
+
+func (m *PostgresMonitor) Measure() (Datapoint, error) {
+	sslMode := "verify-full"
+	if m.config.Postgres.Insecure {
+		sslMode = "allow"
+	}
+	connStr := fmt.Sprintf(
+		"postgres://%s:%s@%s:%d/%s?sslmode=%s",
+		m.config.Postgres.Username,
+		m.config.Postgres.Password,
+		m.config.Postgres.Hostname,
+		m.config.Postgres.Port,
+		m.config.Postgres.Database,
+		sslMode,
+	)
+	before := time.Now()
+	db, err := sql.Open("postgres", connStr)
+	after := time.Now()
+	latency := int(after.Sub(before).Nanoseconds() / 1000000)
+	defer db.Close()
+	if err != nil {
+		logrus.Infof("Monitor %s: %s", err)
+		return Datapoint{
+			Time:    after,
+			Up:      false,
+			Latency: latency,
+		}, nil
+	}
+
+	return Datapoint{
+		Time:    after,
+		Up:      true,
+		Latency: latency,
+	}, nil
+}
diff --git a/monitor_quassel.go b/monitor_quassel.go
new file mode 100644
index 0000000000000000000000000000000000000000..2b528fdce77b7c03d6a06d861574758f6b6a6c00
--- /dev/null
+++ b/monitor_quassel.go
@@ -0,0 +1,51 @@
+package main
+
+import (
+	"git.kuschku.de/justjanne/cachet-monitor/quassel"
+	"github.com/sirupsen/logrus"
+	"time"
+)
+
+type QuasselMonitor struct {
+	config ConfigComponent
+}
+
+func NewQuasselMonitor(config ConfigComponent) *QuasselMonitor {
+	return &QuasselMonitor{
+		config: config,
+	}
+}
+
+func (m *QuasselMonitor) Config() *ConfigComponent {
+	return &m.config
+}
+
+func (m *QuasselMonitor) Measure() (Datapoint, error) {
+	before := time.Now()
+	conn := quassel.Connect(quassel.ConnectOptions{
+		ConnectionOptions: quassel.ConnectionOptions{
+			Address: m.config.Quassel.Hostname,
+			Port:    m.config.Quassel.Port,
+			Timeout: time.Duration(m.config.LatencyThresholds.Down) * time.Millisecond,
+		},
+		Verify: !m.config.Quassel.Insecure,
+	})
+	defer conn.Close()
+	after := time.Now()
+	latency := int(after.Sub(before).Nanoseconds() / 1000000)
+
+	if conn.Error() != nil {
+		logrus.Infof("Monitor %s: %s", conn.Error())
+		return Datapoint{
+			Time:    after,
+			Up:      false,
+			Latency: latency,
+		}, nil
+	}
+
+	return Datapoint{
+		Time:    after,
+		Up:      true,
+		Latency: latency,
+	}, nil
+}
diff --git a/quassel/connection.go b/quassel/connection.go
new file mode 100644
index 0000000000000000000000000000000000000000..f73c4b4f1db0bdd41a7ad936782739088f1a0793
--- /dev/null
+++ b/quassel/connection.go
@@ -0,0 +1,102 @@
+package quassel
+
+import (
+	"bufio"
+	"crypto/tls"
+	"encoding/binary"
+	"fmt"
+	"net"
+	"time"
+)
+
+type Connection struct {
+	hostname     string
+	socket       net.Conn
+	tlsSocket    *tls.Conn
+	readWriter   *bufio.ReadWriter
+	buffer       []byte
+	protocolInfo ProtocolInfo
+	err          error
+}
+
+type ConnectionOptions struct {
+	Address string
+	Port    int
+	Timeout time.Duration
+}
+
+func MakeConnection(options ConnectionOptions) Connection {
+	socket, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", options.Address, options.Port), options.Timeout)
+	if err != nil {
+		panic(err.Error())
+	}
+
+	return Connection{
+		hostname: options.Address,
+		socket:   socket,
+		readWriter: bufio.NewReadWriter(
+			bufio.NewReader(socket),
+			bufio.NewWriter(socket),
+		),
+		buffer: make([]byte, 4),
+	}
+}
+
+func (c *Connection) Write(data uint32) {
+	if c.err == nil {
+		binary.BigEndian.PutUint32(c.buffer, data)
+		_, c.err = c.readWriter.Write(c.buffer)
+	}
+}
+
+func (c *Connection) Read(len int) []byte {
+	buffer := make([]byte, len)
+	if c.err == nil {
+		_, c.err = c.readWriter.Read(buffer)
+	}
+	return buffer
+}
+
+func (c *Connection) Flush() {
+	if c.err == nil {
+		c.err = c.readWriter.Flush()
+	}
+}
+
+func (c *Connection) WithTLS(verify bool) {
+	if c.err == nil {
+		config := &tls.Config{
+			ServerName:         c.hostname,
+			InsecureSkipVerify: !verify,
+		}
+		c.tlsSocket = tls.Client(c.socket, config)
+		c.readWriter = bufio.NewReadWriter(
+			bufio.NewReader(c.tlsSocket),
+			bufio.NewWriter(c.tlsSocket),
+		)
+		c.err = c.tlsSocket.Handshake()
+	}
+}
+
+func (c *Connection) TlsState() *tls.ConnectionState {
+	if c.tlsSocket != nil {
+		state := c.tlsSocket.ConnectionState()
+		return &state
+	} else {
+		return nil
+	}
+}
+
+func (c *Connection) ProtocolInfo() ProtocolInfo {
+	return c.protocolInfo
+}
+
+func (c *Connection) Error() error {
+	return c.err
+}
+
+func (c *Connection) Close() {
+	_ = c.readWriter.Flush()
+	_ = c.tlsSocket.Close()
+	_ = c.socket.Close()
+}
diff --git a/quassel/quassel.go b/quassel/quassel.go
new file mode 100644
index 0000000000000000000000000000000000000000..d6f0f5cf83aa5f6614ca907d0e71988aaacea9f0
--- /dev/null
+++ b/quassel/quassel.go
@@ -0,0 +1,55 @@
+package quassel
+
+import (
+	"encoding/binary"
+)
+
+const ProtocolMagic uint32 = 0x42b33f00
+
+const ProtocolFeatureTls uint8 = 0x01
+const ProtocolFeatureCompression uint8 = 0x02
+
+const ProtocolDatastream uint32 = 0x02
+
+type ProtocolInfo struct {
+	FlagTLS         bool
+	FlagCompression bool
+	Data            uint16
+	Version         uint8
+}
+
+func parseProtocolInfo(data []byte) ProtocolInfo {
+	rawFeatures := data[0]
+	rawData := data[1:3]
+	rawVersion := data[3]
+
+	return ProtocolInfo{
+		rawFeatures&ProtocolFeatureTls != 0,
+		rawFeatures&ProtocolFeatureCompression != 0,
+		binary.BigEndian.Uint16(rawData),
+		rawVersion,
+	}
+}
+
+type ConnectOptions struct {
+	ConnectionOptions
+	Verify bool
+}
+
+func Connect(options ConnectOptions) Connection {
+	conn := MakeConnection(options.ConnectionOptions)
+	conn.Write(ProtocolMagic | uint32(ProtocolFeatureTls))
+	supportedProtocols := []uint32{
+		ProtocolDatastream,
+	}
+	for _, protocol := range supportedProtocols {
+		conn.Write(protocol)
+	}
+	conn.Write(1 << 31)
+	conn.Flush()
+	conn.protocolInfo = parseProtocolInfo(conn.Read(4))
+	if conn.protocolInfo.FlagTLS {
+		conn.WithTLS(options.Verify)
+	}
+	return conn
+}