diff --git a/src/exporter.go b/src/exporter.go
index 6dd422f..146eab4 100644
--- a/src/exporter.go
+++ b/src/exporter.go
@@ -49,6 +49,7 @@ var (
 		"Number of errors found since startup.",
 		[]string{"type"}, nil,
 	)
+	
 	metricServerPing = prometheus.NewDesc(
 		prometheus.BuildFQName(sockNamespace, "", "up"),
 		"Check if the fail2ban server is up",
@@ -59,6 +60,26 @@ var (
 		"Number of defined jails",
 		nil, nil,
 	)
+	metricJailFailedCurrent = prometheus.NewDesc(
+		prometheus.BuildFQName(sockNamespace, "", "jail_failed_current"),
+		"Number of current failures on this jail's filter",
+		[]string{"jail"}, nil,
+	)
+	metricJailFailedTotal = prometheus.NewDesc(
+		prometheus.BuildFQName(sockNamespace, "", "jail_failed_total"),
+		"Number of total failures on this jail's filter",
+		[]string{"jail"}, nil,
+	)
+	metricJailBannedCurrent = prometheus.NewDesc(
+		prometheus.BuildFQName(sockNamespace, "", "jail_banned_current"),
+		"Number of IPs currently banned in this jail",
+		[]string{"jail"}, nil,
+	)
+	metricJailBannedTotal = prometheus.NewDesc(
+		prometheus.BuildFQName(sockNamespace, "", "jail_banned_total"),
+		"Total number of IPs banned by this jail (includes expired bans)",
+		[]string{"jail"}, nil,
+	)
 )
 
 type Exporter struct {
@@ -79,6 +100,10 @@ func (e *Exporter) Describe(ch chan<- *prometheus.Desc) {
 	if e.socket != nil {
 		ch <- metricServerPing
 		ch <- metricJailCount
+		ch <- metricJailFailedCurrent
+		ch <- metricJailFailedTotal
+		ch <- metricJailBannedCurrent
+		ch <- metricJailBannedTotal
 	}
 }
 
@@ -92,7 +117,7 @@ func (e *Exporter) Collect(ch chan<- prometheus.Metric) {
 	}
 	if e.socket != nil {
 		e.collectServerPingMetric(ch)
-		e.collectJailCountMetric(ch)
+		e.collectJailMetrics(ch)
 	}
 }
 
@@ -171,7 +196,7 @@ func (e *Exporter) collectServerPingMetric(ch chan<- prometheus.Metric) {
 	)
 }
 
-func (e *Exporter) collectJailCountMetric(ch chan<- prometheus.Metric) {
+func (e *Exporter) collectJailMetrics(ch chan<- prometheus.Metric) {
 	jails, err := e.socket.GetJails()
 	var count float64 = 0
 	if err == nil {
@@ -180,6 +205,31 @@ func (e *Exporter) collectJailCountMetric(ch chan<- prometheus.Metric) {
 	ch <- prometheus.MustNewConstMetric(
 		metricJailCount, prometheus.GaugeValue, count,
 	)
+
+	for i := range(jails) {
+		e.collectJailStatsMetric(ch, jails[i])
+	}
+}
+
+func (e *Exporter) collectJailStatsMetric(ch chan<- prometheus.Metric, jail string) {
+	stats, err := e.socket.GetJailStats(jail)
+	if err != nil {
+		log.Printf("failed to get stats for jail %s: %v", jail, err)
+		return
+	}
+
+	ch <- prometheus.MustNewConstMetric(
+		metricJailFailedCurrent, prometheus.GaugeValue, float64(stats.FailedCurrent), jail,
+	)
+	ch <- prometheus.MustNewConstMetric(
+		metricJailFailedTotal, prometheus.GaugeValue, float64(stats.FailedTotal), jail,
+	)
+	ch <- prometheus.MustNewConstMetric(
+		metricJailBannedCurrent, prometheus.GaugeValue, float64(stats.BannedCurrent), jail,
+	)
+	ch <- prometheus.MustNewConstMetric(
+		metricJailBannedTotal, prometheus.GaugeValue, float64(stats.BannedTotal), jail,
+	)
 }
 
 func printAppVersion() {
diff --git a/src/socket/fail2banSocket.go b/src/socket/fail2banSocket.go
index 48e2ad6..61d273d 100644
--- a/src/socket/fail2banSocket.go
+++ b/src/socket/fail2banSocket.go
@@ -14,6 +14,13 @@ type Fail2BanSocket struct {
 	encoder *ogórek.Encoder
 }
 
+type JailStats struct {
+	FailedCurrent int
+	FailedTotal   int
+	BannedCurrent int
+	BannedTotal   int
+}
+
 func MustConnectToSocket(path string) *Fail2BanSocket {
 	c, err := net.Dial("unix", path)
 	if err != nil {
@@ -61,6 +68,55 @@ func (s *Fail2BanSocket) GetJails() ([]string, error) {
 	return nil, newBadFormatError(statusCommand, response)
 }
 
+func (s *Fail2BanSocket) GetJailStats(jail string) (JailStats, error) {
+	response, err := s.sendCommand([]string{statusCommand, jail})
+	if err != nil {
+		return JailStats{}, err
+	}
+
+	stats := JailStats{
+		FailedCurrent: -1,
+		FailedTotal: -1,
+		BannedCurrent: -1,
+		BannedTotal: -1,
+	}
+
+	if lvl1, ok := response.(*types.Tuple); ok {
+		if lvl2, ok := lvl1.Get(1).(*types.List); ok {
+			if filter, ok := lvl2.Get(0).(*types.Tuple); ok {
+				if filterLvl1, ok := filter.Get(1).(*types.List); ok {
+					if filterCurrentTuple, ok := filterLvl1.Get(0).(*types.Tuple); ok {
+						if filterCurrent, ok := filterCurrentTuple.Get(1).(int); ok {
+							stats.FailedCurrent = filterCurrent
+						}
+					}
+					if filterTotalTuple, ok := filterLvl1.Get(1).(*types.Tuple); ok {
+						if filterTotal, ok := filterTotalTuple.Get(1).(int); ok {
+							stats.FailedTotal = filterTotal
+						}
+					}
+				}
+			}
+			if actions, ok := lvl2.Get(1).(*types.Tuple); ok {
+				if actionsLvl1, ok := actions.Get(1).(*types.List); ok {
+					if actionsCurrentTuple, ok := actionsLvl1.Get(0).(*types.Tuple); ok {
+						if actionsCurrent, ok := actionsCurrentTuple.Get(1).(int); ok {
+							stats.BannedCurrent = actionsCurrent
+						}
+					}
+					if actionsTotalTuple, ok := actionsLvl1.Get(1).(*types.Tuple); ok {
+						if actionsTotal, ok := actionsTotalTuple.Get(1).(int); ok {
+							stats.BannedTotal = actionsTotal
+						}
+					}
+				}
+			}
+			return stats, nil
+		}
+	}
+	return stats, newBadFormatError(statusCommand, response)
+}
+
 func newBadFormatError(command string, data interface{}) error {
 	return fmt.Errorf("(%s) unexpected response format - cannot parse: %v", command, data)
 }