diff --git a/src/config.ts b/src/config.ts
index 756595085475055c2cb06386506bf666c3889efa..7197899ebe8356c556c12b4a8fc7f016b056b742 100644
--- a/src/config.ts
+++ b/src/config.ts
@@ -28,6 +28,7 @@ export class DiscordBridgeConfig {
     public channel: DiscordBridgeConfigChannel = new DiscordBridgeConfigChannel();
     public limits: DiscordBridgeConfigLimits = new DiscordBridgeConfigLimits();
     public ghosts: DiscordBridgeConfigGhosts = new DiscordBridgeConfigGhosts();
+    public metrics: DiscordBridgeConfigMetrics = new DiscordBridgeConfigMetrics();
 
     /**
      * Apply a set of keys and values over the default config.
@@ -92,7 +93,6 @@ class DiscordBridgeConfigBridge {
     public disableEveryoneMention: boolean = false;
     public disableHereMention: boolean = false;
     public disableJoinLeaveNotifications: boolean = false;
-    public enableMetrics: boolean = false;
 }
 
 export class DiscordBridgeConfigDatabase {
@@ -152,3 +152,9 @@ class DiscordBridgeConfigGhosts {
     public nickPattern: string = ":nick";
     public usernamePattern: string = ":username#:tag";
 }
+
+export class DiscordBridgeConfigMetrics {
+    public enable: boolean;
+    public port: number = 9001;
+    public host: string = "127.0.0.1";
+}
diff --git a/src/discordas.ts b/src/discordas.ts
index 375f116e895c9ffb4c2d6f233d2e6c9954a7170c..fe1e5f8e5c80f6b46d87c24b228073c7dc049133 100644
--- a/src/discordas.ts
+++ b/src/discordas.ts
@@ -71,6 +71,7 @@ function generateRegistration(opts, registrationPath)  {
 
 function setupLogging() {
     const logMap = new Map<string, Log>();
+    // tslint:disable-next-line:no-any
     const logFunc = (level: string, module: string, args: any[]) => {
         if (!Array.isArray(args)) {
             args = [args];
@@ -89,9 +90,13 @@ function setupLogging() {
     };
 
     LogService.setLogger({
+        // tslint:disable-next-line:no-any
         debug: (mod: string, args: any[]) => logFunc("silly", mod, args),
+        // tslint:disable-next-line:no-any
         error: (mod: string, args: any[]) => logFunc("error", mod, args),
+        // tslint:disable-next-line:no-any
         info: (mod: string, args: any[]) => logFunc("info", mod, args),
+        // tslint:disable-next-line:no-any
         warn: (mod: string, args: any[]) => logFunc("warn", mod, args),
     });
 }
@@ -153,12 +158,11 @@ async function run() {
                + "The config option userStorePath no longer has any use.");
     }
 
-    if (config.bridge.enableMetrics) {
+    if (config.metrics.enable) {
         log.info("Enabled metrics");
-        MetricPeg.set(new PrometheusBridgeMetrics().init());
+        MetricPeg.set(new PrometheusBridgeMetrics().init(appservice, config.metrics));
     }
 
-
     try {
         await store.init();
     } catch (ex) {
@@ -170,6 +174,7 @@ async function run() {
     const roomhandler = discordbot.RoomHandler;
     const eventProcessor = discordbot.MxEventProcessor;
 
+    // tslint:disable-next-line:no-any
     appservice.on("query.room", async (roomAlias: string, createRoom: (opts: any) => Promise<void>) => {
         try {
             const createRoomOpts = await roomhandler.OnAliasQuery(roomAlias);
@@ -202,4 +207,4 @@ async function run() {
 run().catch((err) => {
     log.error("A fatal error occurred during startup:", err);
     process.exit(1);
-});
\ No newline at end of file
+});
diff --git a/src/metrics.ts b/src/metrics.ts
index 9e228a11f64b1d0f2d38e755615552399f413a0f..d5a7b10a9dedb7d499237385719b5c1c74ced018 100644
--- a/src/metrics.ts
+++ b/src/metrics.ts
@@ -14,30 +14,20 @@ See the License for the specific language governing permissions and
 limitations under the License.
 */
 
-import { Gauge, Counter, Histogram } from "prom-client";
+import { Gauge, Counter, Histogram, default as promClient } from "prom-client";
 import { Log } from "./log";
-import { Appservice } from "matrix-bot-sdk";
+import { Appservice,
+    IMetricContext,
+    METRIC_MATRIX_CLIENT_FAILED_FUNCTION_CALL,
+    METRIC_MATRIX_CLIENT_SUCCESSFUL_FUNCTION_CALL,
+    FunctionCallContext,
+    METRIC_MATRIX_CLIENT_FUNCTION_CALL} from "matrix-bot-sdk";
+import { DiscordBridgeConfigMetrics } from "./config";
+import * as http from "http";
 
-const AgeCounters = PrometheusMetrics.AgeCounters;
 const log = new Log("BridgeMetrics");
 const REQUEST_EXPIRE_TIME_MS = 30000;
 
-interface IAgeCounter {
-    setGauge(gauge: Gauge, morelabels: string[]);
-    bump(age: number);
-}
-
-interface IBridgeGauges {
-    matrixRoomConfigs: number;
-    remoteRoomConfigs: number;
-    matrixGhosts: number;
-    remoteGhosts: number;
-    matrixRoomsByAge: IAgeCounter;
-    remoteRoomsByAge: IAgeCounter;
-    matrixUsersByAge: IAgeCounter;
-    remoteUsersByAge: IAgeCounter;
-}
-
 export interface IBridgeMetrics {
     registerRequest(id: string);
     requestOutcome(id: string, isRemote: boolean, outcome: string);
@@ -67,55 +57,73 @@ export class MetricPeg {
 }
 
 export class PrometheusBridgeMetrics implements IBridgeMetrics {
-    private metrics;
+    private matrixCallCounter: Counter;
     private remoteCallCounter: Counter;
     private storeCallCounter: Counter;
     private presenceGauge: Gauge;
     private remoteRequest: Histogram;
     private matrixRequest: Histogram;
     private requestsInFlight: Map<string, number>;
-    private bridgeGauges: IBridgeGauges = {
-        matrixGhosts: 0,
-        matrixRoomConfigs: 0,
-        matrixRoomsByAge: new AgeCounters(),
-        matrixUsersByAge: new AgeCounters(),
-        remoteGhosts: 0,
-        remoteRoomConfigs: 0,
-        remoteRoomsByAge: new AgeCounters(),
-        remoteUsersByAge: new AgeCounters(),
-    };
-
-    public init(as: Appservice) {
-        this.metrics = new PrometheusMetrics();
-        this.metrics.registerMatrixSdkMetrics();
-        this.metrics.registerBridgeGauges(() => this.bridgeGauges);
-        this.metrics.addAppServicePath(bridge);
-        this.remoteCallCounter = this.metrics.addCounter({
+    private matrixRequestStatus: Map<string, "success"|"failed">;
+    private httpServer: http.Server;
+
+    public init(as: Appservice, config: DiscordBridgeConfigMetrics) {
+        promClient.collectDefaultMetrics({
+            timeout: 15000,
+        });
+        // TODO: Bind this for every user.
+        this.httpServer = http.createServer((req, res) => {
+            if (req.method !== "GET" || req.url !== "/metrics") {
+                // tslint:disable-next-line:no-magic-numbers
+                res.writeHead(404, "Not found");
+                res.end();
+            }
+            // tslint:disable-next-line:no-magic-numbers
+            res.writeHead(200, "OK", {"Content-Type": promClient.register.contentType});
+            res.write(promClient.register.metrics());
+            res.end();
+        });
+        this.matrixCallCounter = new Counter({
+            help: "Count of matrix API calls made",
+            labelNames: ["method", "result"],
+            name: "matrix_api_calls",
+        });
+        promClient.register.registerMetric(this.matrixCallCounter);
+
+        this.remoteCallCounter = new Counter({
             help: "Count of remote API calls made",
-            labels: ["method"],
+            labelNames: ["method"],
             name: "remote_api_calls",
         });
-        this.storeCallCounter = this.metrics.addCounter({
+        promClient.register.registerMetric(this.remoteCallCounter);
+
+        this.storeCallCounter = new Counter({
             help: "Count of store function calls made",
-            labels: ["method", "cached"],
+            labelNames: ["method", "cached"],
             name: "store_calls",
         });
-        this.presenceGauge = this.metrics.addGauge({
-            help: "Count of users in the presence queue",
-            labels: [],
+        promClient.register.registerMetric(this.storeCallCounter);
 
+        this.presenceGauge = new Gauge({
+            help: "Count of users in the presence queue",
             name: "active_presence_users",
         });
-        this.matrixRequest = this.metrics.addTimer({
+        promClient.register.registerMetric(this.presenceGauge);
+
+        this.matrixRequest = new Histogram({
             help: "Histogram of processing durations of received Matrix messages",
-            labels: ["outcome"],
+            labelNames: ["outcome"],
             name: "matrix_request_seconds",
         });
-        this.remoteRequest = this.metrics.addTimer({
+        promClient.register.registerMetric(this.matrixRequest);
+
+        this.remoteRequest = new Histogram({
             help: "Histogram of processing durations of received remote messages",
-            labels: ["outcome"],
+            labelNames: ["outcome"],
             name: "remote_request_seconds",
         });
+        promClient.register.registerMetric(this.remoteRequest);
+
         this.requestsInFlight = new Map();
         setInterval(() => {
             this.requestsInFlight.forEach((time, id) => {
@@ -124,6 +132,17 @@ export class PrometheusBridgeMetrics implements IBridgeMetrics {
                 }
             });
         }, REQUEST_EXPIRE_TIME_MS);
+        this.httpServer.listen(config.port, config.host);
+
+        // Bind bot-sdk metrics
+        as.botClient.metrics.registerListener({
+            onDecrement: this.sdkDecrementMetric.bind(this),
+            onEndMetric: this.sdkEndMetric.bind(this),
+            onIncrement: this.sdkIncrementMetric.bind(this),
+            onReset: this.sdkResetMetric.bind(this),
+            onStartMetric: this.sdkStartMetric.bind(this),
+        });
+
         return this;
     }
 
@@ -152,4 +171,36 @@ export class PrometheusBridgeMetrics implements IBridgeMetrics {
     public storeCall(method: string, cached: boolean) {
         this.storeCallCounter.inc({method, cached: cached ? "yes" : "no"});
     }
+
+    private sdkStartMetric(metricName: string, context: IMetricContext) {
+        // We don't use this yet.
+    }
+
+    private sdkEndMetric(metricName: string, context: FunctionCallContext, timeMs: number) {
+        if (metricName !== METRIC_MATRIX_CLIENT_FUNCTION_CALL) {
+            return; // We don't handle any other type yet.
+        }
+        const successFail = this.matrixRequestStatus.get(context.uniqueId)!;
+        this.matrixRequestStatus.delete(context.uniqueId);
+        this.matrixRequest.observe({
+            method: context.functionName,
+            result: successFail,
+        }, timeMs);
+    }
+
+    private sdkResetMetric(metricName: string, context: IMetricContext) {
+        // We don't use this yet.
+    }
+
+    private sdkIncrementMetric(metricName: string, context: IMetricContext, amount: number) {
+        if (metricName === METRIC_MATRIX_CLIENT_SUCCESSFUL_FUNCTION_CALL) {
+            this.matrixRequestStatus.set(context.uniqueId, "success");
+        } else if (metricName === METRIC_MATRIX_CLIENT_FAILED_FUNCTION_CALL) {
+            this.matrixRequestStatus.set(context.uniqueId, "failed");
+        }
+    }
+
+    private sdkDecrementMetric(metricName: string, context: IMetricContext, amount: number) {
+        // We don't use this yet.
+    }
 }