Initial refactoring. WIP.
diff --git a/prometheus/collector.go b/prometheus/collector.go
index c046880..1905e15 100644
--- a/prometheus/collector.go
+++ b/prometheus/collector.go
@@ -24,6 +24,9 @@
 // already implemented in this library are the metric vectors (i.e. collection
 // of multiple instances of the same Metric but with different label values)
 // like GaugeVec or SummaryVec, and the ExpvarCollector.
+//
+// (Two Collectors are considered equal if their
+// Describe method yields the same set of descriptors.)
 type Collector interface {
 	// Describe sends the super-set of all possible descriptors of metrics
 	// collected by this Collector to the provided channel and returns once
@@ -46,7 +49,9 @@
 	// therefore be implemented in a concurrency safe way. Blocking occurs
 	// at the expense of total performance of rendering all registered
 	// metrics. Ideally, Collector implementations support concurrent
-	// readers.
+	// readers. If a Collector finds itself unable to collect a metric, it
+	// can signal the error to the registry by sending a Metric that will
+	// return the error when its Write method is called.
 	Collect(chan<- Metric)
 }
 
diff --git a/prometheus/collectors/doc.go b/prometheus/collectors/doc.go
new file mode 100644
index 0000000..032fabe
--- /dev/null
+++ b/prometheus/collectors/doc.go
@@ -0,0 +1,15 @@
+// Copyright 2015 The Prometheus 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.
+
+// Package collectors provides collector implemntations for various purposes.
+package collectors
diff --git a/prometheus/go_collector.go b/prometheus/collectors/go.go
similarity index 100%
rename from prometheus/go_collector.go
rename to prometheus/collectors/go.go
diff --git a/prometheus/go_collector_test.go b/prometheus/collectors/go_test.go
similarity index 100%
rename from prometheus/go_collector_test.go
rename to prometheus/collectors/go_test.go
diff --git a/prometheus/process_collector.go b/prometheus/collectors/process.go
similarity index 95%
rename from prometheus/process_collector.go
rename to prometheus/collectors/process.go
index d8cf0ed..473e52e 100644
--- a/prometheus/process_collector.go
+++ b/prometheus/collectors/process.go
@@ -11,13 +11,17 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package prometheus
+package collectors
 
