diff --git a/LICENSE b/LICENSE
--- a/LICENSE
+++ b/LICENSE
@@ -1,30 +1,29 @@
-Copyright Bitnomial, Inc. (c) 2016
+BSD 3-Clause License
 
+Copyright (c) 2016-present, Bitnomial, Inc.
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
 
-    * Redistributions of source code must retain the above copyright
-      notice, this list of conditions and the following disclaimer.
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
 
-    * Redistributions in binary form must reproduce the above
-      copyright notice, this list of conditions and the following
-      disclaimer in the documentation and/or other materials provided
-      with the distribution.
+* Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
 
-    * Neither the name of Bitnomial, Inc. nor the names of other
-      contributors may be used to endorse or promote products derived
-      from this software without specific prior written permission.
+* Neither the name of the copyright holder nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
 
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/gen/Proto/Proto/Metrics.hs b/gen/Proto/Proto/Metrics.hs
new file mode 100644
--- /dev/null
+++ b/gen/Proto/Proto/Metrics.hs
@@ -0,0 +1,1195 @@
+{- This file was auto-generated from proto/metrics.proto by the proto-lens-protoc program. -}
+{-# LANGUAGE ScopedTypeVariables, DataKinds, TypeFamilies,
+  UndecidableInstances, MultiParamTypeClasses, FlexibleContexts,
+  FlexibleInstances, PatternSynonyms, MagicHash, NoImplicitPrelude
+  #-}
+{-# OPTIONS_GHC -fno-warn-unused-imports#-}
+module Proto.Proto.Metrics where
+import qualified Data.ProtoLens.Reexport.Prelude as Prelude
+import qualified Data.ProtoLens.Reexport.Data.Int as Data.Int
+import qualified Data.ProtoLens.Reexport.Data.Word as Data.Word
+import qualified Data.ProtoLens.Reexport.Data.ProtoLens
+       as Data.ProtoLens
+import qualified
+       Data.ProtoLens.Reexport.Data.ProtoLens.Message.Enum
+       as Data.ProtoLens.Message.Enum
+import qualified Data.ProtoLens.Reexport.Lens.Family2
+       as Lens.Family2
+import qualified Data.ProtoLens.Reexport.Lens.Family2.Unchecked
+       as Lens.Family2.Unchecked
+import qualified Data.ProtoLens.Reexport.Data.Default.Class
+       as Data.Default.Class
+import qualified Data.ProtoLens.Reexport.Data.Text as Data.Text
+import qualified Data.ProtoLens.Reexport.Data.Map as Data.Map
+import qualified Data.ProtoLens.Reexport.Data.ByteString
+       as Data.ByteString
+import qualified Data.ProtoLens.Reexport.Lens.Labels as Lens.Labels
+
+data Bucket = Bucket{_Bucket'cumulativeCount ::
+                     !(Prelude.Maybe Data.Word.Word64),
+                     _Bucket'upperBound :: !(Prelude.Maybe Prelude.Double)}
+            deriving (Prelude.Show, Prelude.Eq, Prelude.Ord)
+
+instance (a ~ Data.Word.Word64, b ~ Data.Word.Word64,
+          Prelude.Functor f) =>
+         Lens.Labels.HasLens "cumulativeCount" f Bucket Bucket a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Bucket'cumulativeCount
+                 (\ x__ y__ -> x__{_Bucket'cumulativeCount = y__}))
+              (Data.ProtoLens.maybeLens Data.ProtoLens.fieldDefault)
+
+instance (a ~ Prelude.Maybe Data.Word.Word64,
+          b ~ Prelude.Maybe Data.Word.Word64, Prelude.Functor f) =>
+         Lens.Labels.HasLens "maybe'cumulativeCount" f Bucket Bucket a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Bucket'cumulativeCount
+                 (\ x__ y__ -> x__{_Bucket'cumulativeCount = y__}))
+              Prelude.id
+
+instance (a ~ Prelude.Double, b ~ Prelude.Double,
+          Prelude.Functor f) =>
+         Lens.Labels.HasLens "upperBound" f Bucket Bucket a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Bucket'upperBound
+                 (\ x__ y__ -> x__{_Bucket'upperBound = y__}))
+              (Data.ProtoLens.maybeLens Data.ProtoLens.fieldDefault)
+
+instance (a ~ Prelude.Maybe Prelude.Double,
+          b ~ Prelude.Maybe Prelude.Double, Prelude.Functor f) =>
+         Lens.Labels.HasLens "maybe'upperBound" f Bucket Bucket a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Bucket'upperBound
+                 (\ x__ y__ -> x__{_Bucket'upperBound = y__}))
+              Prelude.id
+
+instance Data.Default.Class.Default Bucket where
+        def
+          = Bucket{_Bucket'cumulativeCount = Prelude.Nothing,
+                   _Bucket'upperBound = Prelude.Nothing}
+
+instance Data.ProtoLens.Message Bucket where
+        descriptor
+          = let cumulativeCount__field_descriptor
+                  = Data.ProtoLens.FieldDescriptor "cumulative_count"
+                      (Data.ProtoLens.UInt64Field ::
+                         Data.ProtoLens.FieldTypeDescriptor Data.Word.Word64)
+                      (Data.ProtoLens.OptionalField maybe'cumulativeCount)
+                      :: Data.ProtoLens.FieldDescriptor Bucket
+                upperBound__field_descriptor
+                  = Data.ProtoLens.FieldDescriptor "upper_bound"
+                      (Data.ProtoLens.DoubleField ::
+                         Data.ProtoLens.FieldTypeDescriptor Prelude.Double)
+                      (Data.ProtoLens.OptionalField maybe'upperBound)
+                      :: Data.ProtoLens.FieldDescriptor Bucket
+              in
+              Data.ProtoLens.MessageDescriptor
+                (Data.Text.pack "io.prometheus.client.Bucket")
+                (Data.Map.fromList
+                   [(Data.ProtoLens.Tag 1, cumulativeCount__field_descriptor),
+                    (Data.ProtoLens.Tag 2, upperBound__field_descriptor)])
+                (Data.Map.fromList
+                   [("cumulative_count", cumulativeCount__field_descriptor),
+                    ("upper_bound", upperBound__field_descriptor)])
+
+data Counter = Counter{_Counter'value ::
+                       !(Prelude.Maybe Prelude.Double)}
+             deriving (Prelude.Show, Prelude.Eq, Prelude.Ord)
+
+instance (a ~ Prelude.Double, b ~ Prelude.Double,
+          Prelude.Functor f) =>
+         Lens.Labels.HasLens "value" f Counter Counter a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Counter'value
+                 (\ x__ y__ -> x__{_Counter'value = y__}))
+              (Data.ProtoLens.maybeLens Data.ProtoLens.fieldDefault)
+
+instance (a ~ Prelude.Maybe Prelude.Double,
+          b ~ Prelude.Maybe Prelude.Double, Prelude.Functor f) =>
+         Lens.Labels.HasLens "maybe'value" f Counter Counter a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Counter'value
+                 (\ x__ y__ -> x__{_Counter'value = y__}))
+              Prelude.id
+
+instance Data.Default.Class.Default Counter where
+        def = Counter{_Counter'value = Prelude.Nothing}
+
+instance Data.ProtoLens.Message Counter where
+        descriptor
+          = let value__field_descriptor
+                  = Data.ProtoLens.FieldDescriptor "value"
+                      (Data.ProtoLens.DoubleField ::
+                         Data.ProtoLens.FieldTypeDescriptor Prelude.Double)
+                      (Data.ProtoLens.OptionalField maybe'value)
+                      :: Data.ProtoLens.FieldDescriptor Counter
+              in
+              Data.ProtoLens.MessageDescriptor
+                (Data.Text.pack "io.prometheus.client.Counter")
+                (Data.Map.fromList
+                   [(Data.ProtoLens.Tag 1, value__field_descriptor)])
+                (Data.Map.fromList [("value", value__field_descriptor)])
+
+data Gauge = Gauge{_Gauge'value :: !(Prelude.Maybe Prelude.Double)}
+           deriving (Prelude.Show, Prelude.Eq, Prelude.Ord)
+
+instance (a ~ Prelude.Double, b ~ Prelude.Double,
+          Prelude.Functor f) =>
+         Lens.Labels.HasLens "value" f Gauge Gauge a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Gauge'value
+                 (\ x__ y__ -> x__{_Gauge'value = y__}))
+              (Data.ProtoLens.maybeLens Data.ProtoLens.fieldDefault)
+
+instance (a ~ Prelude.Maybe Prelude.Double,
+          b ~ Prelude.Maybe Prelude.Double, Prelude.Functor f) =>
+         Lens.Labels.HasLens "maybe'value" f Gauge Gauge a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Gauge'value
+                 (\ x__ y__ -> x__{_Gauge'value = y__}))
+              Prelude.id
+
+instance Data.Default.Class.Default Gauge where
+        def = Gauge{_Gauge'value = Prelude.Nothing}
+
+instance Data.ProtoLens.Message Gauge where
+        descriptor
+          = let value__field_descriptor
+                  = Data.ProtoLens.FieldDescriptor "value"
+                      (Data.ProtoLens.DoubleField ::
+                         Data.ProtoLens.FieldTypeDescriptor Prelude.Double)
+                      (Data.ProtoLens.OptionalField maybe'value)
+                      :: Data.ProtoLens.FieldDescriptor Gauge
+              in
+              Data.ProtoLens.MessageDescriptor
+                (Data.Text.pack "io.prometheus.client.Gauge")
+                (Data.Map.fromList
+                   [(Data.ProtoLens.Tag 1, value__field_descriptor)])
+                (Data.Map.fromList [("value", value__field_descriptor)])
+
+data Histogram = Histogram{_Histogram'sampleCount ::
+                           !(Prelude.Maybe Data.Word.Word64),
+                           _Histogram'sampleSum :: !(Prelude.Maybe Prelude.Double),
+                           _Histogram'bucket :: ![Bucket]}
+               deriving (Prelude.Show, Prelude.Eq, Prelude.Ord)
+
+instance (a ~ Data.Word.Word64, b ~ Data.Word.Word64,
+          Prelude.Functor f) =>
+         Lens.Labels.HasLens "sampleCount" f Histogram Histogram a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Histogram'sampleCount
+                 (\ x__ y__ -> x__{_Histogram'sampleCount = y__}))
+              (Data.ProtoLens.maybeLens Data.ProtoLens.fieldDefault)
+
+instance (a ~ Prelude.Maybe Data.Word.Word64,
+          b ~ Prelude.Maybe Data.Word.Word64, Prelude.Functor f) =>
+         Lens.Labels.HasLens "maybe'sampleCount" f Histogram Histogram a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Histogram'sampleCount
+                 (\ x__ y__ -> x__{_Histogram'sampleCount = y__}))
+              Prelude.id
+
+instance (a ~ Prelude.Double, b ~ Prelude.Double,
+          Prelude.Functor f) =>
+         Lens.Labels.HasLens "sampleSum" f Histogram Histogram a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Histogram'sampleSum
+                 (\ x__ y__ -> x__{_Histogram'sampleSum = y__}))
+              (Data.ProtoLens.maybeLens Data.ProtoLens.fieldDefault)
+
+instance (a ~ Prelude.Maybe Prelude.Double,
+          b ~ Prelude.Maybe Prelude.Double, Prelude.Functor f) =>
+         Lens.Labels.HasLens "maybe'sampleSum" f Histogram Histogram a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Histogram'sampleSum
+                 (\ x__ y__ -> x__{_Histogram'sampleSum = y__}))
+              Prelude.id
+
+instance (a ~ [Bucket], b ~ [Bucket], Prelude.Functor f) =>
+         Lens.Labels.HasLens "bucket" f Histogram Histogram a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Histogram'bucket
+                 (\ x__ y__ -> x__{_Histogram'bucket = y__}))
+              Prelude.id
+
+instance Data.Default.Class.Default Histogram where
+        def
+          = Histogram{_Histogram'sampleCount = Prelude.Nothing,
+                      _Histogram'sampleSum = Prelude.Nothing, _Histogram'bucket = []}
+
+instance Data.ProtoLens.Message Histogram where
+        descriptor
+          = let sampleCount__field_descriptor
+                  = Data.ProtoLens.FieldDescriptor "sample_count"
+                      (Data.ProtoLens.UInt64Field ::
+                         Data.ProtoLens.FieldTypeDescriptor Data.Word.Word64)
+                      (Data.ProtoLens.OptionalField maybe'sampleCount)
+                      :: Data.ProtoLens.FieldDescriptor Histogram
+                sampleSum__field_descriptor
+                  = Data.ProtoLens.FieldDescriptor "sample_sum"
+                      (Data.ProtoLens.DoubleField ::
+                         Data.ProtoLens.FieldTypeDescriptor Prelude.Double)
+                      (Data.ProtoLens.OptionalField maybe'sampleSum)
+                      :: Data.ProtoLens.FieldDescriptor Histogram
+                bucket__field_descriptor
+                  = Data.ProtoLens.FieldDescriptor "bucket"
+                      (Data.ProtoLens.MessageField ::
+                         Data.ProtoLens.FieldTypeDescriptor Bucket)
+                      (Data.ProtoLens.RepeatedField Data.ProtoLens.Unpacked bucket)
+                      :: Data.ProtoLens.FieldDescriptor Histogram
+              in
+              Data.ProtoLens.MessageDescriptor
+                (Data.Text.pack "io.prometheus.client.Histogram")
+                (Data.Map.fromList
+                   [(Data.ProtoLens.Tag 1, sampleCount__field_descriptor),
+                    (Data.ProtoLens.Tag 2, sampleSum__field_descriptor),
+                    (Data.ProtoLens.Tag 3, bucket__field_descriptor)])
+                (Data.Map.fromList
+                   [("sample_count", sampleCount__field_descriptor),
+                    ("sample_sum", sampleSum__field_descriptor),
+                    ("bucket", bucket__field_descriptor)])
+
+data LabelPair = LabelPair{_LabelPair'name ::
+                           !(Prelude.Maybe Data.Text.Text),
+                           _LabelPair'value :: !(Prelude.Maybe Data.Text.Text)}
+               deriving (Prelude.Show, Prelude.Eq, Prelude.Ord)
+
+instance (a ~ Data.Text.Text, b ~ Data.Text.Text,
+          Prelude.Functor f) =>
+         Lens.Labels.HasLens "name" f LabelPair LabelPair a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _LabelPair'name
+                 (\ x__ y__ -> x__{_LabelPair'name = y__}))
+              (Data.ProtoLens.maybeLens Data.ProtoLens.fieldDefault)
+
+instance (a ~ Prelude.Maybe Data.Text.Text,
+          b ~ Prelude.Maybe Data.Text.Text, Prelude.Functor f) =>
+         Lens.Labels.HasLens "maybe'name" f LabelPair LabelPair a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _LabelPair'name
+                 (\ x__ y__ -> x__{_LabelPair'name = y__}))
+              Prelude.id
+
+instance (a ~ Data.Text.Text, b ~ Data.Text.Text,
+          Prelude.Functor f) =>
+         Lens.Labels.HasLens "value" f LabelPair LabelPair a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _LabelPair'value
+                 (\ x__ y__ -> x__{_LabelPair'value = y__}))
+              (Data.ProtoLens.maybeLens Data.ProtoLens.fieldDefault)
+
+instance (a ~ Prelude.Maybe Data.Text.Text,
+          b ~ Prelude.Maybe Data.Text.Text, Prelude.Functor f) =>
+         Lens.Labels.HasLens "maybe'value" f LabelPair LabelPair a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _LabelPair'value
+                 (\ x__ y__ -> x__{_LabelPair'value = y__}))
+              Prelude.id
+
+instance Data.Default.Class.Default LabelPair where
+        def
+          = LabelPair{_LabelPair'name = Prelude.Nothing,
+                      _LabelPair'value = Prelude.Nothing}
+
+instance Data.ProtoLens.Message LabelPair where
+        descriptor
+          = let name__field_descriptor
+                  = Data.ProtoLens.FieldDescriptor "name"
+                      (Data.ProtoLens.StringField ::
+                         Data.ProtoLens.FieldTypeDescriptor Data.Text.Text)
+                      (Data.ProtoLens.OptionalField maybe'name)
+                      :: Data.ProtoLens.FieldDescriptor LabelPair
+                value__field_descriptor
+                  = Data.ProtoLens.FieldDescriptor "value"
+                      (Data.ProtoLens.StringField ::
+                         Data.ProtoLens.FieldTypeDescriptor Data.Text.Text)
+                      (Data.ProtoLens.OptionalField maybe'value)
+                      :: Data.ProtoLens.FieldDescriptor LabelPair
+              in
+              Data.ProtoLens.MessageDescriptor
+                (Data.Text.pack "io.prometheus.client.LabelPair")
+                (Data.Map.fromList
+                   [(Data.ProtoLens.Tag 1, name__field_descriptor),
+                    (Data.ProtoLens.Tag 2, value__field_descriptor)])
+                (Data.Map.fromList
+                   [("name", name__field_descriptor),
+                    ("value", value__field_descriptor)])
+
+data Metric = Metric{_Metric'label :: ![LabelPair],
+                     _Metric'gauge :: !(Prelude.Maybe Gauge),
+                     _Metric'counter :: !(Prelude.Maybe Counter),
+                     _Metric'summary :: !(Prelude.Maybe Summary),
+                     _Metric'untyped :: !(Prelude.Maybe Untyped),
+                     _Metric'histogram :: !(Prelude.Maybe Histogram),
+                     _Metric'timestampMs :: !(Prelude.Maybe Data.Int.Int64)}
+            deriving (Prelude.Show, Prelude.Eq, Prelude.Ord)
+
+instance (a ~ [LabelPair], b ~ [LabelPair], Prelude.Functor f) =>
+         Lens.Labels.HasLens "label" f Metric Metric a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Metric'label
+                 (\ x__ y__ -> x__{_Metric'label = y__}))
+              Prelude.id
+
+instance (a ~ Gauge, b ~ Gauge, Prelude.Functor f) =>
+         Lens.Labels.HasLens "gauge" f Metric Metric a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Metric'gauge
+                 (\ x__ y__ -> x__{_Metric'gauge = y__}))
+              (Data.ProtoLens.maybeLens Data.Default.Class.def)
+
+instance (a ~ Prelude.Maybe Gauge, b ~ Prelude.Maybe Gauge,
+          Prelude.Functor f) =>
+         Lens.Labels.HasLens "maybe'gauge" f Metric Metric a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Metric'gauge
+                 (\ x__ y__ -> x__{_Metric'gauge = y__}))
+              Prelude.id
+
+instance (a ~ Counter, b ~ Counter, Prelude.Functor f) =>
+         Lens.Labels.HasLens "counter" f Metric Metric a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Metric'counter
+                 (\ x__ y__ -> x__{_Metric'counter = y__}))
+              (Data.ProtoLens.maybeLens Data.Default.Class.def)
+
+instance (a ~ Prelude.Maybe Counter, b ~ Prelude.Maybe Counter,
+          Prelude.Functor f) =>
+         Lens.Labels.HasLens "maybe'counter" f Metric Metric a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Metric'counter
+                 (\ x__ y__ -> x__{_Metric'counter = y__}))
+              Prelude.id
+
+instance (a ~ Summary, b ~ Summary, Prelude.Functor f) =>
+         Lens.Labels.HasLens "summary" f Metric Metric a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Metric'summary
+                 (\ x__ y__ -> x__{_Metric'summary = y__}))
+              (Data.ProtoLens.maybeLens Data.Default.Class.def)
+
+instance (a ~ Prelude.Maybe Summary, b ~ Prelude.Maybe Summary,
+          Prelude.Functor f) =>
+         Lens.Labels.HasLens "maybe'summary" f Metric Metric a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Metric'summary
+                 (\ x__ y__ -> x__{_Metric'summary = y__}))
+              Prelude.id
+
+instance (a ~ Untyped, b ~ Untyped, Prelude.Functor f) =>
+         Lens.Labels.HasLens "untyped" f Metric Metric a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Metric'untyped
+                 (\ x__ y__ -> x__{_Metric'untyped = y__}))
+              (Data.ProtoLens.maybeLens Data.Default.Class.def)
+
+instance (a ~ Prelude.Maybe Untyped, b ~ Prelude.Maybe Untyped,
+          Prelude.Functor f) =>
+         Lens.Labels.HasLens "maybe'untyped" f Metric Metric a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Metric'untyped
+                 (\ x__ y__ -> x__{_Metric'untyped = y__}))
+              Prelude.id
+
+instance (a ~ Histogram, b ~ Histogram, Prelude.Functor f) =>
+         Lens.Labels.HasLens "histogram" f Metric Metric a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Metric'histogram
+                 (\ x__ y__ -> x__{_Metric'histogram = y__}))
+              (Data.ProtoLens.maybeLens Data.Default.Class.def)
+
+instance (a ~ Prelude.Maybe Histogram, b ~ Prelude.Maybe Histogram,
+          Prelude.Functor f) =>
+         Lens.Labels.HasLens "maybe'histogram" f Metric Metric a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Metric'histogram
+                 (\ x__ y__ -> x__{_Metric'histogram = y__}))
+              Prelude.id
+
+instance (a ~ Data.Int.Int64, b ~ Data.Int.Int64,
+          Prelude.Functor f) =>
+         Lens.Labels.HasLens "timestampMs" f Metric Metric a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Metric'timestampMs
+                 (\ x__ y__ -> x__{_Metric'timestampMs = y__}))
+              (Data.ProtoLens.maybeLens Data.ProtoLens.fieldDefault)
+
+instance (a ~ Prelude.Maybe Data.Int.Int64,
+          b ~ Prelude.Maybe Data.Int.Int64, Prelude.Functor f) =>
+         Lens.Labels.HasLens "maybe'timestampMs" f Metric Metric a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Metric'timestampMs
+                 (\ x__ y__ -> x__{_Metric'timestampMs = y__}))
+              Prelude.id
+
+instance Data.Default.Class.Default Metric where
+        def
+          = Metric{_Metric'label = [], _Metric'gauge = Prelude.Nothing,
+                   _Metric'counter = Prelude.Nothing,
+                   _Metric'summary = Prelude.Nothing,
+                   _Metric'untyped = Prelude.Nothing,
+                   _Metric'histogram = Prelude.Nothing,
+                   _Metric'timestampMs = Prelude.Nothing}
+
+instance Data.ProtoLens.Message Metric where
+        descriptor
+          = let label__field_descriptor
+                  = Data.ProtoLens.FieldDescriptor "label"
+                      (Data.ProtoLens.MessageField ::
+                         Data.ProtoLens.FieldTypeDescriptor LabelPair)
+                      (Data.ProtoLens.RepeatedField Data.ProtoLens.Unpacked label)
+                      :: Data.ProtoLens.FieldDescriptor Metric
+                gauge__field_descriptor
+                  = Data.ProtoLens.FieldDescriptor "gauge"
+                      (Data.ProtoLens.MessageField ::
+                         Data.ProtoLens.FieldTypeDescriptor Gauge)
+                      (Data.ProtoLens.OptionalField maybe'gauge)
+                      :: Data.ProtoLens.FieldDescriptor Metric
+                counter__field_descriptor
+                  = Data.ProtoLens.FieldDescriptor "counter"
+                      (Data.ProtoLens.MessageField ::
+                         Data.ProtoLens.FieldTypeDescriptor Counter)
+                      (Data.ProtoLens.OptionalField maybe'counter)
+                      :: Data.ProtoLens.FieldDescriptor Metric
+                summary__field_descriptor
+                  = Data.ProtoLens.FieldDescriptor "summary"
+                      (Data.ProtoLens.MessageField ::
+                         Data.ProtoLens.FieldTypeDescriptor Summary)
+                      (Data.ProtoLens.OptionalField maybe'summary)
+                      :: Data.ProtoLens.FieldDescriptor Metric
+                untyped__field_descriptor
+                  = Data.ProtoLens.FieldDescriptor "untyped"
+                      (Data.ProtoLens.MessageField ::
+                         Data.ProtoLens.FieldTypeDescriptor Untyped)
+                      (Data.ProtoLens.OptionalField maybe'untyped)
+                      :: Data.ProtoLens.FieldDescriptor Metric
+                histogram__field_descriptor
+                  = Data.ProtoLens.FieldDescriptor "histogram"
+                      (Data.ProtoLens.MessageField ::
+                         Data.ProtoLens.FieldTypeDescriptor Histogram)
+                      (Data.ProtoLens.OptionalField maybe'histogram)
+                      :: Data.ProtoLens.FieldDescriptor Metric
+                timestampMs__field_descriptor
+                  = Data.ProtoLens.FieldDescriptor "timestamp_ms"
+                      (Data.ProtoLens.Int64Field ::
+                         Data.ProtoLens.FieldTypeDescriptor Data.Int.Int64)
+                      (Data.ProtoLens.OptionalField maybe'timestampMs)
+                      :: Data.ProtoLens.FieldDescriptor Metric
+              in
+              Data.ProtoLens.MessageDescriptor
+                (Data.Text.pack "io.prometheus.client.Metric")
+                (Data.Map.fromList
+                   [(Data.ProtoLens.Tag 1, label__field_descriptor),
+                    (Data.ProtoLens.Tag 2, gauge__field_descriptor),
+                    (Data.ProtoLens.Tag 3, counter__field_descriptor),
+                    (Data.ProtoLens.Tag 4, summary__field_descriptor),
+                    (Data.ProtoLens.Tag 5, untyped__field_descriptor),
+                    (Data.ProtoLens.Tag 7, histogram__field_descriptor),
+                    (Data.ProtoLens.Tag 6, timestampMs__field_descriptor)])
+                (Data.Map.fromList
+                   [("label", label__field_descriptor),
+                    ("gauge", gauge__field_descriptor),
+                    ("counter", counter__field_descriptor),
+                    ("summary", summary__field_descriptor),
+                    ("untyped", untyped__field_descriptor),
+                    ("histogram", histogram__field_descriptor),
+                    ("timestamp_ms", timestampMs__field_descriptor)])
+
+data MetricFamily = MetricFamily{_MetricFamily'name ::
+                                 !(Prelude.Maybe Data.Text.Text),
+                                 _MetricFamily'help :: !(Prelude.Maybe Data.Text.Text),
+                                 _MetricFamily'type' :: !(Prelude.Maybe MetricType),
+                                 _MetricFamily'metric :: ![Metric]}
+                  deriving (Prelude.Show, Prelude.Eq, Prelude.Ord)
+
+instance (a ~ Data.Text.Text, b ~ Data.Text.Text,
+          Prelude.Functor f) =>
+         Lens.Labels.HasLens "name" f MetricFamily MetricFamily a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _MetricFamily'name
+                 (\ x__ y__ -> x__{_MetricFamily'name = y__}))
+              (Data.ProtoLens.maybeLens Data.ProtoLens.fieldDefault)
+
+instance (a ~ Prelude.Maybe Data.Text.Text,
+          b ~ Prelude.Maybe Data.Text.Text, Prelude.Functor f) =>
+         Lens.Labels.HasLens "maybe'name" f MetricFamily MetricFamily a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _MetricFamily'name
+                 (\ x__ y__ -> x__{_MetricFamily'name = y__}))
+              Prelude.id
+
+instance (a ~ Data.Text.Text, b ~ Data.Text.Text,
+          Prelude.Functor f) =>
+         Lens.Labels.HasLens "help" f MetricFamily MetricFamily a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _MetricFamily'help
+                 (\ x__ y__ -> x__{_MetricFamily'help = y__}))
+              (Data.ProtoLens.maybeLens Data.ProtoLens.fieldDefault)
+
+instance (a ~ Prelude.Maybe Data.Text.Text,
+          b ~ Prelude.Maybe Data.Text.Text, Prelude.Functor f) =>
+         Lens.Labels.HasLens "maybe'help" f MetricFamily MetricFamily a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _MetricFamily'help
+                 (\ x__ y__ -> x__{_MetricFamily'help = y__}))
+              Prelude.id
+
+instance (a ~ MetricType, b ~ MetricType, Prelude.Functor f) =>
+         Lens.Labels.HasLens "type'" f MetricFamily MetricFamily a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _MetricFamily'type'
+                 (\ x__ y__ -> x__{_MetricFamily'type' = y__}))
+              (Data.ProtoLens.maybeLens Data.Default.Class.def)
+
+instance (a ~ Prelude.Maybe MetricType,
+          b ~ Prelude.Maybe MetricType, Prelude.Functor f) =>
+         Lens.Labels.HasLens "maybe'type'" f MetricFamily MetricFamily a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _MetricFamily'type'
+                 (\ x__ y__ -> x__{_MetricFamily'type' = y__}))
+              Prelude.id
+
+instance (a ~ [Metric], b ~ [Metric], Prelude.Functor f) =>
+         Lens.Labels.HasLens "metric" f MetricFamily MetricFamily a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _MetricFamily'metric
+                 (\ x__ y__ -> x__{_MetricFamily'metric = y__}))
+              Prelude.id
+
+instance Data.Default.Class.Default MetricFamily where
+        def
+          = MetricFamily{_MetricFamily'name = Prelude.Nothing,
+                         _MetricFamily'help = Prelude.Nothing,
+                         _MetricFamily'type' = Prelude.Nothing, _MetricFamily'metric = []}
+
+instance Data.ProtoLens.Message MetricFamily where
+        descriptor
+          = let name__field_descriptor
+                  = Data.ProtoLens.FieldDescriptor "name"
+                      (Data.ProtoLens.StringField ::
+                         Data.ProtoLens.FieldTypeDescriptor Data.Text.Text)
+                      (Data.ProtoLens.OptionalField maybe'name)
+                      :: Data.ProtoLens.FieldDescriptor MetricFamily
+                help__field_descriptor
+                  = Data.ProtoLens.FieldDescriptor "help"
+                      (Data.ProtoLens.StringField ::
+                         Data.ProtoLens.FieldTypeDescriptor Data.Text.Text)
+                      (Data.ProtoLens.OptionalField maybe'help)
+                      :: Data.ProtoLens.FieldDescriptor MetricFamily
+                type'__field_descriptor
+                  = Data.ProtoLens.FieldDescriptor "type"
+                      (Data.ProtoLens.EnumField ::
+                         Data.ProtoLens.FieldTypeDescriptor MetricType)
+                      (Data.ProtoLens.OptionalField maybe'type')
+                      :: Data.ProtoLens.FieldDescriptor MetricFamily
+                metric__field_descriptor
+                  = Data.ProtoLens.FieldDescriptor "metric"
+                      (Data.ProtoLens.MessageField ::
+                         Data.ProtoLens.FieldTypeDescriptor Metric)
+                      (Data.ProtoLens.RepeatedField Data.ProtoLens.Unpacked metric)
+                      :: Data.ProtoLens.FieldDescriptor MetricFamily
+              in
+              Data.ProtoLens.MessageDescriptor
+                (Data.Text.pack "io.prometheus.client.MetricFamily")
+                (Data.Map.fromList
+                   [(Data.ProtoLens.Tag 1, name__field_descriptor),
+                    (Data.ProtoLens.Tag 2, help__field_descriptor),
+                    (Data.ProtoLens.Tag 3, type'__field_descriptor),
+                    (Data.ProtoLens.Tag 4, metric__field_descriptor)])
+                (Data.Map.fromList
+                   [("name", name__field_descriptor),
+                    ("help", help__field_descriptor),
+                    ("type", type'__field_descriptor),
+                    ("metric", metric__field_descriptor)])
+
+data MetricType = COUNTER
+                | GAUGE
+                | SUMMARY
+                | UNTYPED
+                | HISTOGRAM
+                deriving (Prelude.Show, Prelude.Eq, Prelude.Ord)
+
+instance Data.Default.Class.Default MetricType where
+        def = COUNTER
+
+instance Data.ProtoLens.FieldDefault MetricType where
+        fieldDefault = COUNTER
+
+instance Data.ProtoLens.MessageEnum MetricType where
+        maybeToEnum 0 = Prelude.Just COUNTER
+        maybeToEnum 1 = Prelude.Just GAUGE
+        maybeToEnum 2 = Prelude.Just SUMMARY
+        maybeToEnum 3 = Prelude.Just UNTYPED
+        maybeToEnum 4 = Prelude.Just HISTOGRAM
+        maybeToEnum _ = Prelude.Nothing
+        showEnum COUNTER = "COUNTER"
+        showEnum GAUGE = "GAUGE"
+        showEnum SUMMARY = "SUMMARY"
+        showEnum UNTYPED = "UNTYPED"
+        showEnum HISTOGRAM = "HISTOGRAM"
+        readEnum "COUNTER" = Prelude.Just COUNTER
+        readEnum "GAUGE" = Prelude.Just GAUGE
+        readEnum "SUMMARY" = Prelude.Just SUMMARY
+        readEnum "UNTYPED" = Prelude.Just UNTYPED
+        readEnum "HISTOGRAM" = Prelude.Just HISTOGRAM
+        readEnum _ = Prelude.Nothing
+
+instance Prelude.Enum MetricType where
+        toEnum k__
+          = Prelude.maybe
+              (Prelude.error
+                 ((Prelude.++) "toEnum: unknown value for enum MetricType: "
+                    (Prelude.show k__)))
+              Prelude.id
+              (Data.ProtoLens.maybeToEnum k__)
+        fromEnum COUNTER = 0
+        fromEnum GAUGE = 1
+        fromEnum SUMMARY = 2
+        fromEnum UNTYPED = 3
+        fromEnum HISTOGRAM = 4
+        succ HISTOGRAM
+          = Prelude.error
+              "MetricType.succ: bad argument HISTOGRAM. This value would be out of bounds."
+        succ COUNTER = GAUGE
+        succ GAUGE = SUMMARY
+        succ SUMMARY = UNTYPED
+        succ UNTYPED = HISTOGRAM
+        pred COUNTER
+          = Prelude.error
+              "MetricType.pred: bad argument COUNTER. This value would be out of bounds."
+        pred GAUGE = COUNTER
+        pred SUMMARY = GAUGE
+        pred UNTYPED = SUMMARY
+        pred HISTOGRAM = UNTYPED
+        enumFrom = Data.ProtoLens.Message.Enum.messageEnumFrom
+        enumFromTo = Data.ProtoLens.Message.Enum.messageEnumFromTo
+        enumFromThen = Data.ProtoLens.Message.Enum.messageEnumFromThen
+        enumFromThenTo = Data.ProtoLens.Message.Enum.messageEnumFromThenTo
+
+instance Prelude.Bounded MetricType where
+        minBound = COUNTER
+        maxBound = HISTOGRAM
+
+data Quantile = Quantile{_Quantile'quantile ::
+                         !(Prelude.Maybe Prelude.Double),
+                         _Quantile'value :: !(Prelude.Maybe Prelude.Double)}
+              deriving (Prelude.Show, Prelude.Eq, Prelude.Ord)
+
+instance (a ~ Prelude.Double, b ~ Prelude.Double,
+          Prelude.Functor f) =>
+         Lens.Labels.HasLens "quantile" f Quantile Quantile a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Quantile'quantile
+                 (\ x__ y__ -> x__{_Quantile'quantile = y__}))
+              (Data.ProtoLens.maybeLens Data.ProtoLens.fieldDefault)
+
+instance (a ~ Prelude.Maybe Prelude.Double,
+          b ~ Prelude.Maybe Prelude.Double, Prelude.Functor f) =>
+         Lens.Labels.HasLens "maybe'quantile" f Quantile Quantile a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Quantile'quantile
+                 (\ x__ y__ -> x__{_Quantile'quantile = y__}))
+              Prelude.id
+
+instance (a ~ Prelude.Double, b ~ Prelude.Double,
+          Prelude.Functor f) =>
+         Lens.Labels.HasLens "value" f Quantile Quantile a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Quantile'value
+                 (\ x__ y__ -> x__{_Quantile'value = y__}))
+              (Data.ProtoLens.maybeLens Data.ProtoLens.fieldDefault)
+
+instance (a ~ Prelude.Maybe Prelude.Double,
+          b ~ Prelude.Maybe Prelude.Double, Prelude.Functor f) =>
+         Lens.Labels.HasLens "maybe'value" f Quantile Quantile a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Quantile'value
+                 (\ x__ y__ -> x__{_Quantile'value = y__}))
+              Prelude.id
+
+instance Data.Default.Class.Default Quantile where
+        def
+          = Quantile{_Quantile'quantile = Prelude.Nothing,
+                     _Quantile'value = Prelude.Nothing}
+
+instance Data.ProtoLens.Message Quantile where
+        descriptor
+          = let quantile__field_descriptor
+                  = Data.ProtoLens.FieldDescriptor "quantile"
+                      (Data.ProtoLens.DoubleField ::
+                         Data.ProtoLens.FieldTypeDescriptor Prelude.Double)
+                      (Data.ProtoLens.OptionalField maybe'quantile)
+                      :: Data.ProtoLens.FieldDescriptor Quantile
+                value__field_descriptor
+                  = Data.ProtoLens.FieldDescriptor "value"
+                      (Data.ProtoLens.DoubleField ::
+                         Data.ProtoLens.FieldTypeDescriptor Prelude.Double)
+                      (Data.ProtoLens.OptionalField maybe'value)
+                      :: Data.ProtoLens.FieldDescriptor Quantile
+              in
+              Data.ProtoLens.MessageDescriptor
+                (Data.Text.pack "io.prometheus.client.Quantile")
+                (Data.Map.fromList
+                   [(Data.ProtoLens.Tag 1, quantile__field_descriptor),
+                    (Data.ProtoLens.Tag 2, value__field_descriptor)])
+                (Data.Map.fromList
+                   [("quantile", quantile__field_descriptor),
+                    ("value", value__field_descriptor)])
+
+data Summary = Summary{_Summary'sampleCount ::
+                       !(Prelude.Maybe Data.Word.Word64),
+                       _Summary'sampleSum :: !(Prelude.Maybe Prelude.Double),
+                       _Summary'quantile :: ![Quantile]}
+             deriving (Prelude.Show, Prelude.Eq, Prelude.Ord)
+
+instance (a ~ Data.Word.Word64, b ~ Data.Word.Word64,
+          Prelude.Functor f) =>
+         Lens.Labels.HasLens "sampleCount" f Summary Summary a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Summary'sampleCount
+                 (\ x__ y__ -> x__{_Summary'sampleCount = y__}))
+              (Data.ProtoLens.maybeLens Data.ProtoLens.fieldDefault)
+
+instance (a ~ Prelude.Maybe Data.Word.Word64,
+          b ~ Prelude.Maybe Data.Word.Word64, Prelude.Functor f) =>
+         Lens.Labels.HasLens "maybe'sampleCount" f Summary Summary a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Summary'sampleCount
+                 (\ x__ y__ -> x__{_Summary'sampleCount = y__}))
+              Prelude.id
+
+instance (a ~ Prelude.Double, b ~ Prelude.Double,
+          Prelude.Functor f) =>
+         Lens.Labels.HasLens "sampleSum" f Summary Summary a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Summary'sampleSum
+                 (\ x__ y__ -> x__{_Summary'sampleSum = y__}))
+              (Data.ProtoLens.maybeLens Data.ProtoLens.fieldDefault)
+
+instance (a ~ Prelude.Maybe Prelude.Double,
+          b ~ Prelude.Maybe Prelude.Double, Prelude.Functor f) =>
+         Lens.Labels.HasLens "maybe'sampleSum" f Summary Summary a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Summary'sampleSum
+                 (\ x__ y__ -> x__{_Summary'sampleSum = y__}))
+              Prelude.id
+
+instance (a ~ [Quantile], b ~ [Quantile], Prelude.Functor f) =>
+         Lens.Labels.HasLens "quantile" f Summary Summary a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Summary'quantile
+                 (\ x__ y__ -> x__{_Summary'quantile = y__}))
+              Prelude.id
+
+instance Data.Default.Class.Default Summary where
+        def
+          = Summary{_Summary'sampleCount = Prelude.Nothing,
+                    _Summary'sampleSum = Prelude.Nothing, _Summary'quantile = []}
+
+instance Data.ProtoLens.Message Summary where
+        descriptor
+          = let sampleCount__field_descriptor
+                  = Data.ProtoLens.FieldDescriptor "sample_count"
+                      (Data.ProtoLens.UInt64Field ::
+                         Data.ProtoLens.FieldTypeDescriptor Data.Word.Word64)
+                      (Data.ProtoLens.OptionalField maybe'sampleCount)
+                      :: Data.ProtoLens.FieldDescriptor Summary
+                sampleSum__field_descriptor
+                  = Data.ProtoLens.FieldDescriptor "sample_sum"
+                      (Data.ProtoLens.DoubleField ::
+                         Data.ProtoLens.FieldTypeDescriptor Prelude.Double)
+                      (Data.ProtoLens.OptionalField maybe'sampleSum)
+                      :: Data.ProtoLens.FieldDescriptor Summary
+                quantile__field_descriptor
+                  = Data.ProtoLens.FieldDescriptor "quantile"
+                      (Data.ProtoLens.MessageField ::
+                         Data.ProtoLens.FieldTypeDescriptor Quantile)
+                      (Data.ProtoLens.RepeatedField Data.ProtoLens.Unpacked quantile)
+                      :: Data.ProtoLens.FieldDescriptor Summary
+              in
+              Data.ProtoLens.MessageDescriptor
+                (Data.Text.pack "io.prometheus.client.Summary")
+                (Data.Map.fromList
+                   [(Data.ProtoLens.Tag 1, sampleCount__field_descriptor),
+                    (Data.ProtoLens.Tag 2, sampleSum__field_descriptor),
+                    (Data.ProtoLens.Tag 3, quantile__field_descriptor)])
+                (Data.Map.fromList
+                   [("sample_count", sampleCount__field_descriptor),
+                    ("sample_sum", sampleSum__field_descriptor),
+                    ("quantile", quantile__field_descriptor)])
+
+data Untyped = Untyped{_Untyped'value ::
+                       !(Prelude.Maybe Prelude.Double)}
+             deriving (Prelude.Show, Prelude.Eq, Prelude.Ord)
+
+instance (a ~ Prelude.Double, b ~ Prelude.Double,
+          Prelude.Functor f) =>
+         Lens.Labels.HasLens "value" f Untyped Untyped a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Untyped'value
+                 (\ x__ y__ -> x__{_Untyped'value = y__}))
+              (Data.ProtoLens.maybeLens Data.ProtoLens.fieldDefault)
+
+instance (a ~ Prelude.Maybe Prelude.Double,
+          b ~ Prelude.Maybe Prelude.Double, Prelude.Functor f) =>
+         Lens.Labels.HasLens "maybe'value" f Untyped Untyped a b
+         where
+        lensOf _
+          = (Prelude..)
+              (Lens.Family2.Unchecked.lens _Untyped'value
+                 (\ x__ y__ -> x__{_Untyped'value = y__}))
+              Prelude.id
+
+instance Data.Default.Class.Default Untyped where
+        def = Untyped{_Untyped'value = Prelude.Nothing}
+
+instance Data.ProtoLens.Message Untyped where
+        descriptor
+          = let value__field_descriptor
+                  = Data.ProtoLens.FieldDescriptor "value"
+                      (Data.ProtoLens.DoubleField ::
+                         Data.ProtoLens.FieldTypeDescriptor Prelude.Double)
+                      (Data.ProtoLens.OptionalField maybe'value)
+                      :: Data.ProtoLens.FieldDescriptor Untyped
+              in
+              Data.ProtoLens.MessageDescriptor
+                (Data.Text.pack "io.prometheus.client.Untyped")
+                (Data.Map.fromList
+                   [(Data.ProtoLens.Tag 1, value__field_descriptor)])
+                (Data.Map.fromList [("value", value__field_descriptor)])
+
+bucket ::
+       forall f s t a b . (Lens.Labels.HasLens "bucket" f s t a b) =>
+         Lens.Family2.LensLike f s t a b
+bucket
+  = Lens.Labels.lensOf
+      ((Lens.Labels.proxy#) :: (Lens.Labels.Proxy#) "bucket")
+
+counter ::
+        forall f s t a b . (Lens.Labels.HasLens "counter" f s t a b) =>
+          Lens.Family2.LensLike f s t a b
+counter
+  = Lens.Labels.lensOf
+      ((Lens.Labels.proxy#) :: (Lens.Labels.Proxy#) "counter")
+
+cumulativeCount ::
+                forall f s t a b .
+                  (Lens.Labels.HasLens "cumulativeCount" f s t a b) =>
+                  Lens.Family2.LensLike f s t a b
+cumulativeCount
+  = Lens.Labels.lensOf
+      ((Lens.Labels.proxy#) :: (Lens.Labels.Proxy#) "cumulativeCount")
+
+gauge ::
+      forall f s t a b . (Lens.Labels.HasLens "gauge" f s t a b) =>
+        Lens.Family2.LensLike f s t a b
+gauge
+  = Lens.Labels.lensOf
+      ((Lens.Labels.proxy#) :: (Lens.Labels.Proxy#) "gauge")
+
+help ::
+     forall f s t a b . (Lens.Labels.HasLens "help" f s t a b) =>
+       Lens.Family2.LensLike f s t a b
+help
+  = Lens.Labels.lensOf
+      ((Lens.Labels.proxy#) :: (Lens.Labels.Proxy#) "help")
+
+histogram ::
+          forall f s t a b . (Lens.Labels.HasLens "histogram" f s t a b) =>
+            Lens.Family2.LensLike f s t a b
+histogram
+  = Lens.Labels.lensOf
+      ((Lens.Labels.proxy#) :: (Lens.Labels.Proxy#) "histogram")
+
+label ::
+      forall f s t a b . (Lens.Labels.HasLens "label" f s t a b) =>
+        Lens.Family2.LensLike f s t a b
+label
+  = Lens.Labels.lensOf
+      ((Lens.Labels.proxy#) :: (Lens.Labels.Proxy#) "label")
+
+maybe'counter ::
+              forall f s t a b .
+                (Lens.Labels.HasLens "maybe'counter" f s t a b) =>
+                Lens.Family2.LensLike f s t a b
+maybe'counter
+  = Lens.Labels.lensOf
+      ((Lens.Labels.proxy#) :: (Lens.Labels.Proxy#) "maybe'counter")
+
+maybe'cumulativeCount ::
+                      forall f s t a b .
+                        (Lens.Labels.HasLens "maybe'cumulativeCount" f s t a b) =>
+                        Lens.Family2.LensLike f s t a b
+maybe'cumulativeCount
+  = Lens.Labels.lensOf
+      ((Lens.Labels.proxy#) ::
+         (Lens.Labels.Proxy#) "maybe'cumulativeCount")
+
+maybe'gauge ::
+            forall f s t a b . (Lens.Labels.HasLens "maybe'gauge" f s t a b) =>
+              Lens.Family2.LensLike f s t a b
+maybe'gauge
+  = Lens.Labels.lensOf
+      ((Lens.Labels.proxy#) :: (Lens.Labels.Proxy#) "maybe'gauge")
+
+maybe'help ::
+           forall f s t a b . (Lens.Labels.HasLens "maybe'help" f s t a b) =>
+             Lens.Family2.LensLike f s t a b
+maybe'help
+  = Lens.Labels.lensOf
+      ((Lens.Labels.proxy#) :: (Lens.Labels.Proxy#) "maybe'help")
+
+maybe'histogram ::
+                forall f s t a b .
+                  (Lens.Labels.HasLens "maybe'histogram" f s t a b) =>
+                  Lens.Family2.LensLike f s t a b
+maybe'histogram
+  = Lens.Labels.lensOf
+      ((Lens.Labels.proxy#) :: (Lens.Labels.Proxy#) "maybe'histogram")
+
+maybe'name ::
+           forall f s t a b . (Lens.Labels.HasLens "maybe'name" f s t a b) =>
+             Lens.Family2.LensLike f s t a b
+maybe'name
+  = Lens.Labels.lensOf
+      ((Lens.Labels.proxy#) :: (Lens.Labels.Proxy#) "maybe'name")
+
+maybe'quantile ::
+               forall f s t a b .
+                 (Lens.Labels.HasLens "maybe'quantile" f s t a b) =>
+                 Lens.Family2.LensLike f s t a b
+maybe'quantile
+  = Lens.Labels.lensOf
+      ((Lens.Labels.proxy#) :: (Lens.Labels.Proxy#) "maybe'quantile")
+
+maybe'sampleCount ::
+                  forall f s t a b .
+                    (Lens.Labels.HasLens "maybe'sampleCount" f s t a b) =>
+                    Lens.Family2.LensLike f s t a b
+maybe'sampleCount
+  = Lens.Labels.lensOf
+      ((Lens.Labels.proxy#) :: (Lens.Labels.Proxy#) "maybe'sampleCount")
+
+maybe'sampleSum ::
+                forall f s t a b .
+                  (Lens.Labels.HasLens "maybe'sampleSum" f s t a b) =>
+                  Lens.Family2.LensLike f s t a b
+maybe'sampleSum
+  = Lens.Labels.lensOf
+      ((Lens.Labels.proxy#) :: (Lens.Labels.Proxy#) "maybe'sampleSum")
+
+maybe'summary ::
+              forall f s t a b .
+                (Lens.Labels.HasLens "maybe'summary" f s t a b) =>
+                Lens.Family2.LensLike f s t a b
+maybe'summary
+  = Lens.Labels.lensOf
+      ((Lens.Labels.proxy#) :: (Lens.Labels.Proxy#) "maybe'summary")
+
+maybe'timestampMs ::
+                  forall f s t a b .
+                    (Lens.Labels.HasLens "maybe'timestampMs" f s t a b) =>
+                    Lens.Family2.LensLike f s t a b
+maybe'timestampMs
+  = Lens.Labels.lensOf
+      ((Lens.Labels.proxy#) :: (Lens.Labels.Proxy#) "maybe'timestampMs")
+
+maybe'type' ::
+            forall f s t a b . (Lens.Labels.HasLens "maybe'type'" f s t a b) =>
+              Lens.Family2.LensLike f s t a b
+maybe'type'
+  = Lens.Labels.lensOf
+      ((Lens.Labels.proxy#) :: (Lens.Labels.Proxy#) "maybe'type'")
+
+maybe'untyped ::
+              forall f s t a b .
+                (Lens.Labels.HasLens "maybe'untyped" f s t a b) =>
+                Lens.Family2.LensLike f s t a b
+maybe'untyped
+  = Lens.Labels.lensOf
+      ((Lens.Labels.proxy#) :: (Lens.Labels.Proxy#) "maybe'untyped")
+
+maybe'upperBound ::
+                 forall f s t a b .
+                   (Lens.Labels.HasLens "maybe'upperBound" f s t a b) =>
+                   Lens.Family2.LensLike f s t a b
+maybe'upperBound
+  = Lens.Labels.lensOf
+      ((Lens.Labels.proxy#) :: (Lens.Labels.Proxy#) "maybe'upperBound")
+
+maybe'value ::
+            forall f s t a b . (Lens.Labels.HasLens "maybe'value" f s t a b) =>
+              Lens.Family2.LensLike f s t a b
+maybe'value
+  = Lens.Labels.lensOf
+      ((Lens.Labels.proxy#) :: (Lens.Labels.Proxy#) "maybe'value")
+
+metric ::
+       forall f s t a b . (Lens.Labels.HasLens "metric" f s t a b) =>
+         Lens.Family2.LensLike f s t a b
+metric
+  = Lens.Labels.lensOf
+      ((Lens.Labels.proxy#) :: (Lens.Labels.Proxy#) "metric")
+
+name ::
+     forall f s t a b . (Lens.Labels.HasLens "name" f s t a b) =>
+       Lens.Family2.LensLike f s t a b
+name
+  = Lens.Labels.lensOf
+      ((Lens.Labels.proxy#) :: (Lens.Labels.Proxy#) "name")
+
+quantile ::
+         forall f s t a b . (Lens.Labels.HasLens "quantile" f s t a b) =>
+           Lens.Family2.LensLike f s t a b
+quantile
+  = Lens.Labels.lensOf
+      ((Lens.Labels.proxy#) :: (Lens.Labels.Proxy#) "quantile")
+
+sampleCount ::
+            forall f s t a b . (Lens.Labels.HasLens "sampleCount" f s t a b) =>
+              Lens.Family2.LensLike f s t a b
+sampleCount
+  = Lens.Labels.lensOf
+      ((Lens.Labels.proxy#) :: (Lens.Labels.Proxy#) "sampleCount")
+
+sampleSum ::
+          forall f s t a b . (Lens.Labels.HasLens "sampleSum" f s t a b) =>
+            Lens.Family2.LensLike f s t a b
+sampleSum
+  = Lens.Labels.lensOf
+      ((Lens.Labels.proxy#) :: (Lens.Labels.Proxy#) "sampleSum")
+
+summary ::
+        forall f s t a b . (Lens.Labels.HasLens "summary" f s t a b) =>
+          Lens.Family2.LensLike f s t a b
+summary
+  = Lens.Labels.lensOf
+      ((Lens.Labels.proxy#) :: (Lens.Labels.Proxy#) "summary")
+
+timestampMs ::
+            forall f s t a b . (Lens.Labels.HasLens "timestampMs" f s t a b) =>
+              Lens.Family2.LensLike f s t a b
+timestampMs
+  = Lens.Labels.lensOf
+      ((Lens.Labels.proxy#) :: (Lens.Labels.Proxy#) "timestampMs")
+
+type' ::
+      forall f s t a b . (Lens.Labels.HasLens "type'" f s t a b) =>
+        Lens.Family2.LensLike f s t a b
+type'
+  = Lens.Labels.lensOf
+      ((Lens.Labels.proxy#) :: (Lens.Labels.Proxy#) "type'")
+
+untyped ::
+        forall f s t a b . (Lens.Labels.HasLens "untyped" f s t a b) =>
+          Lens.Family2.LensLike f s t a b
+untyped
+  = Lens.Labels.lensOf
+      ((Lens.Labels.proxy#) :: (Lens.Labels.Proxy#) "untyped")
+
+upperBound ::
+           forall f s t a b . (Lens.Labels.HasLens "upperBound" f s t a b) =>
+             Lens.Family2.LensLike f s t a b
+upperBound
+  = Lens.Labels.lensOf
+      ((Lens.Labels.proxy#) :: (Lens.Labels.Proxy#) "upperBound")
+
+value ::
+      forall f s t a b . (Lens.Labels.HasLens "value" f s t a b) =>
+        Lens.Family2.LensLike f s t a b
+value
+  = Lens.Labels.lensOf
+      ((Lens.Labels.proxy#) :: (Lens.Labels.Proxy#) "value")
diff --git a/prometheus.cabal b/prometheus.cabal
--- a/prometheus.cabal
+++ b/prometheus.cabal
@@ -1,5 +1,5 @@
 name:                prometheus
-version:             0.4.2
+version:             0.5.0
 synopsis:            Prometheus Haskell Client
 homepage:            http://github.com/bitnomial/prometheus
 bug-reports:         http://github.com/bitnomial/prometheus/issues
@@ -55,15 +55,20 @@
                   , README.md
 
 library
-  hs-source-dirs:      src
+  hs-source-dirs: gen
+                , src
   default-language:    Haskell2010
 
-  exposed-modules: System.Metrics.Prometheus.Concurrent.Http
-                 , System.Metrics.Prometheus.Concurrent.Registry
+  ghc-options: -Wall -fwarn-tabs -fno-warn-unused-do-bind
+
+  exposed-modules: System.Metrics.Prometheus.Concurrent.Registry
                  , System.Metrics.Prometheus.Concurrent.RegistryT
-                 , System.Metrics.Prometheus.Encode
-                 , System.Metrics.Prometheus.Encode.Histogram
-                 , System.Metrics.Prometheus.Encode.MetricId
+                 , System.Metrics.Prometheus.Encode.ProtocolBuffers
+                 , System.Metrics.Prometheus.Encode.Text
+                 , System.Metrics.Prometheus.Encode.Text.Histogram
+                 , System.Metrics.Prometheus.Encode.Text.MetricId
+                 , System.Metrics.Prometheus.Http.Push
+                 , System.Metrics.Prometheus.Http.Scrape
                  , System.Metrics.Prometheus.Metric
                  , System.Metrics.Prometheus.Metric.Counter
                  , System.Metrics.Prometheus.Metric.Gauge
@@ -73,15 +78,22 @@
                  , System.Metrics.Prometheus.Registry
                  , System.Metrics.Prometheus.RegistryT
 
-  build-depends: atomic-primops >= 0.8  && < 0.9
-               , base           >= 4.7  && < 4.11
-               , bytestring     >= 0.10 && < 0.11
-               , containers     >= 0.5  && < 0.6
-               , http-types     >= 0.8  && < 0.10
-               , text           >= 1.2  && < 1.3
-               , transformers   >= 0.4  && < 0.6
-               , wai            >= 3.2  && < 3.3
-               , warp           >= 3.2  && < 3.3
+  other-modules: Proto.Proto.Metrics
+
+  build-depends: base              >= 4.7  && < 4.11
+               , atomic-primops    >= 0.8  && < 0.9
+               , bytestring        >= 0.10 && < 0.11
+               , containers        >= 0.5  && < 0.6
+               , http-client       >= 0.5  && < 0.6
+               , http-types        >= 0.8  && < 0.10
+               , lens              >= 4.15 && < 4.16
+               , proto-lens        >= 0.2  && < 0.3
+               , proto-lens-protoc >= 0.2  && < 0.3
+               , text              >= 1.2  && < 1.3
+               , transformers      >= 0.4  && < 0.6
+               , wai               >= 3.2  && < 3.3
+               , warp              >= 3.2  && < 3.3
+               , wreq              >= 0.5  && < 0.6
 
 source-repository head
   type:     git
diff --git a/src/System/Metrics/Prometheus/Concurrent/Http.hs b/src/System/Metrics/Prometheus/Concurrent/Http.hs
deleted file mode 100644
--- a/src/System/Metrics/Prometheus/Concurrent/Http.hs
+++ /dev/null
@@ -1,64 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-
-module System.Metrics.Prometheus.Concurrent.Http
-       ( Path
-       , serveHttpTextMetrics
-       , serveHttpTextMetricsT
-       , prometheusApp
-       )
-       where
-
-import           Control.Monad.IO.Class                         (MonadIO,
-                                                                 liftIO)
-import           Data.Text                                      (Text)
-import           Network.HTTP.Types                             (hContentType,
-                                                                 methodGet,
-                                                                 status200,
-                                                                 status404)
-import           Network.Wai                                    (Application,
-                                                                 Request,
-                                                                 Response,
-                                                                 pathInfo,
-                                                                 requestMethod,
-                                                                 responseBuilder,
-                                                                 responseLBS)
-import           Network.Wai.Handler.Warp                       (Port, run)
-
-import           System.Metrics.Prometheus.Concurrent.RegistryT (RegistryT,
-                                                                 sample)
-import           System.Metrics.Prometheus.Encode               (encodeMetrics)
-import           System.Metrics.Prometheus.Registry             (RegistrySample)
-
-
-type Path = [Text]
-
-
-serveHttpTextMetrics :: MonadIO m => Port -> Path -> IO RegistrySample -> m ()
-serveHttpTextMetrics port path = liftIO . run port . prometheusApp path
-
-
-serveHttpTextMetricsT :: MonadIO m => Port -> Path -> RegistryT m ()
-serveHttpTextMetricsT port path = liftIO . serveHttpTextMetrics port path =<< sample
-
-
-prometheusApp :: Path -> IO RegistrySample -> Application
-prometheusApp path runSample request respond
-    | isPrometheusRequest path request = respond =<< prometheusResponse <$> runSample
-    | otherwise = respond response404
-  where
-    prometheusResponse = responseBuilder status200 headers . encodeMetrics
-    headers = [(hContentType, "text/plain; version=0.0.4")]
-
-
-response404 :: Response
-response404 = responseLBS status404 header404 body404
-  where
-    header404 = [(hContentType, "text/plain")]
-    body404 = "404"
-
-
-isPrometheusRequest :: Path -> Request -> Bool
-isPrometheusRequest path request = isGet && matchesPath
-  where
-    matchesPath = pathInfo request == path
-    isGet = requestMethod request == methodGet
diff --git a/src/System/Metrics/Prometheus/Encode.hs b/src/System/Metrics/Prometheus/Encode.hs
deleted file mode 100644
--- a/src/System/Metrics/Prometheus/Encode.hs
+++ /dev/null
@@ -1,60 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-
-module System.Metrics.Prometheus.Encode
-       ( encodeMetrics
-       , serializeMetrics
-       ) where
-
-import           Data.ByteString.Builder                    (Builder,
-                                                             toLazyByteString)
-import           Data.ByteString.Lazy                       (ByteString)
-import           Data.Function                              (on)
-import           Data.List                                  (groupBy,
-                                                             intersperse)
-import qualified Data.Map                                   as Map
-import           Data.Monoid                                ((<>))
-
-import           System.Metrics.Prometheus.Encode.Histogram (encodeHistogram)
-import           System.Metrics.Prometheus.Encode.MetricId  (encodeDouble,
-                                                             encodeHeader,
-                                                             encodeInt,
-                                                             encodeMetricId,
-                                                             newline, space)
-import           System.Metrics.Prometheus.Metric           (MetricSample (..),
-                                                             metricSample)
-import           System.Metrics.Prometheus.Metric.Counter   (CounterSample (..))
-import           System.Metrics.Prometheus.Metric.Gauge     (GaugeSample (..))
-import           System.Metrics.Prometheus.MetricId         (MetricId (..))
-import           System.Metrics.Prometheus.Registry         (RegistrySample (..))
-
-
-serializeMetrics :: RegistrySample -> ByteString
-serializeMetrics = toLazyByteString . encodeMetrics
-
-
-encodeMetrics :: RegistrySample -> Builder
-encodeMetrics = (<> newline) . mconcat . intersperse newline . map encodeMetricGroup
-    . groupByName . Map.toList . unRegistrySample
-  where groupByName = groupBy ((==) `on` (name . fst))
-
-
-encodeMetricGroup :: [(MetricId, MetricSample)] -> Builder
-encodeMetricGroup group = encodeHeader mid sample <> newline
-    <> mconcat (intersperse newline $ map encodeMetric group)
-  where
-    (mid, sample) = head group
-
-
-encodeMetric :: (MetricId, MetricSample) -> Builder
-encodeMetric (mid, sample) = metricSample (encodeCounter mid) (encodeGauge mid)
-    (encodeHistogram mid) (encodeSummary mid) sample
-  where
-    encodeSummary = undefined
-
-
-encodeCounter :: MetricId -> CounterSample -> Builder
-encodeCounter mid counter = encodeMetricId mid <> space <> encodeInt (unCounterSample counter)
-
-
-encodeGauge :: MetricId -> GaugeSample -> Builder
-encodeGauge mid gauge = encodeMetricId mid <> space <> encodeDouble (unGaugeSample gauge)
diff --git a/src/System/Metrics/Prometheus/Encode/Histogram.hs b/src/System/Metrics/Prometheus/Encode/Histogram.hs
deleted file mode 100644
--- a/src/System/Metrics/Prometheus/Encode/Histogram.hs
+++ /dev/null
@@ -1,44 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-
-module System.Metrics.Prometheus.Encode.Histogram
-       ( encodeHistogram
-       ) where
-
-
-import           Data.ByteString.Builder                    (Builder)
-import           Data.List                                  (intersperse)
-import qualified Data.Map                                   as Map
-import           Data.Monoid                                ((<>))
-
-import           System.Metrics.Prometheus.Encode.MetricId  (encodeDouble,
-                                                             encodeInt,
-                                                             encodeLabels,
-                                                             encodeName,
-                                                             newline, space,
-                                                             textValue)
-import           System.Metrics.Prometheus.Metric.Histogram (HistogramSample (..),
-                                                             UpperBound)
-import           System.Metrics.Prometheus.MetricId         (MetricId (..),
-                                                             addLabel)
-
-
-encodeHistogram :: MetricId -> HistogramSample -> Builder
-encodeHistogram mid histogram
-    =  encodeHistogramBuckets mid histogram <> newline
-    <> n <> "_sum"   <> ls <> space <> encodeDouble (histSum histogram) <> newline
-    <> n <> "_count" <> ls <> space <> encodeInt (histCount histogram)
-  where
-    n = encodeName $ name mid
-    ls = encodeLabels $ labels mid
-
-
-encodeHistogramBuckets :: MetricId -> HistogramSample -> Builder
-encodeHistogramBuckets mid = mconcat . intersperse newline . map snd . Map.toList
-    . Map.mapWithKey (encodeHistogramBucket mid) . histBuckets
-
-
-encodeHistogramBucket :: MetricId -> UpperBound -> Double -> Builder
-encodeHistogramBucket mid upperBound count
-    = encodeName (name mid) <> "_bucket" <> encodeLabels labels' <> space <> encodeDouble count
-  where
-    labels' = addLabel "le" (textValue upperBound) (labels mid)
diff --git a/src/System/Metrics/Prometheus/Encode/MetricId.hs b/src/System/Metrics/Prometheus/Encode/MetricId.hs
deleted file mode 100644
--- a/src/System/Metrics/Prometheus/Encode/MetricId.hs
+++ /dev/null
@@ -1,115 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-
-module System.Metrics.Prometheus.Encode.MetricId
-       ( encodeHeader
-       , encodeMetricId
-       , encodeLabels
-       , encodeName
-       , textValue
-       , encodeDouble
-       , encodeInt
-       , escape
-       , newline
-       , space
-       ) where
-
-import           Data.ByteString.Builder            (Builder, byteString, char8,
-                                                     intDec)
-import           Data.List                          (intersperse)
-import           Data.Monoid                        ((<>))
-import           Data.Text                          (Text, replace)
-import           Data.Text.Encoding                 (encodeUtf8)
-import           Data.Text.Lazy                     (toStrict)
-import           Data.Text.Lazy.Builder             (toLazyText)
-import           Data.Text.Lazy.Builder.RealFloat   (FPFormat (Generic),
-                                                     formatRealFloat)
-import           Prelude                            hiding (null)
-
-import           System.Metrics.Prometheus.Metric   (MetricSample (..),
-                                                     metricSample)
-import           System.Metrics.Prometheus.MetricId (Labels (..), MetricId (..),
-                                                     Name (..), null, toList)
-
-
-encodeHeader :: MetricId -> MetricSample -> Builder
-encodeHeader mid sample
-    = "# TYPE " <> nm <> space <> encodeSampleType sample
-    -- <> "# HELP " <> nm <> space <> escape "help" <> newline <>
-  where nm = encodeName (name mid)
-
-
-encodeSampleType :: MetricSample -> Builder
-encodeSampleType = byteString . metricSample (const "counter")
-    (const "gauge") (const "histogram") (const "summary")
-
-
-encodeMetricId :: MetricId -> Builder
-encodeMetricId mid = encodeName (name mid) <> encodeLabels (labels mid)
-
-
-encodeName :: Name -> Builder
-encodeName = text . unName
-
-
-encodeLabels :: Labels -> Builder
-encodeLabels ls
-    | null ls = space
-    | otherwise =
-             openBracket
-          <> (mconcat . intersperse comma . map encodeLabel $ toList ls)
-          <> closeBracket
-
-
-encodeLabel :: (Text, Text) -> Builder
-encodeLabel (key, val) = text key <> equals <> quote <> text (escape val) <> quote
-
-
-textValue :: RealFloat f => f -> Text
-textValue x | isInfinite x && x > 0 = "+Inf"
-            | isInfinite x && x < 0 = "-Inf"
-            | isNaN x = "NaN"
-            | otherwise = toStrict . toLazyText $ formatRealFloat Generic Nothing x
-
-
-encodeDouble :: RealFloat f => f -> Builder
-encodeDouble = text . textValue
-
-
-encodeInt :: Int -> Builder
-encodeInt = intDec
-
-
-text :: Text -> Builder
-text = byteString . encodeUtf8
-
-
-escape :: Text -> Text
-escape = replace "\n" "\\n" . replace "\"" "\\\"" . replace "\\" "\\\\"
-
-
-space :: Builder
-space = char8 ' '
-
-
-newline :: Builder
-newline = char8 '\n'
-
-
-openBracket :: Builder
-openBracket = char8 '{'
-
-
-closeBracket :: Builder
-closeBracket = char8 '}'
-
-
-comma :: Builder
-comma = char8 ','
-
-
-equals :: Builder
-equals = char8 '='
-
-
-quote :: Builder
-quote = char8 '"'
diff --git a/src/System/Metrics/Prometheus/Encode/ProtocolBuffers.hs b/src/System/Metrics/Prometheus/Encode/ProtocolBuffers.hs
new file mode 100644
--- /dev/null
+++ b/src/System/Metrics/Prometheus/Encode/ProtocolBuffers.hs
@@ -0,0 +1,103 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module System.Metrics.Prometheus.Encode.ProtocolBuffers
+  ( encodeMetrics
+  , metricsRequest
+  ) where
+
+import           Control.Lens.Operators
+import           Data.ByteString.Lazy.Builder               (Builder,
+                                                             toLazyByteString)
+import qualified Data.Map                                   as Map
+import           Data.ProtoLens                             (def)
+import           Data.ProtoLens.Encoding                    (buildMessage)
+import           Network.HTTP.Client                        (Request,
+                                                             RequestBody (..),
+                                                             requestBody,
+                                                             requestHeaders)
+import           Network.Wreq.Types                         (Putable (..))
+import qualified Proto.Proto.Metrics                        as Proto
+
+import           System.Metrics.Prometheus.Metric           (MetricSample (..))
+import qualified System.Metrics.Prometheus.Metric.Counter   as Counter
+import qualified System.Metrics.Prometheus.Metric.Gauge     as Gauge
+import qualified System.Metrics.Prometheus.Metric.Histogram as Histogram
+import qualified System.Metrics.Prometheus.Metric.Summary   as Summary
+import           System.Metrics.Prometheus.MetricId         (Labels (..),
+                                                             MetricId (MetricId),
+                                                             Name (..))
+import           System.Metrics.Prometheus.Registry         (RegistrySample (..))
+
+
+instance Putable RegistrySample where
+    putPayload = (pure .) . metricsRequest
+
+
+metricsRequest :: RegistrySample -> Request -> Request
+metricsRequest s req = req
+    { requestBody    = RequestBodyLBS . toLazyByteString $ encodeMetrics s
+    , requestHeaders = contentType : requestHeaders req
+    }
+  where contentType =
+            ( "Content-Type"
+            , "application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited"
+            )
+
+
+encodeMetrics :: RegistrySample -> Builder
+encodeMetrics = Map.foldMapWithKey ((buildMessage .) . encodeMetric) . unRegistrySample
+
+
+encodeMetric :: MetricId -> MetricSample -> Proto.MetricFamily
+encodeMetric (MetricId (Name name) (Labels labels)) = go
+  where
+    base :: Proto.MetricFamily
+    base = def & Proto.name .~ name
+    baseMetric = def & Proto.label .~ labels'
+    labels' =
+      Map.foldrWithKey
+        (\n v -> ((def & Proto.name .~ n & Proto.value .~ v) :))
+        []
+        labels
+    go (CounterMetricSample (Counter.CounterSample i)) =
+      base & Proto.type' .~ Proto.COUNTER
+           & Proto.metric .~
+             [ baseMetric & Proto.counter . Proto.value .~
+                 fromIntegral i
+             ]
+    go (GaugeMetricSample (Gauge.GaugeSample i)) =
+      base & Proto.type' .~ Proto.GAUGE
+           & Proto.metric .~
+             [ baseMetric & Proto.gauge . Proto.value .~ i
+             ]
+    go (HistogramMetricSample (Histogram.HistogramSample buckets s count)) =
+      base & Proto.type' .~ Proto.HISTOGRAM
+           & Proto.metric .~
+             [ baseMetric & Proto.histogram .~
+                 (def & Proto.sampleCount .~ fromIntegral count
+                      & Proto.sampleSum .~ s
+                      & Proto.bucket .~
+                          Map.foldrWithKey
+                            (\ub c -> ((def & Proto.cumulativeCount .~
+                                                round c
+                                            & Proto.upperBound .~ ub
+                                       ) :))
+                            []
+                            buckets
+                 )
+             ]
+    go (SummaryMetricSample (Summary.SummarySample quantiles s count)) =
+      base & Proto.type' .~ Proto.SUMMARY
+           & Proto.metric .~
+             [ baseMetric & Proto.summary .~
+               (def & Proto.sampleCount .~ fromIntegral count
+                    & Proto.sampleSum .~ fromIntegral s
+                    & Proto.quantile .~
+                        Map.foldrWithKey
+                          (\q v -> ((def & Proto.quantile .~ q
+                                         & Proto.value .~ fromIntegral v
+                                    ) :))
+                          []
+                          quantiles
+               )
+             ]
diff --git a/src/System/Metrics/Prometheus/Encode/Text.hs b/src/System/Metrics/Prometheus/Encode/Text.hs
new file mode 100644
--- /dev/null
+++ b/src/System/Metrics/Prometheus/Encode/Text.hs
@@ -0,0 +1,65 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module System.Metrics.Prometheus.Encode.Text
+       ( encodeMetrics
+       ) where
+
+import           Data.ByteString.Builder                         (Builder, toLazyByteString)
+import           Data.Function                                   (on)
+import           Data.List                                       (groupBy,
+                                                                  intersperse)
+import qualified Data.Map                                        as Map
+import           Data.Monoid                                     ((<>))
+import           Network.HTTP.Client                             (Request, RequestBody (..),
+                                                                  requestBody,
+                                                                  requestHeaders)
+
+import           System.Metrics.Prometheus.Encode.Text.Histogram (encodeHistogram)
+import           System.Metrics.Prometheus.Encode.Text.MetricId  (encodeDouble,
+                                                                  encodeHeader,
+                                                                  encodeInt,
+                                                                  encodeMetricId,
+                                                                  newline,
+                                                                  space)
+import           System.Metrics.Prometheus.Metric                (MetricSample (..),
+                                                                  metricSample)
+import           System.Metrics.Prometheus.Metric.Counter        (CounterSample (..))
+import           System.Metrics.Prometheus.Metric.Gauge          (GaugeSample (..))
+import           System.Metrics.Prometheus.MetricId              (MetricId (..))
+import           System.Metrics.Prometheus.Registry              (RegistrySample (..))
+
+
+metricsRequest :: RegistrySample -> Request -> Request
+metricsRequest s req = req
+    { requestBody    = RequestBodyLBS . toLazyByteString $ encodeMetrics s
+    , requestHeaders = contentType : requestHeaders req
+    }
+  where contentType = ("Content-Type", "text/plain; version=0.0.4")
+
+
+encodeMetrics :: RegistrySample -> Builder
+encodeMetrics = (<> newline) . mconcat . intersperse newline . map encodeMetricGroup
+    . groupByName . Map.toList . unRegistrySample
+  where groupByName = groupBy ((==) `on` (name . fst))
+
+
+encodeMetricGroup :: [(MetricId, MetricSample)] -> Builder
+encodeMetricGroup group = encodeHeader mid sample <> newline
+    <> mconcat (intersperse newline $ map encodeMetric group)
+  where
+    (mid, sample) = head group
+
+
+encodeMetric :: (MetricId, MetricSample) -> Builder
+encodeMetric (mid, sample) = metricSample (encodeCounter mid) (encodeGauge mid)
+    (encodeHistogram mid) (encodeSummary mid) sample
+  where
+    encodeSummary = undefined
+
+
+encodeCounter :: MetricId -> CounterSample -> Builder
+encodeCounter mid counter = encodeMetricId mid <> space <> encodeInt (unCounterSample counter)
+
+
+encodeGauge :: MetricId -> GaugeSample -> Builder
+encodeGauge mid gauge = encodeMetricId mid <> space <> encodeDouble (unGaugeSample gauge)
diff --git a/src/System/Metrics/Prometheus/Encode/Text/Histogram.hs b/src/System/Metrics/Prometheus/Encode/Text/Histogram.hs
new file mode 100644
--- /dev/null
+++ b/src/System/Metrics/Prometheus/Encode/Text/Histogram.hs
@@ -0,0 +1,44 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module System.Metrics.Prometheus.Encode.Text.Histogram
+       ( encodeHistogram
+       ) where
+
+
+import           Data.ByteString.Builder                    (Builder)
+import           Data.List                                  (intersperse)
+import qualified Data.Map                                   as Map
+import           Data.Monoid                                ((<>))
+
+import           System.Metrics.Prometheus.Encode.Text.MetricId  (encodeDouble,
+                                                             encodeInt,
+                                                             encodeLabels,
+                                                             encodeName,
+                                                             newline, space,
+                                                             textValue)
+import           System.Metrics.Prometheus.Metric.Histogram (HistogramSample (..),
+                                                             UpperBound)
+import           System.Metrics.Prometheus.MetricId         (MetricId (..),
+                                                             addLabel)
+
+
+encodeHistogram :: MetricId -> HistogramSample -> Builder
+encodeHistogram mid histogram
+    =  encodeHistogramBuckets mid histogram <> newline
+    <> n <> "_sum"   <> ls <> space <> encodeDouble (histSum histogram) <> newline
+    <> n <> "_count" <> ls <> space <> encodeInt (histCount histogram)
+  where
+    n = encodeName $ name mid
+    ls = encodeLabels $ labels mid
+
+
+encodeHistogramBuckets :: MetricId -> HistogramSample -> Builder
+encodeHistogramBuckets mid = mconcat . intersperse newline . map snd . Map.toList
+    . Map.mapWithKey (encodeHistogramBucket mid) . histBuckets
+
+
+encodeHistogramBucket :: MetricId -> UpperBound -> Double -> Builder
+encodeHistogramBucket mid upperBound count
+    = encodeName (name mid) <> "_bucket" <> encodeLabels labels' <> space <> encodeDouble count
+  where
+    labels' = addLabel "le" (textValue upperBound) (labels mid)
diff --git a/src/System/Metrics/Prometheus/Encode/Text/MetricId.hs b/src/System/Metrics/Prometheus/Encode/Text/MetricId.hs
new file mode 100644
--- /dev/null
+++ b/src/System/Metrics/Prometheus/Encode/Text/MetricId.hs
@@ -0,0 +1,115 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module System.Metrics.Prometheus.Encode.Text.MetricId
+       ( encodeHeader
+       , encodeMetricId
+       , encodeLabels
+       , encodeName
+       , textValue
+       , encodeDouble
+       , encodeInt
+       , escape
+       , newline
+       , space
+       ) where
+
+import           Data.ByteString.Builder            (Builder, byteString, char8,
+                                                     intDec)
+import           Data.List                          (intersperse)
+import           Data.Monoid                        ((<>))
+import           Data.Text                          (Text, replace)
+import           Data.Text.Encoding                 (encodeUtf8)
+import           Data.Text.Lazy                     (toStrict)
+import           Data.Text.Lazy.Builder             (toLazyText)
+import           Data.Text.Lazy.Builder.RealFloat   (FPFormat (Generic),
+                                                     formatRealFloat)
+import           Prelude                            hiding (null)
+
+import           System.Metrics.Prometheus.Metric   (MetricSample (..),
+                                                     metricSample)
+import           System.Metrics.Prometheus.MetricId (Labels (..), MetricId (..),
+                                                     Name (..), null, toList)
+
+
+encodeHeader :: MetricId -> MetricSample -> Builder
+encodeHeader mid sample
+    = "# TYPE " <> nm <> space <> encodeSampleType sample
+    -- <> "# HELP " <> nm <> space <> escape "help" <> newline <>
+  where nm = encodeName (name mid)
+
+
+encodeSampleType :: MetricSample -> Builder
+encodeSampleType = byteString . metricSample (const "counter")
+    (const "gauge") (const "histogram") (const "summary")
+
+
+encodeMetricId :: MetricId -> Builder
+encodeMetricId mid = encodeName (name mid) <> encodeLabels (labels mid)
+
+
+encodeName :: Name -> Builder
+encodeName = text . unName
+
+
+encodeLabels :: Labels -> Builder
+encodeLabels ls
+    | null ls = space
+    | otherwise =
+             openBracket
+          <> (mconcat . intersperse comma . map encodeLabel $ toList ls)
+          <> closeBracket
+
+
+encodeLabel :: (Text, Text) -> Builder
+encodeLabel (key, val) = text key <> equals <> quote <> text (escape val) <> quote
+
+
+textValue :: RealFloat f => f -> Text
+textValue x | isInfinite x && x > 0 = "+Inf"
+            | isInfinite x && x < 0 = "-Inf"
+            | isNaN x = "NaN"
+            | otherwise = toStrict . toLazyText $ formatRealFloat Generic Nothing x
+
+
+encodeDouble :: RealFloat f => f -> Builder
+encodeDouble = text . textValue
+
+
+encodeInt :: Int -> Builder
+encodeInt = intDec
+
+
+text :: Text -> Builder
+text = byteString . encodeUtf8
+
+
+escape :: Text -> Text
+escape = replace "\n" "\\n" . replace "\"" "\\\"" . replace "\\" "\\\\"
+
+
+space :: Builder
+space = char8 ' '
+
+
+newline :: Builder
+newline = char8 '\n'
+
+
+openBracket :: Builder
+openBracket = char8 '{'
+
+
+closeBracket :: Builder
+closeBracket = char8 '}'
+
+
+comma :: Builder
+comma = char8 ','
+
+
+equals :: Builder
+equals = char8 '='
+
+
+quote :: Builder
+quote = char8 '"'
diff --git a/src/System/Metrics/Prometheus/Http/Push.hs b/src/System/Metrics/Prometheus/Http/Push.hs
new file mode 100644
--- /dev/null
+++ b/src/System/Metrics/Prometheus/Http/Push.hs
@@ -0,0 +1,28 @@
+module System.Metrics.Prometheus.Http.Push
+       ( pushHttpProtoMetrics
+       )
+       where
+
+import           Control.Concurrent                               (threadDelay)
+import           Control.Monad                                    (forever)
+import           Data.Map                                         (foldMapWithKey)
+import           Data.Text                                        (Text, unpack)
+import           Network.Wreq.Session                             (put,
+                                                                   withSession)
+import           System.Metrics.Prometheus.Encode.ProtocolBuffers ()
+import           System.Metrics.Prometheus.MetricId               (Labels (..))
+import           System.Metrics.Prometheus.Registry               (RegistrySample)
+
+-- | Push metrics to a pushgateway.
+pushHttpProtoMetrics :: String            -- ^ The base URL of the pushgateway, including the port number.
+                     -> Text              -- ^ The name of this job.
+                     -> Labels            -- ^ The label set to use as a grouping key for these metrics.
+                     -> Int               -- ^ Push frequency, in microseconds.
+                     -> IO RegistrySample -- ^ The action to get the latest metrics.
+                     -> IO ()
+pushHttpProtoMetrics base job (Labels ls) frequency get =
+    withSession $ \session -> forever $
+      get >>= put session url >> threadDelay frequency
+  where
+    url = base ++ "/metrics/job/" ++ unpack job ++
+        foldMapWithKey (\k v -> "/" ++ unpack k ++ "/" ++ unpack v) ls
diff --git a/src/System/Metrics/Prometheus/Http/Scrape.hs b/src/System/Metrics/Prometheus/Http/Scrape.hs
new file mode 100644
--- /dev/null
+++ b/src/System/Metrics/Prometheus/Http/Scrape.hs
@@ -0,0 +1,64 @@
+{-# LANGUAGE OverloadedStrings #-}
+
+module System.Metrics.Prometheus.Http.Scrape
+       ( Path
+       , serveHttpTextMetrics
+       , serveHttpTextMetricsT
+       , prometheusApp
+       )
+       where
+
+import           Control.Monad.IO.Class                         (MonadIO,
+                                                                 liftIO)
+import           Data.Text                                      (Text)
+import           Network.HTTP.Types                             (hContentType,
+                                                                 methodGet,
+                                                                 status200,
+                                                                 status404)
+import           Network.Wai                                    (Application,
+                                                                 Request,
+                                                                 Response,
+                                                                 pathInfo,
+                                                                 requestMethod,
+                                                                 responseBuilder,
+                                                                 responseLBS)
+import           Network.Wai.Handler.Warp                       (Port, run)
+
+import           System.Metrics.Prometheus.Concurrent.RegistryT (RegistryT,
+                                                                 sample)
+import           System.Metrics.Prometheus.Encode.Text          (encodeMetrics)
+import           System.Metrics.Prometheus.Registry             (RegistrySample)
+
+
+type Path = [Text]
+
+
+serveHttpTextMetrics :: MonadIO m => Port -> Path -> IO RegistrySample -> m ()
+serveHttpTextMetrics port path = liftIO . run port . prometheusApp path
+
+
+serveHttpTextMetricsT :: MonadIO m => Port -> Path -> RegistryT m ()
+serveHttpTextMetricsT port path = liftIO . serveHttpTextMetrics port path =<< sample
+
+
+prometheusApp :: Path -> IO RegistrySample -> Application
+prometheusApp path runSample request respond
+    | isPrometheusRequest path request = respond =<< prometheusResponse <$> runSample
+    | otherwise = respond response404
+  where
+    prometheusResponse = responseBuilder status200 headers . encodeMetrics
+    headers = [(hContentType, "text/plain; version=0.0.4")]
+
+
+response404 :: Response
+response404 = responseLBS status404 header404 body404
+  where
+    header404 = [(hContentType, "text/plain")]
+    body404 = "404"
+
+
+isPrometheusRequest :: Path -> Request -> Bool
+isPrometheusRequest path request = isGet && matchesPath
+  where
+    matchesPath = pathInfo request == path
+    isGet = requestMethod request == methodGet
diff --git a/src/System/Metrics/Prometheus/Registry.hs b/src/System/Metrics/Prometheus/Registry.hs
--- a/src/System/Metrics/Prometheus/Registry.hs
+++ b/src/System/Metrics/Prometheus/Registry.hs
@@ -1,5 +1,4 @@
 {-# LANGUAGE DeriveDataTypeable #-}
-{-# LANGUAGE OverloadedStrings  #-}
 
 module System.Metrics.Prometheus.Registry
        ( Registry
@@ -25,9 +24,9 @@
 import           System.Metrics.Prometheus.Metric.Histogram (Histogram,
                                                              UpperBound)
 import qualified System.Metrics.Prometheus.Metric.Histogram as Histogram
-import           System.Metrics.Prometheus.MetricId         (Labels,
+import           System.Metrics.Prometheus.MetricId         (Labels (..),
                                                              MetricId (MetricId),
-                                                             Name)
+                                                             Name (..))
 
 newtype Registry = Registry { unRegistry :: Map MetricId Metric }
 newtype RegistrySample = RegistrySample { unRegistrySample :: Map MetricId MetricSample }
