diff --git a/OpenTelemetry.sln b/OpenTelemetry.sln
index 84d80c5c51c..d1761243800 100644
--- a/OpenTelemetry.sln
+++ b/OpenTelemetry.sln
@@ -208,7 +208,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "exception-reporting", "docs
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "customizing-the-sdk", "docs\trace\customizing-the-sdk\customizing-the-sdk.csproj", "{64E3D8BB-93AB-4571-93F7-ED8D64DFFD06}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "getting-started", "docs\metrics\getting-started\getting-started.csproj", "{DFB0AD2F-11BE-4BCD-A77B-1018C3344FA8}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "getting-started", "docs\metrics\getting-started\getting-started.csproj", "{DFB0AD2F-11BE-4BCD-A77B-1018C3344FA8}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OpenTelemetry.Exporter.Prometheus", "src\OpenTelemetry.Exporter.Prometheus\OpenTelemetry.Exporter.Prometheus.csproj", "{52158A12-E7EF-45A1-859F-06F9B17410CB}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -412,6 +414,10 @@ Global
 		{DFB0AD2F-11BE-4BCD-A77B-1018C3344FA8}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{DFB0AD2F-11BE-4BCD-A77B-1018C3344FA8}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{DFB0AD2F-11BE-4BCD-A77B-1018C3344FA8}.Release|Any CPU.Build.0 = Release|Any CPU