-import "github.com/prometheus/procfs"
+import (
+	"github.com/prometheus/procfs"
+
+	"github.com/prometheus/client_golang/prometheus/metric"
+)
 
 type processCollector struct {
 	pid             int
-	collectFn       func(chan<- Metric)
+	collectFn       func(chan<- metric.Metric)
 	pidFn           func() (int, error)
 	cpuTotal        Counter
 	openFDs, maxFDs Gauge
diff --git a/prometheus/process_collector_test.go b/prometheus/collectors/process_test.go
similarity index 98%
rename from prometheus/process_collector_test.go
rename to prometheus/collectors/process_test.go
index 829715a..6169842 100644
--- a/prometheus/process_collector_test.go
+++ b/prometheus/collectors/process_test.go
@@ -1,4 +1,4 @@
-package prometheus
+package collectors
 
 import (
 	"io/ioutil"
diff --git a/prometheus/desc.go b/prometheus/desc.go
index ee02d9b..5a214e3 100644
--- a/prometheus/desc.go
+++ b/prometheus/desc.go
@@ -6,6 +6,7 @@
 	"regexp"
 	"sort"
 	"strings"
+	"unicode/utf8"
 
 	"github.com/golang/protobuf/proto"
 
@@ -30,6 +31,197 @@
 // create a Desc.
 type Labels map[string]string
 
+// Desc is used to describe the meta-data of a Metric (via its Desc method) or a
+// group of metrics collected by a Collector (via its Describe method). Some of its
+// methods are only used internally and are therefore not exported, which also
+// prevents users to implement their own descriptors. Descriptor instances must
+// be created via suitable NewXXXDesc functions and will in generally only be
+// needed in custom collectors.
+//
+// Desc implementations are immutable by contract.
+//
+// A Desc that also implements the error interface is called an invalid
+// descriptor, which is solely used to communicate an error and must never be
+// processed further.
+type Desc interface {
+	// String returns a string representation of the descriptor as usual. It
+	// is also used as an ID that must be unique among all descriptors
+	// registered by a Registry.
+	String() string
+	dims() string
+}
+
+// NewInvalidDesc returns a descriptor that also implements the error
+// interface. It is used to communicate an error during a call of Desc (Metric
+// method) or Describe (Collector method). Create with NewInvalidDesc.
+func NewInvalidDesc(err error) Desc {
+	return &invalidDesc{err: err}
+}
+
+type invalidDesc struct {
+	err error
+}
+
+func (d *invalidDesc) Error() string {
+	return d.err.Error()
+}
+
+func (d *invalidDesc) String() string {
+	return "[invalid] " + d.err.Error()
+}
+
+func (d *invalidDesc) dims() string {
+	return ""
+}
+
+// NewPrefixDesc returns a descriptor that is used by Collectors that want to
+// reserve a whole metric name prefix for their own use. An invalid descriptor
+// is returned if the prefix is not a valid as the start of a metric
+// name. However, an empty prefix is valid and reserves all metric names.
+func NewPrefixDesc(prefix string) Desc {
+	if prefix != "" && !validMetricName(prefix) {
+		return NewInvalidDesc(fmt.Errorf("%q is not a valid metric name prefix", prefix))
+	}
+	return &prefixDesc{pfx: prefix}
+}
+
+type prefixDesc struct {
+	prefix string
+}
+
+func (d *prefixDesc) String() string {
+	return "[prefix] " + d.prefix
+}
+
+func (d *prefixDesc) dims() string {
+	return "" // PrefixDesc is for all dimensions.
+}
+
+func (d *prefixDesc) overlapsWith(other Desc) bool {
+	switch o := other.(type) {
+	case *invalidDesc:
+		// Invalid descs never overlap.
+		return false
+	case *partialDesc, *fullDesc:
+		return strings.HasPrefix(o.fqName, d.prefix)
+	case *prefixDesc:
+		return strings.HasPrefix(o.prefix, d.prefix) || strings.HasPrefix(d.Prefix, o.prefix)
+	default:
+		panic(fmt.Errorf("unexpected type of descriptor %q", o))
+	}
+}
+
+// NewPartialDesc returns a descriptor that is used by Collectors that want to
+// reserve a specific metric name and type with specific label dimensions of
+// which some (but not all) label values might be set already. An invalid
+// descriptor is returned in the following cases: The resulting label name
+// (assembled from namespace, subsystem, and name) is invalid, the help string
+// is empty, unsetLabels is empty or contains invalid label names,
+// setLabels (which might be empty) contains invalid label names or label
+// values, metricType is not a valid MetricType.
+func NewPartialDesc(
+	namespace, subsystem, name string,
+	metricType MetricType,
+	help string,
+	setLabels Labels,
+	unsetLabels []string,
+) Desc {
+	return nil // TODO
+}
+
+// NewFullDesc returns a descriptor with fully specified name, type, and
+// labels. It can be used by Collectors and must be used by Metrics. An invalid
+// descriptor is returned if the resulting label name (assembled from namespace,
+// subsystem, and name) is invalid, the help string is empty, metricType has an
+// invalid value, or the labels contain invalid label names or values. The labels
+// might be empty, though.
+func NewFullDesc(
+	namespace, subsystem, name string,
+	metricType MetricType,
+	help string,
+	labels Labels,
+) Desc {
+	return nil // TODO
+}
+
+// FullySpecify returns a fully specified descriptor based on the provided
+// partial descriptor by setting all the unset labels to the provided values (in
+// the same order as they have been specified in the NewFullDesc or DeSpecify
+// call). An invalid desc is returned if the provided desc is not a partial
+// descriptor, the cardinality of labelValues does not fit, or labelValues
+// contains invalid label values.
+func FullySpecify(desc Desc, labelValues ...string) Desc {
+	d, ok := desc.(*partialDesc)
+	if !ok {
+		return NewInvalidDesc(fmt.Errorf("tried to fully specify non-partial descriptor %q", desc))
+	}
+	return nil // TODO
+}
+
+// DeSpecify creates a partial descriptor based on the provided full descriptor
+// by adding un-set labels with the provided label names. An invalid desc is
+// returned if the provided desc is not a full descriptor, or labelNames
+// contains invalid label names (or no label names at all).
+func DeSpecify(desc Desc, labelNames ...string) Desc {
+	d, ok := desc.(*fullDesc)
+	if !ok {
+		return NewInvalidDesc(fmt.Errorf("tried to de-specify non-full descriptor %q", desc))
+	}
+	if len(ln) == 0 {
+		return NewInvalidDesc(fmt.Errorf("no label names provided to de-specify %q", desc))
+	}
+	for _, ln := range labelNames {
+		if !validLabelName(ln) {
+			return NewInvalidDesc(fmt.Errorf("encountered invalid label name %q while de-specifying %q", ln, desc))
+		}
+	}
+	return &partialDesc{*d, labelNames}
+}
+
+type fullDesc struct {
+	fqName, help string
+	metricType   MetricType
+	setLabels    []*dto.LabelPair // Sorted.
+}
+
+type partialDesc struct {
+	fullDesc
+	unsetLabels []string // Keep in original order.
+}
+
+// buildFQName joins the given three name components by "_". Empty name
+// components are ignored. If the name parameter itself is empty, an empty
+// string is returned, no matter what.
+func buildFQName(namespace, subsystem, name string) string {
+	if name == "" {
+		return ""
+	}
+	switch {
+	case namespace != "" && subsystem != "":
+		return namespace + "_" + subsystem + "_" + name
+	case namespace != "":
+		return namespace + "_" + name
+	case subsystem != "":
+		return subsystem + "_" + name
+	}
+	return name
+}
+
+func validMetricName(n string) bool {
+	return metricNameRE.MatchString(n)
+}
+
+func validLabelName(l string) bool {
+	return labelNameRE.MatchString(l) &&
+		!strings.HasPrefix(l, reservedLabelPrefix)
+}
+
+func validLabelValue(l string) bool {
+	return utf8.ValidString(l)
+}
+
+// OLD CODE below.
+
 // Desc is the descriptor used by every Prometheus Metric. It is essentially
 // the immutable meta-data of a Metric. The normal Metric implementations
 // included in this package manage their Desc under the hood. Users only have to
@@ -102,7 +294,7 @@
 	labelNameSet := map[string]struct{}{}
 	// First add only the const label names and sort them...
 	for labelName := range constLabels {
-		if !checkLabelName(labelName) {
+		if !validLabelName(labelName) {
 			d.err = fmt.Errorf("%q is not a valid label name", labelName)
 			return d
 		}
@@ -118,7 +310,7 @@
 	// cannot be in a regular label name. That prevents matching the label
 	// dimension with a different mix between preset and variable labels.
 	for _, labelName := range variableLabels {
-		if !checkLabelName(labelName) {
+		if !validLabelName(labelName) {
 			d.err = fmt.Errorf("%q is not a valid label name", labelName)
 			return d
 		}
@@ -159,16 +351,6 @@
 	return d
 }
 
-// NewInvalidDesc returns an invalid descriptor, i.e. a descriptor with the
-// provided error set. If a collector returning such a descriptor is registered,
-// registration will fail with the provided error. NewInvalidDesc can be used by
-// a Collector to signal inability to describe itself.
-func NewInvalidDesc(err error) *Desc {
-	return &Desc{
-		err: err,
-	}
-}
-
 func (d *Desc) String() string {
 	lpStrings := make([]string, 0, len(d.constLabelPairs))
 	for _, lp := range d.constLabelPairs {
@@ -185,8 +367,3 @@
 		d.variableLabels,
 	)
 }
-
-func checkLabelName(l string) bool {
-	return labelNameRE.MatchString(l) &&
-		!strings.HasPrefix(l, reservedLabelPrefix)
-}
diff --git a/prometheus/metric.go b/prometheus/metric.go
index 86fd81c..6c31d9a 100644
--- a/prometheus/metric.go
+++ b/prometheus/metric.go
@@ -13,11 +13,7 @@
 
 package prometheus
 
-import (
-	"strings"
-
-	dto "github.com/prometheus/client_model/go"
-)
+import dto "github.com/prometheus/client_model/go"
 
 const separatorByte byte = 255
 
@@ -53,6 +49,42 @@
 	Write(*dto.Metric) error
 }
 
+// MetricType is an enumeration of metric types. It deliberately mirrors the
+// MetricType enum from the protobuf specification to avoid exposing protobuf
+// references to the user of this package. (The protobuf parts could be
+// internally vendored.)
+type MetricType int
+
+// Possible values for the MetricType enum.
+const (
+	CounterMetric MetricType = iota
+	GaugeMetric
+	SummaryMetric
+	UntypedMetric
+	HistogramMetric
+)
+
+func (m MetricType) Valid() bool {
+	return m >= CounterMetric && m <= HistogramMetric
+}
+
+func (m MetricType) String() string {
+	switch m {
+	case CounterMetric:
+		return "COUNTER"
+	case GaugeMetric:
+		return "GAUGE"
+	case SummaryMetric:
+		return "SUMMARY"
+	case UntypedMetric:
+		return "UNTYPED"
+	case HistogramMetric:
+		return "HISTOGRAM"
+	default:
+		return "INVALID"
+	}
+}
+
 // Opts bundles the options for creating most Metric types. Each metric
 // implementation XXX has its own XXXOpts type, but in most cases, it is just be
 // an alias of this type (which might change when the requirement arises.)
@@ -96,28 +128,6 @@
 	ConstLabels Labels
 }
 
-// BuildFQName joins the given three name components by "_". Empty name
-// components are ignored. If the name parameter itself is empty, an empty
-// string is returned, no matter what. Metric implementations included in this
-// library use this function internally to generate the fully-qualified metric
-// name from the name component in their Opts. Users of the library will only
-// need this function if they implement their own Metric or instantiate a Desc
-// (with NewDesc) directly.
-func BuildFQName(namespace, subsystem, name string) string {
-	if name == "" {
-		return ""
-	}
-	switch {
-	case namespace != "" && subsystem != "":
-		return strings.Join([]string{namespace, subsystem, name}, "_")
-	case namespace != "":
-		return strings.Join([]string{namespace, name}, "_")
-	case subsystem != "":
-		return strings.Join([]string{subsystem, name}, "_")
-	}
-	return name
-}
-
 // LabelPairSorter implements sort.Interface. It is used to sort a slice of
 // dto.LabelPair pointers. This is useful for implementing the Write method of
 // custom metrics.
@@ -150,17 +160,18 @@
 }
 
 type invalidMetric struct {
-	desc *Desc
+	desc Desc
 	err  error
 }
 
 // NewInvalidMetric returns a metric whose Write method always returns the
-// provided error. It is useful if a Collector finds itself unable to collect
-// a metric and wishes to report an error to the registry.
-func NewInvalidMetric(desc *Desc, err error) Metric {
-	return &invalidMetric{desc, err}
+// provided error, and whose descriptor is invalid, carrying the provided
+// error. It is useful if a Collector finds itself unable to collect a metric
+// and wishes to report an error to the registry.
+func NewInvalidMetric(err error) Metric {
+	return &invalidMetric{NewInvalidDesc(err), err}
 }
 
-func (m *invalidMetric) Desc() *Desc { return m.desc }
+func (m *invalidMetric) Desc() Desc { return m.desc }
 
 func (m *invalidMetric) Write(*dto.Metric) error { return m.err }
diff --git a/prometheus/metric/collector.go b/prometheus/metric/collector.go
new file mode 100644
index 0000000..763fda5
--- /dev/null
+++ b/prometheus/metric/collector.go
@@ -0,0 +1,54 @@
+// Copyright 2015 The Prometheus 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.
+
+package metric
+
+// Collector is the interface implemented by anything that can be used by
+// Prometheus to collect metrics. A Collector has to be registered for
+// collection.
+//
+// The stock metrics provided in their respective packages (like Gauge, Counter,
+// Summary, Histogram) are also Collectors (which only ever collect one metric,
+// namely itself). An implementer of Collector may, however, collect multiple
+// metrics in a coordinated fashion and/or create metrics on the fly. Examples
+// for collectors already implemented in this library are the metric vectors
+// (i.e. collection of multiple instances of the same Metric but with different
+// label values) like gauge.Vec or summary.Vec, and the ExpvarCollector.
+//
+// Two Collectors are considered equal if their Describe methods yield the same
+// set of descriptors.
+type Collector interface {
+	// Describe sends all descriptors required to describe the metrics
+	// collected by this Collector to the provided channel and returns once
+	// the last descriptor has been sent. The sent descriptors fulfill the
+	// consistency and uniqueness requirements described in the Desc
+	// documentation. This method idempotently sends the same descriptors
+	// throughout the lifetime of the Collector. If a Collector encounters
+	// an error while executing this method, it must send an invalid
+	// descriptor (created with NewInvalidDesc) to signal the error to the
+	// registry.
+	Describe(chan<- Desc)
+	// Collect is called by Prometheus when collecting metrics. The
+	// implementation sends each collected metric via the provided channel
+	// and returns once the last metric has been sent. Each sent metric must
+	// be consistent with one of the descriptors returned by
+	// Describe. Returned metrics that are described by the same descriptor
+	// must differ in their variable label values. This method may be called
+	// concurrently and must therefore be implemented in a concurrency safe
+	// way. Blocking occurs at the expense of total performance of rendering
+	// all registered metrics. Ideally, Collector implementations support
+	// concurrent readers. If a Collector finds itself unable to collect a
+	// metric, it can signal the error to the registry by sending a Metric
+	// that will return the error in its Write method..
+	Collect(chan<- Metric)
+}
diff --git a/prometheus/metric/desc.go b/prometheus/metric/desc.go
new file mode 100644
index 0000000..f5ae294
--- /dev/null
+++ b/prometheus/metric/desc.go
@@ -0,0 +1,49 @@
+
+import "fmt"
+
+func NewDesc(
+	namespace, subsystem, name string,
+	help string,
+	constLabels Labels,
+	variableLabels []string,
+) Desc {
+	fqName := buildFQName(namespace, subsystem, name)
+	if !metricNameRE.MatchString(fqName) {
+		return NewInvalidDesc(fmt.Errorf("%q is not a valid metric name", fqName))
+	}
+	if help == "" {
+		return NewInvalidDesc(fmt.Errorf("empty help string for metric %q", fqName))
+	}
+
+	return nil // TODO
+}
+
+type regularDesc struct {
+	baseDesc
+	fqName, help    string
+	constLabelPairs []*dto.LabelPair
+	variableLabels  []string
+}
+
+type prefixDesc struct {
+	baseDesc
+	prefix string
+}
+
+type Set struct {
+	regular map[string]*regularDesc
+	// The prefix ones should be tries. But it's unlikely to have many of them.
+	prefix []*prefixDesc
+}
+
+func (s *Set) Add(d Desc) error {
+	if d.Error() != nil {
+		return d.Error()
+	}
+	return nil
+}
+
+func (s *Set) Remove(d Desc) bool {
+	return false
+}
+
diff --git a/prometheus/fnv.go b/prometheus/metric/fnv.go
similarity index 96%
rename from prometheus/fnv.go
rename to prometheus/metric/fnv.go
index e3b67df..ef0c224 100644
--- a/prometheus/fnv.go
+++ b/prometheus/metric/fnv.go
@@ -1,4 +1,4 @@
-package prometheus
+package metric
 
 // Inline and byte-free variant of hash/fnv's fnv64a.
 
diff --git a/prometheus/metric/metric.go b/prometheus/metric/metric.go
new file mode 100644
index 0000000..9a42112
--- /dev/null
+++ b/prometheus/metric/metric.go
@@ -0,0 +1,46 @@
+// Copyright 2015 The Prometheus 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.
+
+package metric
+
+import dto "github.com/prometheus/client_model/go"
+
+// A Metric models a single sample value with its meta data being exported to
+// Prometheus. Implementers of Metric in this package include Gauge, Counter,
+// Untyped, and Summary. Users can implement their own Metric types, but that
+// should be rarely needed.
+type Metric interface {
+	// Desc returns the descriptor for the Metric. This method idempotently
+	// returns the same descriptor throughout the lifetime of the Metric. A
+	// Metric unable to describe itself must return an invalid descriptor
+	// (created with NewInvalidDesc).
+	Desc() Desc
+	// Write encodes the Metric into a "Metric" Protocol Buffer data
+	// transmission object.
+	//
+	// Implementers of custom Metric types must observe concurrency safety
+	// as reads of this metric may occur at any time, and any blocking
+	// occurs at the expense of total performance of rendering all
+	// registered metrics. Ideally Metric implementations should support
+	// concurrent readers.
+	//
+	// The caller may minimize memory allocations by providing a
+	// pre-existing reset dto.Metric pointer. The caller may recycle the
+	// dto.Metric proto message, so Metric implementations should just
+	// populate the provided dto.Metric and then should not keep any
+	// reference to it.
+	//
+	// While populating dto.Metric, labels must be sorted lexicographically.
+	// (Implementers may find LabelPairSorter useful for that.)
+	Write(*dto.Metric) error
+}
diff --git a/prometheus/promhttp/exposition.go b/prometheus/promhttp/exposition.go
new file mode 100644
index 0000000..79b581d
--- /dev/null
+++ b/prometheus/promhttp/exposition.go
@@ -0,0 +1,53 @@
+// Copyright 2015 The Prometheus 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.
+
+package promhttp
+
+import (
+	"net/http"
+
+	"github.com/prometheus/client_golang/prometheus/registry"
+)
+
+// Constants relevant to the HTTP interface.
+const (
+	// APIVersion is the version of the format of the exported data.  This
+	// will match this library's version, which subscribes to the Semantic
+	// Versioning scheme.
+	APIVersion = "0.0.4"
+
+	// DelimitedTelemetryContentType is the content type set on telemetry
+	// data responses in delimited protobuf format.
+	DelimitedTelemetryContentType = `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited`
+	// TextTelemetryContentType is the content type set on telemetry data
+	// responses in text format.
+	TextTelemetryContentType = `text/plain; version=` + APIVersion
+	// ProtoTextTelemetryContentType is the content type set on telemetry
+	// data responses in protobuf text format.  (Only used for debugging.)
+	ProtoTextTelemetryContentType = `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=text`
+	// ProtoCompactTextTelemetryContentType is the content type set on
+	// telemetry data responses in protobuf compact text format.  (Only used
+	// for debugging.)
+	ProtoCompactTextTelemetryContentType = `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=compact-text`
+
+	contentTypeHeader     = "Content-Type"
+	contentLengthHeader   = "Content-Length"
+	contentEncodingHeader = "Content-Encoding"
+
+	acceptEncodingHeader = "Accept-Encoding"
+	acceptHeader         = "Accept"
+)
+
+func Handler(r registry.Registry) http.Handler {
+	return nil // TODO
+}
diff --git a/prometheus/http.go b/prometheus/promhttp/instrumentation.go
similarity index 97%
rename from prometheus/http.go
rename to prometheus/promhttp/instrumentation.go
index eabe602..bd327bd 100644
--- a/prometheus/http.go
+++ b/prometheus/promhttp/instrumentation.go
@@ -1,4 +1,4 @@
-// Copyright 2014 The Prometheus Authors
+// Copyright 2015 The Prometheus 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
@@ -11,7 +11,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package prometheus
+package promhttp
 
 import (
 	"bufio"
@@ -23,6 +23,8 @@
 	"time"
 )
 
+// TODO: Rework handler instrumentation (histograms, more configurable...).
+
 var instLabels = []string{"method", "code"}
 
 type nower interface {
diff --git a/prometheus/registry.go b/prometheus/registry.go
index 1dc2536..2f7f8eb 100644
--- a/prometheus/registry.go
+++ b/prometheus/registry.go
@@ -27,7 +27,6 @@
 	"io"
 	"net/http"
 	"net/url"
-	"os"
 	"sort"
 	"strings"
 	"sync"
@@ -36,56 +35,19 @@
 	"github.com/prometheus/common/expfmt"
 
 	dto "github.com/prometheus/client_model/go"
+
+	"github.com/prometheus/client_golang/prometheus/promhttp"
 )
 
-var (
-	defRegistry   = newDefaultRegistry()
-	errAlreadyReg = errors.New("duplicate metrics collector registration attempted")
-)
-
-// Constants relevant to the HTTP interface.
-const (
-	// APIVersion is the version of the format of the exported data.  This
-	// will match this library's version, which subscribes to the Semantic
-	// Versioning scheme.
-	APIVersion = "0.0.4"
-
-	// DelimitedTelemetryContentType is the content type set on telemetry
-	// data responses in delimited protobuf format.
-	DelimitedTelemetryContentType = `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=delimited`
-	// TextTelemetryContentType is the content type set on telemetry data
-	// responses in text format.
-	TextTelemetryContentType = `text/plain; version=` + APIVersion
-	// ProtoTextTelemetryContentType is the content type set on telemetry
-	// data responses in protobuf text format.  (Only used for debugging.)
-	ProtoTextTelemetryContentType = `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=text`
-	// ProtoCompactTextTelemetryContentType is the content type set on
-	// telemetry data responses in protobuf compact text format.  (Only used
-	// for debugging.)
-	ProtoCompactTextTelemetryContentType = `application/vnd.google.protobuf; proto=io.prometheus.client.MetricFamily; encoding=compact-text`
-
-	// Constants for object pools.
-	numBufs           = 4
-	numMetricFamilies = 1000
-	numMetrics        = 10000
-
-	// Capacity for the channel to collect metrics and descriptors.
-	capMetricChan = 1000
-	capDescChan   = 10
-
-	contentTypeHeader     = "Content-Type"
-	contentLengthHeader   = "Content-Length"
-	contentEncodingHeader = "Content-Encoding"
-
-	acceptEncodingHeader = "Accept-Encoding"
-	acceptHeader         = "Accept"
-)
-
-// Handler returns the HTTP handler for the global Prometheus registry. It is
-// already instrumented with InstrumentHandler (using "prometheus" as handler
-// name). Usually the handler is used to handle the "/metrics" endpoint.
+// Handler returns an instrumented HTTP handler for the default Prometheus
+// registry. It is already instrumented with InstrumentHandler (using
+// "prometheus" as handler name). Usually the handler is used to handle the
+// "/metrics" endpoint.
 func Handler() http.Handler {
-	return InstrumentHandler("prometheus", defRegistry)
+	return promhttp.InstrumentHandler(
+		"prometheus",
+		promhttp.Handler(registry.Default),
+	)
 }
 
 // UninstrumentedHandler works in the same way as Handler, but the returned HTTP
@@ -94,30 +56,26 @@
 // different handler name (or with a different instrumentation approach
 // altogether). See the InstrumentHandler example.
 func UninstrumentedHandler() http.Handler {
-	return defRegistry
+	return promhttp.Handler(registry.Default)
 }
 
-// Register registers a new Collector to be included in metrics collection. It
-// returns an error if the descriptors provided by the Collector are invalid or
-// if they - in combination with descriptors of already registered Collectors -
-// do not fulfill the consistency and uniqueness criteria described in the Desc
-// documentation.
+// Register registers a new Collector to be included in metrics collection with
+// the default registry. It returns an error if the descriptors provided by the
+// Collector are invalid or if they - in combination with descriptors of already
+// registered Collectors - do not fulfill the consistency and uniqueness
+// criteria described in the Desc documentation.
 //
 // Do not register the same Collector multiple times concurrently. (Registering
 // the same Collector twice would result in an error anyway, but on top of that,
 // it is not safe to do so concurrently.)
-func Register(m Collector) error {
-	_, err := defRegistry.Register(m)
-	return err
+func Register(c Collector) error {
+	return registry.Default.Register(c)
 }
 
 // MustRegister works like Register but panics where Register would have
 // returned an error.
-func MustRegister(m Collector) {
-	err := Register(m)
-	if err != nil {
-		panic(err)
-	}
+func MustRegister(c Collector) {
+	registry.MustRegister(registry.Default, c)
 }
 
 // RegisterOrGet works like Register but does not return an error if a Collector
@@ -129,18 +87,14 @@
 //
 // As for Register, it is still not safe to call RegisterOrGet with the same
 // Collector multiple times concurrently.
-func RegisterOrGet(m Collector) (Collector, error) {
-	return defRegistry.RegisterOrGet(m)
+func RegisterOrGet(c Collector) (Collector, error) {
+	return registry.RegisterOrGet(registry.Default, c)
 }
 
 // MustRegisterOrGet works like Register but panics where RegisterOrGet would
 // have returned an error.
-func MustRegisterOrGet(m Collector) Collector {
-	existing, err := RegisterOrGet(m)
-	if err != nil {
-		panic(err)
-	}
-	return existing
+func MustRegisterOrGet(c Collector) Collector {
+	return registry.MustRegisterOrGet(registry.Default, c)
 }
 
 // Unregister unregisters the Collector that equals the Collector passed in as
@@ -148,50 +102,10 @@
 // yields the same set of descriptors.) The function returns whether a Collector
 // was unregistered.
 func Unregister(c Collector) bool {
-	return defRegistry.Unregister(c)
+	return registry.Default.Unregister(c)
 }
 
-// SetMetricFamilyInjectionHook sets a function that is called whenever metrics
-// are collected. The hook function must be set before metrics collection begins
-// (i.e. call SetMetricFamilyInjectionHook before setting the HTTP handler.) The
-// MetricFamily protobufs returned by the hook function are merged with the
-// metrics collected in the usual way.
-//
-// This is a way to directly inject MetricFamily protobufs managed and owned by
-// the caller. The caller has full responsibility. As no registration of the
-// injected metrics has happened, there is no descriptor to check against, and
-// there are no registration-time checks. If collect-time checks are disabled
-// (see function EnableCollectChecks), no sanity checks are performed on the
-// returned protobufs at all. If collect-checks are enabled, type and uniqueness
-// checks are performed, but no further consistency checks (which would require
-// knowledge of a metric descriptor).
-//
-// Sorting concerns: The caller is responsible for sorting the label pairs in
-// each metric. However, the order of metrics will be sorted by the registry as
-// it is required anyway after merging with the metric families collected
-// conventionally.
-//
-// The function must be callable at any time and concurrently.
-func SetMetricFamilyInjectionHook(hook func() []*dto.MetricFamily) {
-	defRegistry.metricFamilyInjectionHook = hook
-}
-
-// PanicOnCollectError sets the behavior whether a panic is caused upon an error
-// while metrics are collected and served to the HTTP endpoint. By default, an
-// internal server error (status code 500) is served with an error message.
-func PanicOnCollectError(b bool) {
-	defRegistry.panicOnCollectError = b
-}
-
-// EnableCollectChecks enables (or disables) additional consistency checks
-// during metrics collection. These additional checks are not enabled by default
-// because they inflict a performance penalty and the errors they check for can
-// only happen if the used Metric and Collector types have internal programming
-// errors. It can be helpful to enable these checks while working with custom
-// Collectors or Metrics whose correctness is not well established yet.
-func EnableCollectChecks(b bool) {
-	defRegistry.collectChecksEnabled = b
-}
+// TODO: Move out from here.
 
 // encoder is a function that writes a dto.MetricFamily to an io.Writer in a
 // certain encoding. It returns the number of bytes written and any error
@@ -305,7 +219,7 @@
 	}()
 
 	descIDs := map[uint64]struct{}{}
-	var collectorID uint64 // Just a sum of the desc IDs.
+	var collectorID uint64 // Just a sum of the desc IDs. TODO: should be fnv on its own
 	for desc := range descChan {
 		if _, exists := descIDs[desc.id]; !exists {
 			collectorID += desc.id
@@ -670,13 +584,6 @@
 	}
 }
 
-func newDefaultRegistry() *registry {
-	r := newRegistry()
-	r.Register(NewProcessCollector(os.Getpid(), ""))
-	r.Register(NewGoCollector())
-	return r
-}
-
 // decorateWriter wraps a writer to handle gzip compression if requested.  It
 // returns the decorated writer and the appropriate "Content-Encoding" header
 // (which is empty if no compression is enabled).
diff --git a/prometheus/registry/doc.go b/prometheus/registry/doc.go
new file mode 100644
index 0000000..1aa1022
--- /dev/null
+++ b/prometheus/registry/doc.go
@@ -0,0 +1,17 @@
+// Copyright 2015 The Prometheus 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.
+
+// Package registry provides the interface of the metrics registry and means to
+// create concrete instantiations thereof.
+
+package registry
diff --git a/prometheus/registry/error.go b/prometheus/registry/error.go
new file mode 100644
index 0000000..960d3d3
--- /dev/null
+++ b/prometheus/registry/error.go
@@ -0,0 +1,24 @@
+// Copyright 2015 The Prometheus 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.
+
+package registry
+
+import "github.com/prometheus/client_golang/prometheus/metric"
+
+type AlreadyRegisteredError struct {
+	ExistingCollector, NewCollector metric.Collector
+}
+
+func (err AlreadyRegisteredError) Error() string {
+	return "" // TODO
+}
diff --git a/prometheus/registry/impl.go b/prometheus/registry/impl.go
new file mode 100644
index 0000000..07586b4
--- /dev/null
+++ b/prometheus/registry/impl.go
@@ -0,0 +1,66 @@
+// Copyright 2015 The Prometheus 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.
+
+package registry
+
+import (
+	"os"
+
+	dto "github.com/prometheus/client_model/go"
+
+	"github.com/prometheus/client_golang/prometheus"
+)
+
+// TODO: These are from the old code. Vet!
+const (
+	// Constants for object pools.
+	numBufs           = 4
+	numMetricFamilies = 1000
+	numMetrics        = 10000
+
+	// Capacity for the channel to collect metrics and descriptors.
+	capMetricChan = 1000
+	capDescChan   = 10
+)
+
+func init() {
+	MustRegister(Default, collectors.NewProcessCollector(os.Getpid(), ""))
+	MustRegister(Default, collectors.NewGoCollector())
+}
+
+// Default is the default registry implicitly used by the top-level functions in
+// the prometheus package. It is using the default value of Opts and has a
+// ProcessCollector and a GoCollector pre-registered.
+var Default Registry = New(Opts{})
+
+func New(opts Opts) Registry {
+	return &registry{}
+}
+
+type registry struct {
+}
+
+func (r *registry) Register(prometheus.Collector) error {
+	return nil // TODO
+}
+
+func (r *registry) Unregister(prometheus.Collector) bool {
+	return false // TODO
+}
+
+func (r *registry) Collect(names map[string]struct{}) <-chan struct {
+	*dto.MetricFamily
+	error
+} {
+	return nil // TODO
+}
diff --git a/prometheus/registry/interface.go b/prometheus/registry/interface.go
new file mode 100644
index 0000000..8b180bd
--- /dev/null
+++ b/prometheus/registry/interface.go
@@ -0,0 +1,96 @@
+// Copyright 2015 The Prometheus 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.
+
+// Package registry provides the interface of the metrics registry and means to
+// instantiate implementations thereof. It also provides the so-called default
+// registry, a pre-configured instantiation of a registry that should be
+// sufficient for most use-cases.
+package registry
+
+import (
+	dto "github.com/prometheus/client_model/go"
+
+	"github.com/prometheus/client_golang/prometheus/metric"
+)
+
+// Registry is the interface for the metrics registry.
+type Registry interface {
+	// Register registers a new Collector to be included in metrics
+	// collection. It returns an error if the descriptors provided by the
+	// Collector are invalid or if they - in combination with descriptors of
+	// already registered Collectors - do not fulfill the consistency and
+	// uniqueness criteria described in the documentation of metric.Desc.
+	//
+	// If the provided Collector is equal to a Collector already registered
+	// (which includes the case of re-registering the same Collector), the
+	// returned error is an instance of AlreadyRegisteredError, which
+	// contains the previously registered Collector.
+	//
+	// It is in general not safe to register the same Collector multiple
+	// times concurrently.
+	Register(metric.Collector) error
+	// Unregister unregisters the Collector that equals the Collector passed
+	// in as an argument. The function returns whether a Collector was
+	// unregistered.
+	Unregister(metric.Collector) bool
+	// Collect returns a channel that yields MetricFamily protobufs
+	// (collected from registered collectors) together with applicable
+	// errors. The metric family pointer returned with an error could be nil
+	// or point to a (presumably incomplete) metric family. Once all
+	// MetricFamilies have been read, the channel is closed. To not leak
+	// resources, the channel must always be read until closed, even if one
+	// ore more errors have been returned. If names is nil or empty, all
+	// MetricFamilies are returned. Otherwise, only MetricFamilies with a
+	// name contained in names are returned. Implementations should aim for
+	// lexicographical sorting of MetricFamilies if the resource cost of
+	// sorting is not prohibitive.
+	Collect(names map[string]struct{}) <-chan struct {
+		*dto.MetricFamily
+		error
+	}
+}
+
+// Opts are options for the instantiation of new registries. The zero value of
+// Opts is a safe default.
+type Opts struct {
+	// If true, metrics are checked for consistency during collection. The
+	// check has a performance overhead and is not necessary with
+	// well-behaved collectors. It can be helpful to enable the check while
+	// working with custom Collectors whose correctness is not well
+	// established yet or where inconsistent collection might happen by
+	// design.
+	CollectCheckEnabled bool
+	// If true, the channel returned by the Collect method will never yield
+	// an error (so that no error handling has to be implemented when
+	// receiving from the channel). Instead, the program will panic. This
+	// behavior is useful in programs where collect errors cannot (or must
+	// not) happen.
+	PanicOnCollectError bool
+	// The MetricFamilyInjectionHook is a function that is called whenever
+	// metrics are collected. The MetricFamily protobufs returned by the
+	// hook function are merged with the metrics collected in the usual way.
+	//
+	// This is a way to directly inject MetricFamily protobufs managed and
+	// owned by the caller. The caller has full responsibility. As no
+	// registration of the injected metrics has happened, there was no check
+	// at registration-time. If CollectCheckEnabled is false, only very
+	// limited sanity checks are performed on the returned protobufs.
+	//
+	// Sorting concerns: The caller is responsible for sorting the label
+	// pairs in each metric. However, the order of metrics will be sorted by
+	// the registry as it is required anyway after merging with the metric
+	// families collected conventionally.
+	//
+	// The function must be callable at any time and concurrently.
+	MetricFamilyInjectionHook func() []*dto.MetricFamily
+}
diff --git a/prometheus/registry/util.go b/prometheus/registry/util.go
new file mode 100644
index 0000000..85fe34d
--- /dev/null
+++ b/prometheus/registry/util.go
@@ -0,0 +1,40 @@
+// Copyright 2015 The Prometheus 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.
+
+package registry
+
+import "github.com/prometheus/client_golang/prometheus/metric"
+
+func MustRegister(r Registry, c metric.Collector) {
+	if err := r.Register(c); err != nil {
+		panic(err)
+	}
+}
+
+func RegisterOrGet(r Registry, c metric.Collector) (metric.Collector, error) {
+	if err := r.Register(c); err != nil {
+		if are, ok := err.(AlreadyRegisteredError); ok {
+			return are.ExistingCollector, nil
+		}
+		return nil, err
+	}
+	return c, nil
+}
+
+func MustRegisterOrGet(r Registry, c metric.Collector) metric.Collector {
+	existing, err := RegisterOrGet(r, c)
+	if err != nil {
+		panic(err)
+	}
+	return existing
+}
diff --git a/prometheus/vec.go b/prometheus/vec.go
index 68f9461..c7dfc4b 100644
--- a/prometheus/vec.go
+++ b/prometheus/vec.go
@@ -241,6 +241,7 @@
 	if !ok {
 		// Copy labelValues. Otherwise, they would be allocated even if we don't go
 		// down this code path.
+		// TODO: Use copy.
 		copiedLabelValues := append(make([]string, 0, len(labelValues)), labelValues...)
 		metric = m.newMetric(copiedLabelValues...)
 		m.children[hash] = metric