+		{52158A12-E7EF-45A1-859F-06F9B17410CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{52158A12-E7EF-45A1-859F-06F9B17410CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{52158A12-E7EF-45A1-859F-06F9B17410CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{52158A12-E7EF-45A1-859F-06F9B17410CB}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE
diff --git a/examples/Console/Examples.Console.csproj b/examples/Console/Examples.Console.csproj
index 33a1f6a4191..84ecf4f5b71 100644
--- a/examples/Console/Examples.Console.csproj
+++ b/examples/Console/Examples.Console.csproj
@@ -36,5 +36,6 @@
     <ProjectReference Include="$(RepoRoot)\src\OpenTelemetry.Exporter.Zipkin\OpenTelemetry.Exporter.Zipkin.csproj" />
     <ProjectReference Include="$(RepoRoot)\src\OpenTelemetry.Exporter.Jaeger\OpenTelemetry.Exporter.Jaeger.csproj" />
     <ProjectReference Include="$(RepoRoot)\src\OpenTelemetry.Exporter.InMemory\OpenTelemetry.Exporter.InMemory.csproj" />
+    <ProjectReference Include="$(RepoRoot)\src\OpenTelemetry.Exporter.Prometheus\OpenTelemetry.Exporter.Prometheus.csproj" />
   </ItemGroup>
 </Project>
diff --git a/examples/Console/Program.cs b/examples/Console/Program.cs
index 3b3b061869f..324e25aa940 100644
--- a/examples/Console/Program.cs
+++ b/examples/Console/Program.cs
@@ -46,7 +46,7 @@ public static void Main(string[] args)
                 .MapResult(
                     (JaegerOptions options) => TestJaegerExporter.Run(options.Host, options.Port),
                     (ZipkinOptions options) => TestZipkinExporter.Run(options.Uri),
-                    (PrometheusOptions options) => TestPrometheusExporter.Run(options.Port, options.PushIntervalInSecs, options.DurationInMins),
+                    (PrometheusOptions options) => TestPrometheusExporter.Run(options.Port, options.DurationInMins),
                     (MetricsOptions options) => TestMetrics.Run(options),
                     (GrpcNetClientOptions options) => TestGrpcNetClient.Run(),
                     (HttpClientOptions options) => TestHttpClient.Run(),
@@ -83,13 +83,10 @@ internal class ZipkinOptions
     [Verb("prometheus", HelpText = "Specify the options required to test Prometheus")]
     internal class PrometheusOptions
     {
-        [Option('i', "pushIntervalInSecs", Default = 15, HelpText = "The interval at which Push controller pushes metrics.", Required = false)]
-        public int PushIntervalInSecs { get; set; }
-
         [Option('p', "port", Default = 9184, HelpText = "The port to expose metrics. The endpoint will be http://localhost:port/metrics (This is the port from which your Prometheus server scraps metrics from.)", Required = false)]
         public int Port { get; set; }
 
-        [Option('d', "duration", Default = 2, HelpText = "Total duration in minutes to run the demo. Run atleast for a min to see metrics flowing.", Required = false)]
+        [Option('d', "duration", Default = 2, HelpText = "Total duration in minutes to run the demo.", Required = false)]
         public int DurationInMins { get; set; }
     }
 
diff --git a/examples/Console/TestPrometheusExporter.cs b/examples/Console/TestPrometheusExporter.cs
index 098846b4793..34ef6efcf08 100644
--- a/examples/Console/TestPrometheusExporter.cs
+++ b/examples/Console/TestPrometheusExporter.cs
@@ -17,18 +17,22 @@
 using System;
 using System.Collections.Generic;
 using System.Diagnostics;
+using System.Diagnostics.Metrics;
+using System.Threading;
 using System.Threading.Tasks;
 using OpenTelemetry;
+using OpenTelemetry.Metrics;
 using OpenTelemetry.Trace;
 
 namespace Examples.Console
 {
     internal class TestPrometheusExporter
     {
-        internal static object Run(int port, int pushIntervalInSecs, int totalDurationInMins)
-        {
-            System.Console.WriteLine($"OpenTelemetry Prometheus Exporter is making metrics available at http://localhost:{port}/metrics/");
+        private static readonly Meter MyMeter = new Meter("TestMeter", "0.0.1");
+        private static readonly Counter<long> Counter = MyMeter.CreateCounter<long>("counter");
 
+        internal static object Run(int port, int totalDurationInMins)
+        {
             /*
             Following is sample prometheus.yml config. Adjust port,interval as needed.
 
@@ -42,9 +46,37 @@ internal static object Run(int port, int pushIntervalInSecs, int totalDurationIn
                 static_configs:
                 - targets: ['localhost:9184']
             */
-            System.Console.WriteLine("Press Enter key to exit.");
-            System.Console.ReadLine();
+            using var meterProvider = Sdk.CreateMeterProviderBuilder()
+                .AddSource("TestMeter")
+                .AddPrometheusExporter(opt => opt.Url = $"http://localhost:{port}/metrics/")
+                .Build();
+
+            using var token = new CancellationTokenSource();
+            Task writeMetricTask = new Task(() =>
+            {
+                while (!token.IsCancellationRequested)
+                {
+                    Counter.Add(
+                                10,
+                                new KeyValuePair<string, object>("tag1", "value1"),
+                                new KeyValuePair<string, object>("tag2", "value2"));
 
+                    Counter.Add(
+                                100,
+                                new KeyValuePair<string, object>("tag1", "anothervalue"),
+                                new KeyValuePair<string, object>("tag2", "somethingelse"));
+                    Task.Delay(10).Wait();
+                }
+            });
+            writeMetricTask.Start();
+
+            token.CancelAfter(totalDurationInMins * 60 * 1000);
+
+            System.Console.WriteLine($"OpenTelemetry Prometheus Exporter is making metrics available at http://localhost:{port}/metrics/");
+            System.Console.WriteLine($"Press Enter key to exit now or will exit automatically after {totalDurationInMins} minutes.");
+            System.Console.ReadLine();
+            token.Cancel();
+            System.Console.WriteLine("Exiting...");
             return null;
         }
     }
diff --git a/src/OpenTelemetry.Exporter.Prometheus/Implementation/PrometheusExporterEventSource.cs b/src/OpenTelemetry.Exporter.Prometheus/Implementation/PrometheusExporterEventSource.cs
new file mode 100644
index 00000000000..f533884005d
--- /dev/null
+++ b/src/OpenTelemetry.Exporter.Prometheus/Implementation/PrometheusExporterEventSource.cs
@@ -0,0 +1,76 @@
+// <copyright file="PrometheusExporterEventSource.cs" company="OpenTelemetry Authors">
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// </copyright>
+
+using System;
+using System.Diagnostics.Tracing;
+using OpenTelemetry.Internal;
+
+namespace OpenTelemetry.Exporter.Prometheus.Implementation
+{
+    /// <summary>
+    /// EventSource events emitted from the project.
+    /// </summary>
+    [EventSource(Name = "OpenTelemetry-Exporter-Prometheus")]
+    internal class PrometheusExporterEventSource : EventSource
+    {
+        public static PrometheusExporterEventSource Log = new PrometheusExporterEventSource();
+
+        [NonEvent]
+        public void FailedExport(Exception ex)
+        {
+            if (this.IsEnabled(EventLevel.Error, (EventKeywords)(-1)))
+            {
+                this.FailedExport(ex.ToInvariantString());
+            }
+        }
+
+        [NonEvent]
+        public void FailedShutdown(Exception ex)
+        {
+            if (this.IsEnabled(EventLevel.Error, (EventKeywords)(-1)))
+            {
+                this.FailedShutdown(ex.ToInvariantString());
+            }
+        }
+
+        [NonEvent]
+        public void CanceledExport(Exception ex)
+        {
+            if (this.IsEnabled(EventLevel.Error, (EventKeywords)(-1)))
+            {
+                this.CanceledExport(ex.ToInvariantString());
+            }
+        }
+
+        [Event(1, Message = "Failed to export metrics: '{0}'", Level = EventLevel.Error)]
+        public void FailedExport(string exception)
+        {
+            this.WriteEvent(1, exception);
+        }
+
+        [Event(2, Message = "Canceled to export metrics: '{0}'", Level = EventLevel.Error)]
+        public void CanceledExport(string exception)
+        {
+            this.WriteEvent(2, exception);
+        }
+
+        [Event(3, Message = "Failed to shutdown Metrics server '{0}'", Level = EventLevel.Error)]
+        public void FailedShutdown(string exception)
+        {
+            this.WriteEvent(3, exception);
+        }
+    }
+}
diff --git a/src/OpenTelemetry.Exporter.Prometheus/Implementation/PrometheusMetricBuilder.cs b/src/OpenTelemetry.Exporter.Prometheus/Implementation/PrometheusMetricBuilder.cs
new file mode 100644
index 00000000000..a11c8e5131d
--- /dev/null
+++ b/src/OpenTelemetry.Exporter.Prometheus/Implementation/PrometheusMetricBuilder.cs
@@ -0,0 +1,276 @@
+// <copyright file="PrometheusMetricBuilder.cs" company="OpenTelemetry Authors">
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// </copyright>
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Text;
+#if NET452
+using OpenTelemetry.Internal;
+#endif
+
+namespace OpenTelemetry.Exporter.Prometheus.Implementation
+{
+    internal class PrometheusMetricBuilder
+    {
+        public const string ContentType = "text/plain; version = 0.0.4";
+
+        private static readonly char[] FirstCharacterNameCharset =
+        {
+            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+            '_', ':',
+        };
+
+        private static readonly char[] NameCharset =
+        {
+            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+            '_', ':',
+        };
+
+        private static readonly char[] FirstCharacterLabelCharset =
+        {
+            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+            '_',
+        };
+
+        private static readonly char[] LabelCharset =
+        {
+            'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
+            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
+            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
+            '_',
+        };
+
+        private readonly ICollection<PrometheusMetricValueBuilder> values = new List<PrometheusMetricValueBuilder>();
+
+        private string name;
+        private string description;
+        private string type;
+
+        public PrometheusMetricBuilder WithName(string name)
+        {
+            this.name = name;
+            return this;
+        }
+
+        public PrometheusMetricBuilder WithDescription(string description)
+        {
+            this.description = description;
+            return this;
+        }
+
+        public PrometheusMetricBuilder WithType(string type)
+        {
+            this.type = type;
+            return this;
+        }
+
+        public PrometheusMetricValueBuilder AddValue()
+        {
+            var val = new PrometheusMetricValueBuilder();
+
+            this.values.Add(val);
+
+            return val;
+        }
+
+        public void Write(StreamWriter writer)
+        {
+            // https://prometheus.io/docs/instrumenting/exposition_formats/
+
+            if (string.IsNullOrEmpty(this.name))
+            {
+                throw new InvalidOperationException("Metric name should not be empty");
+            }
+
+            this.name = GetSafeMetricName(this.name);
+
+            if (!string.IsNullOrEmpty(this.description))
+            {
+                // Lines with a # as the first non-whitespace character are comments.
+                // They are ignored unless the first token after # is either HELP or TYPE.
+                // Those lines are treated as follows: If the token is HELP, at least one
+                // more token is expected, which is the metric name. All remaining tokens
+                // are considered the docstring for that metric name. HELP lines may contain
+                // any sequence of UTF-8 characters (after the metric name), but the backslash
+                // and the line feed characters have to be escaped as \\ and \n, respectively.
+                // Only one HELP line may exist for any given metric name.
+
+                writer.Write("# HELP ");
+                writer.Write(this.name);
+                writer.Write(GetSafeMetricDescription(this.description));
+                writer.Write("\n");
+            }
+
+            if (!string.IsNullOrEmpty(this.type))
+            {
+                // If the token is TYPE, exactly two more tokens are expected. The first is the
+                // metric name, and the second is either counter, gauge, histogram, summary, or
+                // untyped, defining the type for the metric of that name. Only one TYPE line
+                // may exist for a given metric name. The TYPE line for a metric name must appear
+                // before the first sample is reported for that metric name. If there is no TYPE
+                // line for a metric name, the type is set to untyped.
+
+                writer.Write("# TYPE ");
+                writer.Write(this.name);
+                writer.Write(" ");
+                writer.Write(this.type);
+                writer.Write("\n");
+            }
+
+            // The remaining lines describe samples (one per line) using the following syntax (EBNF):
+            // metric_name [
+            //   "{" label_name "=" `"` label_value `"` { "," label_name "=" `"` label_value `"` } [ "," ] "}"
+            // ] value [ timestamp ]
+            // In the sample syntax:
+
+            var now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds().ToString(CultureInfo.InvariantCulture);
+
+            foreach (var m in this.values)
+            {
+                // metric_name and label_name carry the usual Prometheus expression language restrictions.
+                writer.Write(m.Name != null ? GetSafeMetricName(m.Name) : this.name);
+
+                // label_value can be any sequence of UTF-8 characters, but the backslash
+                // (\, double-quote ("}, and line feed (\n) characters have to be escaped
+                // as \\, \", and \n, respectively.
+
+                if (m.Labels.Count > 0)
+                {
+                    writer.Write(@"{");
+                    writer.Write(string.Join(",", m.Labels.Select(x => GetLabelAndValue(x.Item1, x.Item2))));
+                    writer.Write(@"}");
+                }
+
+                // value is a float represented as required by Go's ParseFloat() function. In addition to
+                // standard numerical values, Nan, +Inf, and -Inf are valid values representing not a number,
+                // positive infinity, and negative infinity, respectively.
+                writer.Write(" ");
+                writer.Write(m.Value.ToString(CultureInfo.InvariantCulture));
+                writer.Write(" ");
+
+                // The timestamp is an int64 (milliseconds since epoch, i.e. 1970-01-01 00:00:00 UTC, excluding
+                // leap seconds), represented as required by Go's ParseInt() function.
+                writer.Write(now);
+
+                // Prometheus' text-based format is line oriented. Lines are separated
+                // by a line feed character (\n). The last line must end with a line
+                // feed character. Empty lines are ignored.
+                writer.Write("\n");
+            }
+
+            static string GetLabelAndValue(string label, string value)
+            {
+                var safeKey = GetSafeLabelName(label);
+                var safeValue = GetSafeLabelValue(value);
+                return $"{safeKey}=\"{safeValue}\"";
+            }
+        }
+
+        private static string GetSafeName(string name, char[] firstCharNameCharset, char[] charNameCharset)
+        {
+            // https://prometheus.io/docs/concepts/data_model/#metric-names-and-labels
+            //
+            // Metric names and labels
+            // Every time series is uniquely identified by its metric name and a set of key-value pairs, also known as labels.
+            // The metric name specifies the general feature of a system that is measured (e.g. http_requests_total - the total number of HTTP requests received). It may contain ASCII letters and digits, as well as underscores and colons. It must match the regex [a-zA-Z_:][a-zA-Z0-9_:]*.
+            // Note: The colons are reserved for user defined recording rules. They should not be used by exporters or direct instrumentation.
+            // Labels enable Prometheus's dimensional data model: any given combination of labels for the same metric name identifies a particular dimensional instantiation of that metric (for example: all HTTP requests that used the method POST to the /api/tracks handler). The query language allows filtering and aggregation based on these dimensions. Changing any label value, including adding or removing a label, will create a new time series.
+            // Label names may contain ASCII letters, numbers, as well as underscores. They must match the regex [a-zA-Z_][a-zA-Z0-9_]*. Label names beginning with __ are reserved for internal use.
+            // Label values may contain any Unicode characters.
+
+            var sb = new StringBuilder();
+            var firstChar = name[0];
+
+            sb.Append(firstCharNameCharset.Contains(firstChar)
+                ? firstChar
+                : GetSafeChar(char.ToLowerInvariant(firstChar), firstCharNameCharset));
+
+            for (var i = 1; i < name.Length; ++i)
+            {
+                sb.Append(GetSafeChar(name[i], charNameCharset));
+            }
+
+            return sb.ToString();
+
+            static char GetSafeChar(char c, char[] charset) => charset.Contains(c) ? c : '_';
+        }
+
+        private static string GetSafeMetricName(string name) => GetSafeName(name, FirstCharacterNameCharset, NameCharset);
+
+        private static string GetSafeLabelName(string name) => GetSafeName(name, FirstCharacterLabelCharset, LabelCharset);
+
+        private static string GetSafeLabelValue(string value)
+        {
+            // label_value can be any sequence of UTF-8 characters, but the backslash
+            // (\), double-quote ("), and line feed (\n) characters have to be escaped
+            // as \\, \", and \n, respectively.
+
+            var result = value.Replace("\\", "\\\\");
+            result = result.Replace("\n", "\\n");
+            result = result.Replace("\"", "\\\"");
+
+            return result;
+        }
+
+        private static string GetSafeMetricDescription(string description)
+        {
+            // HELP lines may contain any sequence of UTF-8 characters(after the metric name), but the backslash
+            // and the line feed characters have to be escaped as \\ and \n, respectively.Only one HELP line may
+            // exist for any given metric name.
+            var result = description.Replace(@"\", @"\\");
+            result = result.Replace("\n", @"\n");
+
+            return result;
+        }
+
+        internal class PrometheusMetricValueBuilder
+        {
+            public readonly ICollection<Tuple<string, string>> Labels = new List<Tuple<string, string>>();
+            public double Value;
+            public string Name;
+
+            public PrometheusMetricValueBuilder WithLabel(string name, string value)
+            {
+                this.Labels.Add(new Tuple<string, string>(name, value));
+                return this;
+            }
+
+            public PrometheusMetricValueBuilder WithValue(long metricValue)
+            {
+                this.Value = metricValue;
+                return this;
+            }
+
+            public PrometheusMetricValueBuilder WithValue(double metricValue)
+            {
+                this.Value = metricValue;
+                return this;
+            }
+
+            public PrometheusMetricValueBuilder WithName(string name)
+            {
+                this.Name = name;
+                return this;
+            }
+        }
+    }
+}
diff --git a/src/OpenTelemetry.Exporter.Prometheus/MeterProviderBuilderExtensions.cs b/src/OpenTelemetry.Exporter.Prometheus/MeterProviderBuilderExtensions.cs
new file mode 100644
index 00000000000..b7e307ada2b
--- /dev/null
+++ b/src/OpenTelemetry.Exporter.Prometheus/MeterProviderBuilderExtensions.cs
@@ -0,0 +1,49 @@
+// <copyright file="MeterProviderBuilderExtensions.cs" company="OpenTelemetry Authors">
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// </copyright>
+
+using System;
+using OpenTelemetry.Exporter;
+
+namespace OpenTelemetry.Metrics
+{
+    public static class MeterProviderBuilderExtensions
+    {
+        /// <summary>
+        /// Adds Console exporter to the TracerProvider.
+        /// </summary>
+        /// <param name="builder"><see cref="MeterProviderBuilder"/> builder to use.</param>
+        /// <param name="configure">Exporter configuration options.</param>
+        /// <returns>The instance of <see cref="MeterProviderBuilder"/> to chain the calls.</returns>
+        [System.Diagnostics.CodeAnalysis.SuppressMessage("Reliability", "CA2000:Dispose objects before losing scope", Justification = "The objects should not be disposed.")]
+        public static MeterProviderBuilder AddPrometheusExporter(this MeterProviderBuilder builder, Action<PrometheusExporterOptions> configure = null)
+        {
+            if (builder == null)
+            {
+                throw new ArgumentNullException(nameof(builder));
+            }
+
+            var options = new PrometheusExporterOptions();
+            configure?.Invoke(options);
+            var exporter = new PrometheusExporter(options);
+            var pullMetricProcessor = new PullMetricProcessor(exporter, false);
+            exporter.MakePullRequest = pullMetricProcessor.PullRequest;
+
+            var metricsHttpServer = new PrometheusExporterMetricsHttpServer(exporter);
+            metricsHttpServer.Start();
+            return builder.AddMetricProcessor(pullMetricProcessor);
+        }
+    }
+}
diff --git a/src/OpenTelemetry.Exporter.Prometheus/OpenTelemetry.Exporter.Prometheus.csproj b/src/OpenTelemetry.Exporter.Prometheus/OpenTelemetry.Exporter.Prometheus.csproj
new file mode 100644
index 00000000000..6ee2ac3fa22
--- /dev/null
+++ b/src/OpenTelemetry.Exporter.Prometheus/OpenTelemetry.Exporter.Prometheus.csproj
@@ -0,0 +1,26 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <TargetFrameworks>netstandard2.0;net461</TargetFrameworks>
+    <Description>Console exporter for OpenTelemetry .NET</Description>
+    <PackageTags>$(PackageTags);prometheus;metrics</PackageTags>
+  </PropertyGroup>
+
+  <PropertyGroup>
+    <NoWarn>$(NoWarn),1591</NoWarn>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="$(RepoRoot)\src\OpenTelemetry\OpenTelemetry.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <Compile Include="$(RepoRoot)\src\OpenTelemetry\Internal\ServiceProviderExtensions.cs" Link="Includes\ServiceProviderExtensions.cs" />
+    <Compile Include="$(RepoRoot)\src\OpenTelemetry.Api\Internal\ExceptionExtensions.cs" Link="Includes\ExceptionExtensions.cs" />
+  </ItemGroup>
+
+  <ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
+    <PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="$(MicrosoftAspNetCoreHttpAbstractionsPkgVer)" />
+  </ItemGroup>
+
+</Project>
diff --git a/src/OpenTelemetry.Exporter.Prometheus/PrometheusExporter.cs b/src/OpenTelemetry.Exporter.Prometheus/PrometheusExporter.cs
new file mode 100644
index 00000000000..ea51da4cf56
--- /dev/null
+++ b/src/OpenTelemetry.Exporter.Prometheus/PrometheusExporter.cs
@@ -0,0 +1,50 @@
+// <copyright file="PrometheusExporter.cs" company="OpenTelemetry Authors">
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// </copyright>
+
+using System;
+using System.Collections.Generic;
+using System.Threading;
+using System.Threading.Tasks;
+using OpenTelemetry.Metrics;
+
+namespace OpenTelemetry.Exporter
+{
+    /// <summary>
+    /// Exporter of OpenTelemetry metrics to Prometheus.
+    /// </summary>
+    public class PrometheusExporter : BaseExporter<MetricItem>
+    {
+        internal readonly PrometheusExporterOptions Options;
+        internal Batch<MetricItem> Batch;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="PrometheusExporter"/> class.
+        /// </summary>
+        /// <param name="options">Options for the exporter.</param>
+        public PrometheusExporter(PrometheusExporterOptions options)
+        {
+            this.Options = options;
+        }
+
+        internal Action MakePullRequest { get; set; }
+
+        public override ExportResult Export(in Batch<MetricItem> batch)
+        {
+            this.Batch = batch;
+            return ExportResult.Success;
+        }
+    }
+}
diff --git a/src/OpenTelemetry.Exporter.Prometheus/PrometheusExporterExtensions.cs b/src/OpenTelemetry.Exporter.Prometheus/PrometheusExporterExtensions.cs
new file mode 100644
index 00000000000..675acb6c55e
--- /dev/null
+++ b/src/OpenTelemetry.Exporter.Prometheus/PrometheusExporterExtensions.cs
@@ -0,0 +1,145 @@
+// <copyright file="PrometheusExporterExtensions.cs" company="OpenTelemetry Authors">
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// </copyright>
+
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using OpenTelemetry.Exporter.Prometheus.Implementation;
+using OpenTelemetry.Metrics;
+
+namespace OpenTelemetry.Exporter
+{
+    /// <summary>
+    /// Helper to write metrics collection from exporter in Prometheus format.
+    /// </summary>
+    public static class PrometheusExporterExtensions
+    {
+        private const string PrometheusCounterType = "counter";
+        private const string PrometheusSummaryType = "summary";
+        private const string PrometheusSummarySumPostFix = "_sum";
+        private const string PrometheusSummaryCountPostFix = "_count";
+        private const string PrometheusSummaryQuantileLabelName = "quantile";
+        private const string PrometheusSummaryQuantileLabelValueForMin = "0";
+        private const string PrometheusSummaryQuantileLabelValueForMax = "1";
+
+        /// <summary>
+        /// Serialize to Prometheus Format.
+        /// </summary>
+        /// <param name="exporter">Prometheus Exporter.</param>
+        /// <param name="writer">StreamWriter to write to.</param>
+        public static void WriteMetricsCollection(this PrometheusExporter exporter, StreamWriter writer)
+        {
+            foreach (var metricItem in exporter.Batch)
+            {
+                foreach (var metric in metricItem.Metrics)
+                {
+                    var builder = new PrometheusMetricBuilder()
+                    .WithName(metric.Name)
+                    .WithDescription(metric.Name);
+
+                    if (metric is ISumMetric sumMetric)
+                    {
+                        if (sumMetric.Sum.Value is double doubleSum)
+                        {
+                            WriteSum(writer, builder, metric.Attributes, doubleSum);
+                        }
+                        else if (sumMetric.Sum.Value is long longSum)
+                        {
+                            WriteSum(writer, builder, metric.Attributes, longSum);
+                        }
+                    }
+                }
+            }
+        }
+
+        /// <summary>
+        /// Get Metrics Collection as a string.
+        /// </summary>
+        /// <param name="exporter"> Prometheus Exporter. </param>
+        /// <returns>Metrics serialized to string in Prometheus format.</returns>
+        public static string GetMetricsCollection(this PrometheusExporter exporter)
+        {
+            using var stream = new MemoryStream();
+            using var writer = new StreamWriter(stream);
+            WriteMetricsCollection(exporter, writer);
+            writer.Flush();
+
+            return Encoding.UTF8.GetString(stream.ToArray(), 0, (int)stream.Length);
+        }
+
+        private static void WriteSum(StreamWriter writer, PrometheusMetricBuilder builder, IEnumerable<KeyValuePair<string, object>> labels, double doubleValue)
+        {
+            builder = builder.WithType(PrometheusCounterType);
+
+            var metricValueBuilder = builder.AddValue();
+            metricValueBuilder = metricValueBuilder.WithValue(doubleValue);
+
+            foreach (var label in labels)
+            {
+                metricValueBuilder.WithLabel(label.Key, label.Value.ToString());
+            }
+
+            builder.Write(writer);
+        }
+
+        private static void WriteSummary(
+            StreamWriter writer,
+            PrometheusMetricBuilder builder,
+            IEnumerable<KeyValuePair<string, string>> labels,
+            string metricName,
+            double sum,
+            long count,
+            double min,
+            double max)
+        {
+            builder = builder.WithType(PrometheusSummaryType);
+
+            foreach (var label in labels)
+            {
+                /* For Summary we emit one row for Sum, Count, Min, Max.
+                Min,Max exports as quantile 0 and 1.
+                In future, when OpenTelemetry implements more aggregation
+                algorithms, this section will need to be revisited.
+                Sample output:
+                MyMeasure_sum{dim1="value1"} 750 1587013352982
+                MyMeasure_count{dim1="value1"} 5 1587013352982
+                MyMeasure{dim1="value2",quantile="0"} 150 1587013352982
+                MyMeasure{dim1="value2",quantile="1"} 150 1587013352982
+                */
+                builder.AddValue()
+                    .WithName(metricName + PrometheusSummarySumPostFix)
+                    .WithLabel(label.Key, label.Value)
+                    .WithValue(sum);
+                builder.AddValue()
+                    .WithName(metricName + PrometheusSummaryCountPostFix)
+                    .WithLabel(label.Key, label.Value)
+                    .WithValue(count);
+                builder.AddValue()
+                    .WithName(metricName)
+                    .WithLabel(label.Key, label.Value)
+                    .WithLabel(PrometheusSummaryQuantileLabelName, PrometheusSummaryQuantileLabelValueForMin)
+                    .WithValue(min);
+                builder.AddValue()
+                    .WithName(metricName)
+                    .WithLabel(label.Key, label.Value)
+                    .WithLabel(PrometheusSummaryQuantileLabelName, PrometheusSummaryQuantileLabelValueForMax)
+                    .WithValue(max);
+            }
+
+            builder.Write(writer);
+        }
+    }
+}
diff --git a/src/OpenTelemetry.Exporter.Prometheus/PrometheusExporterMetricsHttpServer.cs b/src/OpenTelemetry.Exporter.Prometheus/PrometheusExporterMetricsHttpServer.cs
new file mode 100644
index 00000000000..73266aba29a
--- /dev/null
+++ b/src/OpenTelemetry.Exporter.Prometheus/PrometheusExporterMetricsHttpServer.cs
@@ -0,0 +1,153 @@
+// <copyright file="PrometheusExporterMetricsHttpServer.cs" company="OpenTelemetry Authors">
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// </copyright>
+
+using System;
+using System.IO;
+using System.Net;
+using System.Threading;
+using System.Threading.Tasks;
+using OpenTelemetry.Exporter.Prometheus.Implementation;
+
+namespace OpenTelemetry.Exporter
+{
+    /// <summary>
+    /// A HTTP listener used to expose Prometheus metrics.
+    /// </summary>
+    public class PrometheusExporterMetricsHttpServer : IDisposable
+    {
+        private readonly PrometheusExporter exporter;
+        private readonly HttpListener httpListener = new HttpListener();
+        private readonly object syncObject = new object();
+
+        private CancellationTokenSource tokenSource;
+        private Task workerThread;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="PrometheusExporterMetricsHttpServer"/> class.
+        /// </summary>
+        /// <param name="exporter">The <see cref="PrometheusExporter"/> instance.</param>
+        public PrometheusExporterMetricsHttpServer(PrometheusExporter exporter)
+        {
+            this.exporter = exporter ?? throw new ArgumentNullException(nameof(exporter));
+            this.httpListener.Prefixes.Add(exporter.Options.Url);
+        }
+
+        /// <summary>
+        /// Start exporter.
+        /// </summary>
+        /// <param name="token">An optional <see cref="CancellationToken"/> that can be used to stop the htto server.</param>
+        public void Start(CancellationToken token = default)
+        {
+            lock (this.syncObject)
+            {
+                if (this.tokenSource != null)
+                {
+                    return;
+                }
+
+                // link the passed in token if not null
+                this.tokenSource = token == default ?
+                    new CancellationTokenSource() :
+                    CancellationTokenSource.CreateLinkedTokenSource(token);
+
+                this.workerThread = Task.Factory.StartNew(this.WorkerThread, default, TaskCreationOptions.LongRunning, TaskScheduler.Default);
+            }
+        }
+
+        /// <summary>
+        /// Stop exporter.
+        /// </summary>
+        public void Stop()
+        {
+            lock (this.syncObject)
+            {
+                if (this.tokenSource == null)
+                {
+                    return;
+                }
+
+                this.tokenSource.Cancel();
+                this.workerThread.Wait();
+                this.tokenSource = null;
+            }
+        }
+
+        /// <inheritdoc/>
+        public void Dispose()
+        {
+            this.Dispose(true);
+            GC.SuppressFinalize(this);
+        }
+
+        /// <summary>
+        /// Releases the unmanaged resources used by this class and optionally releases the managed resources.
+        /// </summary>
+        /// <param name="disposing"><see langword="true"/> to release both managed and unmanaged resources; <see langword="false"/> to release only unmanaged resources.</param>
+        protected virtual void Dispose(bool disposing)
+        {
+            if (this.httpListener != null && this.httpListener.IsListening)
+            {
+                this.Stop();
+                this.httpListener.Close();
+            }
+        }
+
+        private void WorkerThread()
+        {
+            this.httpListener.Start();
+
+            try
+            {
+                using var scope = SuppressInstrumentationScope.Begin();
+                while (!this.tokenSource.IsCancellationRequested)
+                {
+                    var ctxTask = this.httpListener.GetContextAsync();
+                    ctxTask.Wait(this.tokenSource.Token);
+
+                    var ctx = ctxTask.Result;
+
+                    ctx.Response.StatusCode = 200;
+                    ctx.Response.ContentType = PrometheusMetricBuilder.ContentType;
+
+                    using var output = ctx.Response.OutputStream;
+                    using var writer = new StreamWriter(output);
+                    this.exporter.MakePullRequest();
+                    this.exporter.WriteMetricsCollection(writer);
+                }
+            }
+            catch (OperationCanceledException ex)
+            {
+                PrometheusExporterEventSource.Log.CanceledExport(ex);
+            }
+            catch (Exception ex)
+            {
+                PrometheusExporterEventSource.Log.FailedExport(ex);
+            }
+            finally
+            {
+                try
+                {
+                    this.httpListener.Stop();
+                    this.httpListener.Close();
+                }
+                catch (Exception exFromFinally)
+                {
+                    PrometheusExporterEventSource.Log.FailedShutdown(exFromFinally);
+                }
+            }
+        }
+    }
+}
diff --git a/src/OpenTelemetry.Exporter.Prometheus/PrometheusExporterMiddleware.cs b/src/OpenTelemetry.Exporter.Prometheus/PrometheusExporterMiddleware.cs
new file mode 100644
index 00000000000..10cb608ee31
--- /dev/null
+++ b/src/OpenTelemetry.Exporter.Prometheus/PrometheusExporterMiddleware.cs
@@ -0,0 +1,60 @@
+// <copyright file="PrometheusExporterMiddleware.cs" company="OpenTelemetry Authors">
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// </copyright>
+
+using System;
+using System.Threading.Tasks;
+
+#if NETSTANDARD2_0
+using Microsoft.AspNetCore.Http;
+
+namespace OpenTelemetry.Exporter
+{
+    /// <summary>
+    /// A middleware used to expose Prometheus metrics.
+    /// </summary>
+    public class PrometheusExporterMiddleware
+    {
+        private readonly PrometheusExporter exporter;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="PrometheusExporterMiddleware"/> class.
+        /// </summary>
+        /// <param name="next">The next middleware in the pipeline.</param>
+        /// <param name="exporter">The <see cref="PrometheusExporter"/> instance.</param>
+        public PrometheusExporterMiddleware(RequestDelegate next, PrometheusExporter exporter)
+        {
+            this.exporter = exporter ?? throw new ArgumentNullException(nameof(exporter));
+        }
+
+        /// <summary>
+        /// Invoke.
+        /// </summary>
+        /// <param name="httpContext"> context. </param>
+        /// <returns>Task. </returns>
+        public Task InvokeAsync(HttpContext httpContext)
+        {
+            if (httpContext is null)
+            {
+                throw new ArgumentNullException(nameof(httpContext));
+            }
+
+            var result = this.exporter.GetMetricsCollection();
+
+            return httpContext.Response.WriteAsync(result);
+        }
+    }
+}
+#endif
diff --git a/src/OpenTelemetry.Exporter.Prometheus/PrometheusExporterOptions.cs b/src/OpenTelemetry.Exporter.Prometheus/PrometheusExporterOptions.cs
new file mode 100644
index 00000000000..ce4aae423cf
--- /dev/null
+++ b/src/OpenTelemetry.Exporter.Prometheus/PrometheusExporterOptions.cs
@@ -0,0 +1,29 @@
+// <copyright file="PrometheusExporterOptions.cs" company="OpenTelemetry Authors">
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// </copyright>
+
+namespace OpenTelemetry.Exporter
+{
+    /// <summary>
+    /// Options to run prometheus exporter.
+    /// </summary>
+    public class PrometheusExporterOptions
+    {
+        /// <summary>
+        /// Gets or sets the port to listen to. Typically it ends with /metrics like http://localhost:9184/metrics/.
+        /// </summary>
+        public string Url { get; set; } = "http://localhost:9184/metrics/";
+    }
+}
diff --git a/src/OpenTelemetry.Exporter.Prometheus/PrometheusRouteBuilderExtensions.cs b/src/OpenTelemetry.Exporter.Prometheus/PrometheusRouteBuilderExtensions.cs
new file mode 100644
index 00000000000..0b38d473419
--- /dev/null
+++ b/src/OpenTelemetry.Exporter.Prometheus/PrometheusRouteBuilderExtensions.cs
@@ -0,0 +1,46 @@
+// <copyright file="PrometheusRouteBuilderExtensions.cs" company="OpenTelemetry Authors">
+// Copyright The OpenTelemetry Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// </copyright>
+
+#if NETSTANDARD2_0
+
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Http;
+
+namespace OpenTelemetry.Exporter.Prometheus
+{
+    /// <summary>
+    /// Provides extension methods for <see cref="IApplicationBuilder"/> to add Prometheus Scraper Endpoint.
+    /// </summary>
+    public static class PrometheusRouteBuilderExtensions
+    {
+        private const string DefaultPath = "/metrics";
+
+        /// <summary>
+        /// Use prometheus extension.
+        /// </summary>
+        /// <param name="app">The <see cref="IApplicationBuilder"/> to add middleware to.</param>
+        /// <returns>A reference to the <see cref="IApplicationBuilder"/> instance after the operation has completed.</returns>
+        public static IApplicationBuilder UsePrometheus(this IApplicationBuilder app)
+        {
+            var options = app.ApplicationServices.GetService(typeof(PrometheusExporterOptions)) as PrometheusExporterOptions;
+            var path = new PathString(options?.Url ?? DefaultPath);
+            return app.Map(
+                new PathString(path),
+                builder => builder.UseMiddleware<PrometheusExporterMiddleware>());
+        }
+    }
+}
+#endif
diff --git a/src/OpenTelemetry.Exporter.Prometheus/README.md b/src/OpenTelemetry.Exporter.Prometheus/README.md
new file mode 100644
index 00000000000..ed79f8d2fa8
--- /dev/null
+++ b/src/OpenTelemetry.Exporter.Prometheus/README.md
@@ -0,0 +1,29 @@
+# Prometheus Exporter for OpenTelemetry .NET
+
+[![NuGet](https://img.shields.io/nuget/v/OpenTelemetry.Exporter.Prometheus.svg)](https://www.nuget.org/packages/OpenTelemetry.Exporter.Prometheus)
+[![NuGet](https://img.shields.io/nuget/dt/OpenTelemetry.Exporter.Prometheus.svg)](https://www.nuget.org/packages/OpenTelemetry.Exporter.Prometheus)
+
+## Prerequisite
+
+* [Get Prometheus](https://prometheus.io/docs/introduction/first_steps/)
+
+## Installation
+
+```shell
+dotnet add package OpenTelemetry.Exporter.Prometheus
+```
+
+## Configuration
+
+You can configure the `PrometheusExporter` by following the directions below:
+
+* `Url`: The url to listen to. Typically it ends with `/metrics` like `http://localhost:9184/metrics/`.
+
+See
+[`TestPrometheusExporter.cs`](../../examples/Console/TestPrometheusExporter.cs)
+for example use.
+
+## References
+
+* [OpenTelemetry Project](https://opentelemetry.io/)
+* [Prometheus](https://prometheus.io)