<commit_before>// Copyright 2014 struktur AG. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package phoenix

import (
	"fmt"
	"log"
	"os"
	"testing"
)

func newTestContainer(name, version string) Container {
	return &container{
		name,
		version,
		nil,
		nil,
		nil,
	}
}

func Test_Container_Name_UsesTheGivenValue(t *testing.T) {
	name := "spreed-app"
	container := newTestContainer(name, "")
	if actualName := container.Name(); actualName != name {
		t.Errorf("Expected app name to be '%s', but was '%s'", name, actualName)
	}
}

func Test_Container_Name_DefaultstoAppIfUnset(t *testing.T) {
	container := newTestContainer("", "")
	if expected, actual := "app", container.Name(); expected != actual {
		t.Errorf("Expected app name to be '%s', but was '%s'", expected, actual)
	}
}

func Test_Container_Version_UsesTheGivenValue(t *testing.T) {
	version := "0.9.4b1"
	container := newTestContainer("", version)
	if actualVersion := container.Version(); actualVersion != version {
		t.Errorf("Expected app name to be '%s', but was '%s'", version, actualVersion)
	}
}

func Test_Container_Name_DefaultstoUnreleasedIfUnset(t *testing.T) {
	container := newTestContainer("", "")
	if expected, actual := "unreleased", container.Version(); expected != actual {
		t.Errorf("Expected app version to be '%s', but was '%s'", expected, actual)
	}
}

func Test_Container_Syslog(t *testing.T) {
	logFilename := "syslog"
	container, err := newContainer("test", "", &logFilename, nil)
	if err != nil {
		fmt.Fprintf(os.Stderr, "WARNING: Could not create container, test will be skipped: '%v'\n", err)
		return
	}
	if err := container.Close(); err != nil {
		t.Errorf("Closing the syslog container returned '%s'", err)
	}
	log.Println("Testing")
	fp, err := os.Open(logFilename)
	if fp != nil {
		fp.Close()
	}
	if err == nil {
		t.Errorf("Logging created a file '%s' but should have logged to syslog", logFilename)
	} else if !os.IsNotExist(err) {
		t.Errorf("Logfile '%s' could not be opened but should not exist: '%s'", logFilename, err)
	}
}
<commit_msg>Update logging of errors.<commit_after>// Copyright 2014 struktur AG. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package phoenix

import (
	"fmt"
	"log"
	"os"
	"testing"
)

func newTestContainer(name, version string) Container {
	return &container{
		name,
		version,
		nil,
		nil,
		nil,
	}
}

func Test_Container_Name_UsesTheGivenValue(t *testing.T) {
	name := "spreed-app"
	container := newTestContainer(name, "")
	if actualName := container.Name(); actualName != name {
		t.Errorf("Expected app name to be '%s', but was '%s'", name, actualName)
	}
}

func Test_Container_Name_DefaultstoAppIfUnset(t *testing.T) {
	container := newTestContainer("", "")
	if expected, actual := "app", container.Name(); expected != actual {
		t.Errorf("Expected app name to be '%s', but was '%s'", expected, actual)
	}
}

func Test_Container_Version_UsesTheGivenValue(t *testing.T) {
	version := "0.9.4b1"
	container := newTestContainer("", version)
	if actualVersion := container.Version(); actualVersion != version {
		t.Errorf("Expected app name to be '%s', but was '%s'", version, actualVersion)
	}
}

func Test_Container_Name_DefaultstoUnreleasedIfUnset(t *testing.T) {
	container := newTestContainer("", "")
	if expected, actual := "unreleased", container.Version(); expected != actual {
		t.Errorf("Expected app version to be '%s', but was '%s'", expected, actual)
	}
}

func Test_Container_Syslog(t *testing.T) {
	logFilename := "syslog"
	container, err := newContainer("test", "", &logFilename, nil)
	if err != nil {
		fmt.Fprintf(os.Stderr, "WARNING: Could not create container, test will be skipped: '%v'\n", err)
		return
	}
	if err := container.Close(); err != nil {
		t.Errorf("Closing the syslog container returned '%v'", err)
	}
	log.Println("Testing")
	fp, err := os.Open(logFilename)
	if fp != nil {
		fp.Close()
	}
	if err == nil {
		t.Errorf("Logging created a file '%s' but should have logged to syslog", logFilename)
	} else if !os.IsNotExist(err) {
		t.Errorf("Logfile '%s' could not be opened but should not exist: '%v'", logFilename, err)
	}
}
<|endoftext|>


<commit_before>package hack

import (
	"bytes"
	"encoding/binary"
	"testing"
)

func TestString(t *testing.T) {
	b := []byte("hello world")
	a := String(b)

	if a != "hello world" {
		t.Fatal(a)
	}

	b[0] = 'a'

	if a != "aello world" {
		t.Fatal(a)
	}

	b = append(b, "abc"...)
	if a != "aello world" {
		t.Fatal(a)
	}
}

func TestByte(t *testing.T) {
	a := "hello world"

	b := Slice(a)

	if !bytes.Equal(b, []byte("hello world")) {
		t.Fatal(string(b))
	}
}
<commit_msg>update<commit_after>package hack

import (
	"bytes"
	"testing"
)

func TestString(t *testing.T) {
	b := []byte("hello world")
	a := String(b)

	if a != "hello world" {
		t.Fatal(a)
	}

	b[0] = 'a'

	if a != "aello world" {
		t.Fatal(a)
	}

	b = append(b, "abc"...)
	if a != "aello world" {
		t.Fatal(a)
	}
}

func TestByte(t *testing.T) {
	a := "hello world"

	b := Slice(a)

	if !bytes.Equal(b, []byte("hello world")) {
		t.Fatal(string(b))
	}
}
<|endoftext|>


<commit_before>package handler

import (
	"net/http"
)

func Render(w http.ResponseWriter, r *http.Request) {
}
<commit_msg>Support until/from query<commit_after>package handler

import (
	"net/http"
	"time"

	"github.com/yuuki/dynamond/log"
	"github.com/yuuki/dynamond/timeparser"
)

const (
	DAYTIME = time.Duration(24 * 60 * 60) * time.Second
)

func Render(w http.ResponseWriter, r *http.Request) {
	until := time.Now()
	from := until.Add(-DAYTIME)

	if v := r.FormValue("from"); v != "" {
		t, err := timeparser.ParseAtTime(v)
		if err != nil {
			BadRequest(w, err.Error())
			return
		}
		from = t
	}
	if v := r.FormValue("until"); v != "" {
		t, err := timeparser.ParseAtTime(v)
		if err != nil {
			BadRequest(w, err.Error())
			return
		}
		until = t
	}
	log.Debugf("from:%d until:%d", from.Unix(), until.Unix())

	return
}
<|endoftext|>


<commit_before>// 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.

package obsreport

import (
	"context"

	"go.opencensus.io/stats"
	"go.opencensus.io/tag"
	"go.opencensus.io/trace"

	"go.opentelemetry.io/collector/config"
	"go.opentelemetry.io/collector/config/configtelemetry"
	"go.opentelemetry.io/collector/internal/obsreportconfig"
	"go.opentelemetry.io/collector/internal/obsreportconfig/obsmetrics"
)

// StartReceiveOptions has the options related to starting a receive operation.
type StartReceiveOptions struct {
	// LongLivedCtx when true indicates that the context passed in the call
	// outlives the individual receive operation. See WithLongLivedCtx() for
	// more information.
	LongLivedCtx bool
}

// StartReceiveOption function applues changes to StartReceiveOptions.
type StartReceiveOption func(*StartReceiveOptions)

// WithLongLivedCtx indicates that the context passed in the call outlives the
// receive operation at hand. Typically the long lived context is associated
// to a connection, eg.: a gRPC stream or a TCP connection, for which many
// batches of data are received in individual operations without a corresponding
// new context per operation.
//
// Example:
//
//    func (r *receiver) ClientConnect(ctx context.Context, rcvChan <-chan pdata.Traces) {
//        longLivedCtx := obsreport.ReceiverContext(ctx, r.config.Name(), r.transport, "")
//        for {
//            // Since the context outlives the individual receive operations call obsreport using
//            // WithLongLivedCtx().
//            ctx := obsreport.StartTraceDataReceiveOp(
//                longLivedCtx,
//                r.config.Name(),
//                r.transport,
//                obsreport.WithLongLivedCtx())
//
//            td, ok := <-rcvChan
//            var err error
//            if ok {
//                err = r.nextConsumer.ConsumeTraces(ctx, td)
//            }
//            obsreport.EndTraceDataReceiveOp(
//                ctx,
//                r.format,
//                len(td.Spans),
//                err)
//            if !ok {
//                break
//            }
//        }
//    }
//
func WithLongLivedCtx() StartReceiveOption {
	return func(opts *StartReceiveOptions) {
		opts.LongLivedCtx = true
	}
}

// Receiver is a helper to add obersvability to a component.Receiver.
type Receiver struct {
	receiverID config.ComponentID
	transport  string
}

// ReceiverSettings are settings for creating an Receiver.
type ReceiverSettings struct {
	ReceiverID config.ComponentID
	Transport  string
}

// NewReceiver creates a new Receiver.
func NewReceiver(cfg ReceiverSettings) *Receiver {
	return &Receiver{
		receiverID: cfg.ReceiverID,
		transport:  cfg.Transport,
	}
}

// StartTraceDataReceiveOp is called when a request is received from a client.
// The returned context should be used in other calls to the obsreport functions
// dealing with the same receive operation.
func (rec *Receiver) StartTraceDataReceiveOp(
	operationCtx context.Context,
	opt ...StartReceiveOption,
) context.Context {
	return rec.traceReceiveOp(
		operationCtx,
		obsmetrics.ReceiveTraceDataOperationSuffix,
		opt...)
}

// StartTraceDataReceiveOp is deprecated but is called when a request is received from a client.
// The returned context should be used in other calls to the obsreport functions
// dealing with the same receive operation.
func StartTraceDataReceiveOp(
	operationCtx context.Context,
	receiverID config.ComponentID,
	transport string,
	opt ...StartReceiveOption,
) context.Context {
	rec := NewReceiver(ReceiverSettings{ReceiverID: receiverID, Transport: transport})
	return rec.traceReceiveOp(
		operationCtx,
		obsmetrics.ReceiveTraceDataOperationSuffix,
		opt...)
}

// EndTraceDataReceiveOp completes the receive operation that was started with
// StartTraceDataReceiveOp.
func (rec *Receiver) EndTraceDataReceiveOp(
	receiverCtx context.Context,
	format string,
	numReceivedSpans int,
	err error,
) {
	rec.endReceiveOp(
		receiverCtx,
		format,
		numReceivedSpans,
		err,
		config.TracesDataType,
	)
}

// EndTraceDataReceiveOp is deprecated but completes the receive operation that was started with
// StartTraceDataReceiveOp.
func EndTraceDataReceiveOp(
	receiverCtx context.Context,
	format string,
	numReceivedSpans int,
	err error,
) {
	rec := NewReceiver(ReceiverSettings{})
	rec.endReceiveOp(
		receiverCtx,
		format,
		numReceivedSpans,
		err,
		config.TracesDataType,
	)
}

// StartLogsReceiveOp is called when a request is received from a client.
// The returned context should be used in other calls to the obsreport functions
// dealing with the same receive operation.
func (rec *Receiver) StartLogsReceiveOp(
	operationCtx context.Context,
	opt ...StartReceiveOption,
) context.Context {
	return rec.traceReceiveOp(
		operationCtx,
		obsmetrics.ReceiverLogsOperationSuffix,
		opt...)
}

// StartLogsReceiveOp is deprecated but is called when a request is received from a client.
// The returned context should be used in other calls to the obsreport functions
// dealing with the same receive operation.
func StartLogsReceiveOp(
	operationCtx context.Context,
	receiverID config.ComponentID,
	transport string,
	opt ...StartReceiveOption,
) context.Context {
	rec := NewReceiver(ReceiverSettings{ReceiverID: receiverID, Transport: transport})
	return rec.traceReceiveOp(
		operationCtx,
		obsmetrics.ReceiverLogsOperationSuffix,
		opt...)
}

// EndLogsReceiveOp completes the receive operation that was started with
// StartLogsReceiveOp.
func (rec *Receiver) EndLogsReceiveOp(
	receiverCtx context.Context,
	format string,
	numReceivedLogRecords int,
	err error,
) {
	rec.endReceiveOp(
		receiverCtx,
		format,
		numReceivedLogRecords,
		err,
		config.LogsDataType,
	)
}

// EndLogsReceiveOp is deprecated but completes the receive operation that was started with
// StartLogsReceiveOp.
func EndLogsReceiveOp(
	receiverCtx context.Context,
	format string,
	numReceivedLogRecords int,
	err error,
) {
	rec := NewReceiver(ReceiverSettings{})
	rec.endReceiveOp(
		receiverCtx,
		format,
		numReceivedLogRecords,
		err,
		config.LogsDataType,
	)
}

// StartMetricsReceiveOp is called when a request is received from a client.
// The returned context should be used in other calls to the obsreport functions
// dealing with the same receive operation.
func (rec *Receiver) StartMetricsReceiveOp(
	operationCtx context.Context,
	opt ...StartReceiveOption,
) context.Context {
	return rec.traceReceiveOp(
		operationCtx,
		obsmetrics.ReceiverMetricsOperationSuffix,
		opt...)
}

// StartMetricsReceiveOp is deprecated but is called when a request is received from a client.
// The returned context should be used in other calls to the obsreport functions
// dealing with the same receive operation.
func StartMetricsReceiveOp(
	operationCtx context.Context,
	receiverID config.ComponentID,
	transport string,
	opt ...StartReceiveOption,
) context.Context {
	rec := NewReceiver(ReceiverSettings{ReceiverID: receiverID, Transport: transport})
	return rec.traceReceiveOp(
		operationCtx,
		obsmetrics.ReceiverMetricsOperationSuffix,
		opt...)
}

// EndMetricsReceiveOp completes the receive operation that was started with
// StartMetricsReceiveOp.
func (rec *Receiver) EndMetricsReceiveOp(
	receiverCtx context.Context,
	format string,
	numReceivedPoints int,
	err error,
) {
	rec.endReceiveOp(
		receiverCtx,
		format,
		numReceivedPoints,
		err,
		config.MetricsDataType,
	)
}

// EndMetricsReceiveOp is deprecated but completes the receive operation that was started with
// StartMetricsReceiveOp.
func EndMetricsReceiveOp(
	receiverCtx context.Context,
	format string,
	numReceivedPoints int,
	err error,
) {
	rec := NewReceiver(ReceiverSettings{})
	rec.endReceiveOp(
		receiverCtx,
		format,
		numReceivedPoints,
		err,
		config.MetricsDataType,
	)
}

// ReceiverContext adds the keys used when recording observability metrics to
// the given context returning the newly created context. This context should
// be used in related calls to the obsreport functions so metrics are properly
// recorded.
func ReceiverContext(
	ctx context.Context,
	receiverID config.ComponentID,
	transport string,
) context.Context {
	ctx, _ = tag.New(ctx,
		tag.Upsert(obsmetrics.TagKeyReceiver, receiverID.String(), tag.WithTTL(tag.TTLNoPropagation)),
		tag.Upsert(obsmetrics.TagKeyTransport, transport, tag.WithTTL(tag.TTLNoPropagation)))

	return ctx
}

// traceReceiveOp creates the span used to trace the operation. Returning
// the updated context with the created span.
func (rec *Receiver) traceReceiveOp(
	receiverCtx context.Context,
	operationSuffix string,
	opt ...StartReceiveOption,
) context.Context {
	var opts StartReceiveOptions
	for _, o := range opt {
		o(&opts)
	}

	var ctx context.Context
	var span *trace.Span
	spanName := obsmetrics.ReceiverPrefix + rec.receiverID.String() + operationSuffix
	if !opts.LongLivedCtx {
		ctx, span = trace.StartSpan(receiverCtx, spanName)
	} else {
		// Since the receiverCtx is long lived do not use it to start the span.
		// This way this trace ends when the EndTraceDataReceiveOp is called.
		// Here is safe to ignore the returned context since it is not used below.
		_, span = trace.StartSpan(context.Background(), spanName)

		// If the long lived context has a parent span, then add it as a parent link.
		setParentLink(receiverCtx, span)

		ctx = trace.NewContext(receiverCtx, span)
	}

	if rec.transport != "" {
		span.AddAttributes(trace.StringAttribute(obsmetrics.TransportKey, rec.transport))
	}
	return ctx
}

// endReceiveOp records the observability signals at the end of an operation.
func (rec *Receiver) endReceiveOp(
	receiverCtx context.Context,
	format string,
	numReceivedItems int,
	err error,
	dataType config.DataType,
) {
	numAccepted := numReceivedItems
	numRefused := 0
	if err != nil {
		numAccepted = 0
		numRefused = numReceivedItems
	}

	span := trace.FromContext(receiverCtx)

	if obsreportconfig.Level != configtelemetry.LevelNone {
		var acceptedMeasure, refusedMeasure *stats.Int64Measure
		switch dataType {
		case config.TracesDataType:
			acceptedMeasure = obsmetrics.ReceiverAcceptedSpans
			refusedMeasure = obsmetrics.ReceiverRefusedSpans
		case config.MetricsDataType:
			acceptedMeasure = obsmetrics.ReceiverAcceptedMetricPoints
			refusedMeasure = obsmetrics.ReceiverRefusedMetricPoints
		case config.LogsDataType:
			acceptedMeasure = obsmetrics.ReceiverAcceptedLogRecords
			refusedMeasure = obsmetrics.ReceiverRefusedLogRecords
		}

		stats.Record(
			receiverCtx,
			acceptedMeasure.M(int64(numAccepted)),
			refusedMeasure.M(int64(numRefused)))
	}

	// end span according to errors
	if span.IsRecordingEvents() {
		var acceptedItemsKey, refusedItemsKey string
		switch dataType {
		case config.TracesDataType:
			acceptedItemsKey = obsmetrics.AcceptedSpansKey
			refusedItemsKey = obsmetrics.RefusedSpansKey
		case config.MetricsDataType:
			acceptedItemsKey = obsmetrics.AcceptedMetricPointsKey
			refusedItemsKey = obsmetrics.RefusedMetricPointsKey
		case config.LogsDataType:
			acceptedItemsKey = obsmetrics.AcceptedLogRecordsKey
			refusedItemsKey = obsmetrics.RefusedLogRecordsKey
		}

		span.AddAttributes(
			trace.StringAttribute(
				obsmetrics.FormatKey, format),
			trace.Int64Attribute(
				acceptedItemsKey, int64(numAccepted)),
			trace.Int64Attribute(
				refusedItemsKey, int64(numRefused)),
		)
		span.SetStatus(errToStatus(err))
	}
	span.End()
}
<commit_msg>Remove deprecated funcs (#3314)<commit_after>// 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.

package obsreport

import (
	"context"

	"go.opencensus.io/stats"
	"go.opencensus.io/tag"
	"go.opencensus.io/trace"

	"go.opentelemetry.io/collector/config"
	"go.opentelemetry.io/collector/config/configtelemetry"
	"go.opentelemetry.io/collector/internal/obsreportconfig"
	"go.opentelemetry.io/collector/internal/obsreportconfig/obsmetrics"
)

// StartReceiveOptions has the options related to starting a receive operation.
type StartReceiveOptions struct {
	// LongLivedCtx when true indicates that the context passed in the call
	// outlives the individual receive operation. See WithLongLivedCtx() for
	// more information.
	LongLivedCtx bool
}

// StartReceiveOption function applues changes to StartReceiveOptions.
type StartReceiveOption func(*StartReceiveOptions)

// WithLongLivedCtx indicates that the context passed in the call outlives the
// receive operation at hand. Typically the long lived context is associated
// to a connection, eg.: a gRPC stream or a TCP connection, for which many
// batches of data are received in individual operations without a corresponding
// new context per operation.
//
// Example:
//
//    func (r *receiver) ClientConnect(ctx context.Context, rcvChan <-chan pdata.Traces) {
//        longLivedCtx := obsreport.ReceiverContext(ctx, r.config.Name(), r.transport, "")
//        for {
//            // Since the context outlives the individual receive operations call obsreport using
//            // WithLongLivedCtx().
//            ctx := obsreport.StartTraceDataReceiveOp(
//                longLivedCtx,
//                r.config.Name(),
//                r.transport,
//                obsreport.WithLongLivedCtx())
//
//            td, ok := <-rcvChan
//            var err error
//            if ok {
//                err = r.nextConsumer.ConsumeTraces(ctx, td)
//            }
//            obsreport.EndTraceDataReceiveOp(
//                ctx,
//                r.format,
//                len(td.Spans),
//                err)
//            if !ok {
//                break
//            }
//        }
//    }
//
func WithLongLivedCtx() StartReceiveOption {
	return func(opts *StartReceiveOptions) {
		opts.LongLivedCtx = true
	}
}

// Receiver is a helper to add obersvability to a component.Receiver.
type Receiver struct {
	receiverID config.ComponentID
	transport  string
}

// ReceiverSettings are settings for creating an Receiver.
type ReceiverSettings struct {
	ReceiverID config.ComponentID
	Transport  string
}

// NewReceiver creates a new Receiver.
func NewReceiver(cfg ReceiverSettings) *Receiver {
	return &Receiver{
		receiverID: cfg.ReceiverID,
		transport:  cfg.Transport,
	}
}

// StartTraceDataReceiveOp is called when a request is received from a client.
// The returned context should be used in other calls to the obsreport functions
// dealing with the same receive operation.
func (rec *Receiver) StartTraceDataReceiveOp(
	operationCtx context.Context,
	opt ...StartReceiveOption,
) context.Context {
	return rec.traceReceiveOp(
		operationCtx,
		obsmetrics.ReceiveTraceDataOperationSuffix,
		opt...)
}

// EndTraceDataReceiveOp completes the receive operation that was started with
// StartTraceDataReceiveOp.
func (rec *Receiver) EndTraceDataReceiveOp(
	receiverCtx context.Context,
	format string,
	numReceivedSpans int,
	err error,
) {
	rec.endReceiveOp(
		receiverCtx,
		format,
		numReceivedSpans,
		err,
		config.TracesDataType,
	)
}

// StartLogsReceiveOp is called when a request is received from a client.
// The returned context should be used in other calls to the obsreport functions
// dealing with the same receive operation.
func (rec *Receiver) StartLogsReceiveOp(
	operationCtx context.Context,
	opt ...StartReceiveOption,
) context.Context {
	return rec.traceReceiveOp(
		operationCtx,
		obsmetrics.ReceiverLogsOperationSuffix,
		opt...)
}

// EndLogsReceiveOp completes the receive operation that was started with
// StartLogsReceiveOp.
func (rec *Receiver) EndLogsReceiveOp(
	receiverCtx context.Context,
	format string,
	numReceivedLogRecords int,
	err error,
) {
	rec.endReceiveOp(
		receiverCtx,
		format,
		numReceivedLogRecords,
		err,
		config.LogsDataType,
	)
}

// StartMetricsReceiveOp is called when a request is received from a client.
// The returned context should be used in other calls to the obsreport functions
// dealing with the same receive operation.
func (rec *Receiver) StartMetricsReceiveOp(
	operationCtx context.Context,
	opt ...StartReceiveOption,
) context.Context {
	return rec.traceReceiveOp(
		operationCtx,
		obsmetrics.ReceiverMetricsOperationSuffix,
		opt...)
}

// EndMetricsReceiveOp completes the receive operation that was started with
// StartMetricsReceiveOp.
func (rec *Receiver) EndMetricsReceiveOp(
	receiverCtx context.Context,
	format string,
	numReceivedPoints int,
	err error,
) {
	rec.endReceiveOp(
		receiverCtx,
		format,
		numReceivedPoints,
		err,
		config.MetricsDataType,
	)
}

// ReceiverContext adds the keys used when recording observability metrics to
// the given context returning the newly created context. This context should
// be used in related calls to the obsreport functions so metrics are properly
// recorded.
func ReceiverContext(
	ctx context.Context,
	receiverID config.ComponentID,
	transport string,
) context.Context {
	ctx, _ = tag.New(ctx,
		tag.Upsert(obsmetrics.TagKeyReceiver, receiverID.String(), tag.WithTTL(tag.TTLNoPropagation)),
		tag.Upsert(obsmetrics.TagKeyTransport, transport, tag.WithTTL(tag.TTLNoPropagation)))

	return ctx
}

// traceReceiveOp creates the span used to trace the operation. Returning
// the updated context with the created span.
func (rec *Receiver) traceReceiveOp(
	receiverCtx context.Context,
	operationSuffix string,
	opt ...StartReceiveOption,
) context.Context {
	var opts StartReceiveOptions
	for _, o := range opt {
		o(&opts)
	}

	var ctx context.Context
	var span *trace.Span
	spanName := obsmetrics.ReceiverPrefix + rec.receiverID.String() + operationSuffix
	if !opts.LongLivedCtx {
		ctx, span = trace.StartSpan(receiverCtx, spanName)
	} else {
		// Since the receiverCtx is long lived do not use it to start the span.
		// This way this trace ends when the EndTraceDataReceiveOp is called.
		// Here is safe to ignore the returned context since it is not used below.
		_, span = trace.StartSpan(context.Background(), spanName)

		// If the long lived context has a parent span, then add it as a parent link.
		setParentLink(receiverCtx, span)

		ctx = trace.NewContext(receiverCtx, span)
	}

	if rec.transport != "" {
		span.AddAttributes(trace.StringAttribute(obsmetrics.TransportKey, rec.transport))
	}
	return ctx
}

// endReceiveOp records the observability signals at the end of an operation.
func (rec *Receiver) endReceiveOp(
	receiverCtx context.Context,
	format string,
	numReceivedItems int,
	err error,
	dataType config.DataType,
) {
	numAccepted := numReceivedItems
	numRefused := 0
	if err != nil {
		numAccepted = 0
		numRefused = numReceivedItems
	}

	span := trace.FromContext(receiverCtx)

	if obsreportconfig.Level != configtelemetry.LevelNone {
		var acceptedMeasure, refusedMeasure *stats.Int64Measure
		switch dataType {
		case config.TracesDataType:
			acceptedMeasure = obsmetrics.ReceiverAcceptedSpans
			refusedMeasure = obsmetrics.ReceiverRefusedSpans
		case config.MetricsDataType:
			acceptedMeasure = obsmetrics.ReceiverAcceptedMetricPoints
			refusedMeasure = obsmetrics.ReceiverRefusedMetricPoints
		case config.LogsDataType:
			acceptedMeasure = obsmetrics.ReceiverAcceptedLogRecords
			refusedMeasure = obsmetrics.ReceiverRefusedLogRecords
		}

		stats.Record(
			receiverCtx,
			acceptedMeasure.M(int64(numAccepted)),
			refusedMeasure.M(int64(numRefused)))
	}

	// end span according to errors
	if span.IsRecordingEvents() {
		var acceptedItemsKey, refusedItemsKey string
		switch dataType {
		case config.TracesDataType:
			acceptedItemsKey = obsmetrics.AcceptedSpansKey
			refusedItemsKey = obsmetrics.RefusedSpansKey
		case config.MetricsDataType:
			acceptedItemsKey = obsmetrics.AcceptedMetricPointsKey
			refusedItemsKey = obsmetrics.RefusedMetricPointsKey
		case config.LogsDataType:
			acceptedItemsKey = obsmetrics.AcceptedLogRecordsKey
			refusedItemsKey = obsmetrics.RefusedLogRecordsKey
		}

		span.AddAttributes(
			trace.StringAttribute(
				obsmetrics.FormatKey, format),
			trace.Int64Attribute(
				acceptedItemsKey, int64(numAccepted)),
			trace.Int64Attribute(
				refusedItemsKey, int64(numRefused)),
		)
		span.SetStatus(errToStatus(err))
	}
	span.End()
}
<|endoftext|>


<commit_before>package datadog

import (
	"bytes"
	"fmt"
	"log"
	"strconv"
	"strings"
	"time"

	"github.com/zorkian/go-datadog-api"

	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/schema"
)

// graphDefintionRequests works around the nested struct in
// https://github.com/zorkian/go-datadog-api/blob/master/dashboards.go#L16
type graphDefintionRequests struct {
	Query   string `json:"q"`
	Stacked bool   `json:"stacked"`
}

// resourceDatadogGraph is a Datadog graph resource. It is a virtual resource as there are no autonomous graphs in
// Datadog.
func resourceDatadogGraph() *schema.Resource {
	return &schema.Resource{
		Create: resourceDatadogGraphCreate,
		Exists: resourceDatadogGraphExists,
		Read:   resourceDatadogGraphRead,
		Delete: resourceDatadogGraphDelete,
		Update: resourceDatadogGraphUpdate,

		Schema: map[string]*schema.Schema{
			"dashboard_id": &schema.Schema{
				Type: schema.TypeInt,
				Required: true,
			},
			"title": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},
			"viz": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},
			"request": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				ForceNew: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"query": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
						"stacked": &schema.Schema{
							Type:     schema.TypeBool,
							Required: true,
						},
					},
				},
				Set: resourceDatadogRequestHash,
			},
			// TODO: support events.
		},
	}
}

// resourceDatadogGraphCreate creates a graph on associated dashboard(s).
func resourceDatadogGraphCreate(d *schema.ResourceData, meta interface{}) error {
	// This should create graphs associated with dashboards.
	// it's a virtual resource, a la "resource_vpn_connection_route"
	// hence we will need to do a bit of hacking to find out what dashboard.

	// TODO: Delete placeholder graph. See https://github.com/ojongerius/terraform-provider-datadog/issues/8

	if d.Id() == "" {
		ID := int(time.Now().Unix())
		d.SetId(strconv.Itoa(ID)) // Use seconds since Epoch, needs to be a string when saving.

		log.Printf("[INFO] Graph ID: %d", ID)
	}

	resourceDatadogGraphUpdate(d, meta)

	err := resourceDatadogGraphRetrieve(d, meta)

	if err != nil {
		return err
	}

	return nil
}

// resourceDatadogGraphExists verifies is a graph exists.
func resourceDatadogGraphExists(d *schema.ResourceData, meta interface{}) (bool, error) {
	client := meta.(*datadog.Client)

	// Verify our Dashboard(s) exist
	_, err := client.GetDashboard(d.Get("dashboard_id").(int))

	if err != nil {
		if strings.EqualFold(err.Error(), "API error: 404 Not Found") {
			return false, nil
		}

		return false, fmt.Errorf("Error retrieving dashboard: %s", err)
	}

	// Verify we exist
	err = resourceDatadogGraphRead(d, meta)

	if err != nil {
		return false, err
	}

	return true, nil
}

// resourceDatadogGraphRead synchronises Datadog and local state. It uses resourceDatadogGraphRetreive for this.
func resourceDatadogGraphRead(d *schema.ResourceData, meta interface{}) error {
	err := resourceDatadogGraphRetrieve(d, meta)

	if err != nil {
		return err
	}

	return nil
}

// resourceDatadogGraphRetreive synchronises Datadog and local state.
func resourceDatadogGraphRetrieve(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*datadog.Client)

	// Get the dashboard(s)
	dashBoard, err := client.GetDashboard(d.Get("dashboard_id").(int))

	if err != nil {
		return fmt.Errorf("Error retrieving associated dashboard: %s", err)
	}

	// Walk through the graphs
	for _, g := range dashBoard.Graphs {
		// If it ends with our ID, it's us:
		if strings.HasSuffix(g.Title, fmt.Sprintf("(%s)", d.Id())) {
			log.Printf("[DEBUG] Found matching graph. Start setting/saving state.")
			d.Set("dashboard_id", d.Get("dashboard_id"))
			// Save title to state, but strip ID
			d.Set("title", strings.Replace(g.Title, fmt.Sprintf(" (%s)", d.Id()), "", 1))
			d.Set("viz", g.Definition.Viz)

			// Create an empty schema to hold all the requests.
			request := &schema.Set{F: resourceDatadogRequestHash}

			for _, r := range g.Definition.Requests {
				m := make(map[string]interface{})

				if r.Query != "" {
					m["query"] = r.Query
				}

				m["stacked"] = r.Stacked

				request.Add(m)
			}

			d.Set("request", request)

			return nil

		}
	}

	// If we are still around we've not found ourselves. Set SetId to empty and Terraform will create the resource for us.
	d.SetId("")

	return nil
}

// resourceDatadogGraphUpdate updates a graph.
func resourceDatadogGraphUpdate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*datadog.Client)

	// Get the dashboard
	dashboard, err := client.GetDashboard(d.Get("dashboard_id").(int))

	// Make sure the mandatory placeholder is not in there
	dashboard = buildGraph("Mandatory placeholder graph", dashboard)

	if err != nil {
		return err
	}

	// Check if there are changes
	if d.HasChange("request") {
		graphDefinition := datadog.Graph{}.Definition
		graphRequests := datadog.Graph{}.Definition.Requests
		graphDefinition.Viz = d.Get("viz").(string)

		log.Printf("[DEBUG] Request has changed.")
		o, n := d.GetChange("request")
		ors := o.(*schema.Set).Difference(n.(*schema.Set))
		nrs := n.(*schema.Set).Difference(o.(*schema.Set))

		// Loop through all the old requests and delete any obsolete ones
		for _, request := range ors.List() {
			m := request.(map[string]interface{})

			// TODO: implement
			// Delete the query as it no longer exists in the config
			log.Printf("[DEBUG] Deleting graph query %s", m["query"].(string))
			log.Printf("[DEBUG] Deleting graph stacked %t", m["stacked"].(bool))

		}
		// Loop through all the new requests and append them
		for _, request := range nrs.List() {
			m := request.(map[string]interface{})

			// Add the request
			log.Printf("[DEBUG] Adding graph query %s", m["query"].(string))
			log.Printf("[DEBUG] Adding graph stacked %t", m["stacked"].(bool))
			graphRequests = append(graphRequests, graphDefintionRequests{Query: m["query"].(string),
				Stacked: m["stacked"].(bool)})
		}

		// Add requests to the graph definition
		graphDefinition.Requests = graphRequests
		title := d.Get("title").(string) + fmt.Sprintf(" (%s)", d.Id())
		g := datadog.Graph{Title: title, Definition: graphDefinition}

		dashboard.Graphs = append(dashboard.Graphs, g) // Should be done for each
	}

	// Update/commit
	err = client.UpdateDashboard(dashboard)

	if err != nil {
		return err
	}

	return nil
}

// resourceDatadogGraphDelete deletes a graph.
func resourceDatadogGraphDelete(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*datadog.Client)

	// Get the dashboard
	dashboard, err := client.GetDashboard(d.Get("dashboard_id").(int))

	if err != nil {
		return fmt.Errorf("Error retrieving associated dashboard: %s", err)
	}

	// Get the dashboard without the Graph to delete
	dashboard = buildGraph(fmt.Sprintf("(%s)", d.Id()), dashboard)

	// Test if we need to reinsert the Mandatory graph
	if len(dashboard.Graphs) < 2 {
		dashboard.Graphs = createPlaceholderGraph()
	}

	// Update/commit
	err = client.UpdateDashboard(dashboard)

	if err != nil {
		return err
	}

	err = resourceDatadogGraphRetrieve(d, meta)

	if err != nil {
		return err
	}

	return nil
}

// resourceDatadogRequestHash creates a hash, used by schema.TypeSet to detect change.
func resourceDatadogRequestHash(v interface{}) int {
	var buf bytes.Buffer
	m := v.(map[string]interface{})

	if v, ok := m["query"]; ok {
		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
	}

	if v, ok := m["stacked"]; ok {
		buf.WriteString(fmt.Sprintf("%t-", v.(bool)))
	}

	return hashcode.String(buf.String())
}

// buildGraph can be used to create a placeholder graph, used to create new dashboards, as the Datadog API does not
// support creation of dashboards without graphs.
func buildGraph(title string, dashboard *datadog.Dashboard) *datadog.Dashboard {
	// Build a new slice of graphs, excluding graphs matching title.
	g := []datadog.Graph{}
	for _, r := range dashboard.Graphs {
		if r.Title == title {
			continue
		} else {
			g = append(g, r)
		}
	}

	dashboard.Graphs = g

	return dashboard
}
<commit_msg>Gofmt.<commit_after>package datadog

import (
	"bytes"
	"fmt"
	"log"
	"strconv"
	"strings"
	"time"

	"github.com/zorkian/go-datadog-api"

	"github.com/hashicorp/terraform/helper/hashcode"
	"github.com/hashicorp/terraform/helper/schema"
)

// graphDefintionRequests works around the nested struct in
// https://github.com/zorkian/go-datadog-api/blob/master/dashboards.go#L16
type graphDefintionRequests struct {
	Query   string `json:"q"`
	Stacked bool   `json:"stacked"`
}

// resourceDatadogGraph is a Datadog graph resource. It is a virtual resource as there are no autonomous graphs in
// Datadog.
func resourceDatadogGraph() *schema.Resource {
	return &schema.Resource{
		Create: resourceDatadogGraphCreate,
		Exists: resourceDatadogGraphExists,
		Read:   resourceDatadogGraphRead,
		Delete: resourceDatadogGraphDelete,
		Update: resourceDatadogGraphUpdate,

		Schema: map[string]*schema.Schema{
			"dashboard_id": &schema.Schema{
				Type:     schema.TypeInt,
				Required: true,
			},
			"title": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},
			"viz": &schema.Schema{
				Type:     schema.TypeString,
				Required: true,
			},
			"request": &schema.Schema{
				Type:     schema.TypeSet,
				Optional: true,
				ForceNew: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"query": &schema.Schema{
							Type:     schema.TypeString,
							Required: true,
						},
						"stacked": &schema.Schema{
							Type:     schema.TypeBool,
							Required: true,
						},
					},
				},
				Set: resourceDatadogRequestHash,
			},
			// TODO: support events.
		},
	}
}

// resourceDatadogGraphCreate creates a graph on associated dashboard(s).
func resourceDatadogGraphCreate(d *schema.ResourceData, meta interface{}) error {
	// This should create graphs associated with dashboards.
	// it's a virtual resource, a la "resource_vpn_connection_route"
	// hence we will need to do a bit of hacking to find out what dashboard.

	// TODO: Delete placeholder graph. See https://github.com/ojongerius/terraform-provider-datadog/issues/8

	if d.Id() == "" {
		ID := int(time.Now().Unix())
		d.SetId(strconv.Itoa(ID)) // Use seconds since Epoch, needs to be a string when saving.

		log.Printf("[INFO] Graph ID: %d", ID)
	}

	resourceDatadogGraphUpdate(d, meta)

	err := resourceDatadogGraphRetrieve(d, meta)

	if err != nil {
		return err
	}

	return nil
}

// resourceDatadogGraphExists verifies is a graph exists.
func resourceDatadogGraphExists(d *schema.ResourceData, meta interface{}) (bool, error) {
	client := meta.(*datadog.Client)

	// Verify our Dashboard(s) exist
	_, err := client.GetDashboard(d.Get("dashboard_id").(int))

	if err != nil {
		if strings.EqualFold(err.Error(), "API error: 404 Not Found") {
			return false, nil
		}

		return false, fmt.Errorf("Error retrieving dashboard: %s", err)
	}

	// Verify we exist
	err = resourceDatadogGraphRead(d, meta)

	if err != nil {
		return false, err
	}

	return true, nil
}

// resourceDatadogGraphRead synchronises Datadog and local state. It uses resourceDatadogGraphRetreive for this.
func resourceDatadogGraphRead(d *schema.ResourceData, meta interface{}) error {
	err := resourceDatadogGraphRetrieve(d, meta)

	if err != nil {
		return err
	}

	return nil
}

// resourceDatadogGraphRetreive synchronises Datadog and local state.
func resourceDatadogGraphRetrieve(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*datadog.Client)

	// Get the dashboard(s)
	dashBoard, err := client.GetDashboard(d.Get("dashboard_id").(int))

	if err != nil {
		return fmt.Errorf("Error retrieving associated dashboard: %s", err)
	}

	// Walk through the graphs
	for _, g := range dashBoard.Graphs {
		// If it ends with our ID, it's us:
		if strings.HasSuffix(g.Title, fmt.Sprintf("(%s)", d.Id())) {
			log.Printf("[DEBUG] Found matching graph. Start setting/saving state.")
			d.Set("dashboard_id", d.Get("dashboard_id"))
			// Save title to state, but strip ID
			d.Set("title", strings.Replace(g.Title, fmt.Sprintf(" (%s)", d.Id()), "", 1))
			d.Set("viz", g.Definition.Viz)

			// Create an empty schema to hold all the requests.
			request := &schema.Set{F: resourceDatadogRequestHash}

			for _, r := range g.Definition.Requests {
				m := make(map[string]interface{})

				if r.Query != "" {
					m["query"] = r.Query
				}

				m["stacked"] = r.Stacked

				request.Add(m)
			}

			d.Set("request", request)

			return nil

		}
	}

	// If we are still around we've not found ourselves. Set SetId to empty and Terraform will create the resource for us.
	d.SetId("")

	return nil
}

// resourceDatadogGraphUpdate updates a graph.
func resourceDatadogGraphUpdate(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*datadog.Client)

	// Get the dashboard
	dashboard, err := client.GetDashboard(d.Get("dashboard_id").(int))

	// Make sure the mandatory placeholder is not in there
	dashboard = buildGraph("Mandatory placeholder graph", dashboard)

	if err != nil {
		return err
	}

	// Check if there are changes
	if d.HasChange("request") {
		graphDefinition := datadog.Graph{}.Definition
		graphRequests := datadog.Graph{}.Definition.Requests
		graphDefinition.Viz = d.Get("viz").(string)

		log.Printf("[DEBUG] Request has changed.")
		o, n := d.GetChange("request")
		ors := o.(*schema.Set).Difference(n.(*schema.Set))
		nrs := n.(*schema.Set).Difference(o.(*schema.Set))

		// Loop through all the old requests and delete any obsolete ones
		for _, request := range ors.List() {
			m := request.(map[string]interface{})

			// TODO: implement
			// Delete the query as it no longer exists in the config
			log.Printf("[DEBUG] Deleting graph query %s", m["query"].(string))
			log.Printf("[DEBUG] Deleting graph stacked %t", m["stacked"].(bool))

		}
		// Loop through all the new requests and append them
		for _, request := range nrs.List() {
			m := request.(map[string]interface{})

			// Add the request
			log.Printf("[DEBUG] Adding graph query %s", m["query"].(string))
			log.Printf("[DEBUG] Adding graph stacked %t", m["stacked"].(bool))
			graphRequests = append(graphRequests, graphDefintionRequests{Query: m["query"].(string),
				Stacked: m["stacked"].(bool)})
		}

		// Add requests to the graph definition
		graphDefinition.Requests = graphRequests
		title := d.Get("title").(string) + fmt.Sprintf(" (%s)", d.Id())
		g := datadog.Graph{Title: title, Definition: graphDefinition}

		dashboard.Graphs = append(dashboard.Graphs, g) // Should be done for each
	}

	// Update/commit
	err = client.UpdateDashboard(dashboard)

	if err != nil {
		return err
	}

	return nil
}

// resourceDatadogGraphDelete deletes a graph.
func resourceDatadogGraphDelete(d *schema.ResourceData, meta interface{}) error {
	client := meta.(*datadog.Client)

	// Get the dashboard
	dashboard, err := client.GetDashboard(d.Get("dashboard_id").(int))

	if err != nil {
		return fmt.Errorf("Error retrieving associated dashboard: %s", err)
	}

	// Get the dashboard without the Graph to delete
	dashboard = buildGraph(fmt.Sprintf("(%s)", d.Id()), dashboard)

	// Test if we need to reinsert the Mandatory graph
	if len(dashboard.Graphs) < 2 {
		dashboard.Graphs = createPlaceholderGraph()
	}

	// Update/commit
	err = client.UpdateDashboard(dashboard)

	if err != nil {
		return err
	}

	err = resourceDatadogGraphRetrieve(d, meta)

	if err != nil {
		return err
	}

	return nil
}

// resourceDatadogRequestHash creates a hash, used by schema.TypeSet to detect change.
func resourceDatadogRequestHash(v interface{}) int {
	var buf bytes.Buffer
	m := v.(map[string]interface{})

	if v, ok := m["query"]; ok {
		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
	}

	if v, ok := m["stacked"]; ok {
		buf.WriteString(fmt.Sprintf("%t-", v.(bool)))
	}

	return hashcode.String(buf.String())
}

// buildGraph can be used to create a placeholder graph, used to create new dashboards, as the Datadog API does not
// support creation of dashboards without graphs.
func buildGraph(title string, dashboard *datadog.Dashboard) *datadog.Dashboard {
	// Build a new slice of graphs, excluding graphs matching title.
	g := []datadog.Graph{}
	for _, r := range dashboard.Graphs {
		if r.Title == title {
			continue
		} else {
			g = append(g, r)
		}
	}

	dashboard.Graphs = g

	return dashboard
}
<|endoftext|>


<commit_before>package hashicorp

import (
	"bytes"
	"fmt"
	"io"
	"sync/atomic"
	"time"

	"golang.org/x/net/context"

	"github.com/Sirupsen/logrus"
	"github.com/hashicorp/go-msgpack/codec"
	hraft "github.com/hashicorp/raft"
	"github.com/relab/raft"
	"github.com/relab/raft/commonpb"
)

type future struct {
	apply hraft.ApplyFuture
	index hraft.IndexFuture
	res   chan raft.Result
	start time.Time
	lat   *raft.Latency
}

func (f *future) ResultCh() <-chan raft.Result {
	go func() {
		confChange := false
		var g hraft.Future = f.apply
		if g == nil {
			confChange = true
			g = f.index
		}
		err := g.Error()

		if err != nil {
			f.res <- raft.Result{
				Value: err,
			}
			return
		}

		f.lat.Record(f.start)

		if !confChange {
			f.res <- raft.Result{
				Index: f.apply.Index(),
				Value: f.apply.Response(),
			}
			return
		}
		f.res <- raft.Result{
			Index: f.index.Index(),
			Value: &commonpb.ReconfResponse{
				Status: commonpb.ReconfOK,
			},
		}
	}()

	return f.res
}

// Wrapper wraps a hashicorp/raft.Raft and implements relab/raft.Raft.
type Wrapper struct {
	id      hraft.ServerID
	n       *hraft.Raft
	sm      raft.StateMachine
	servers []hraft.Server
	conf    hraft.Configuration
	lat     *raft.Latency
	event   *raft.Event
	leader  uint64
	logger  logrus.FieldLogger
}

func NewRaft(logger logrus.FieldLogger,
	sm raft.StateMachine, cfg *hraft.Config, servers []hraft.Server, trans hraft.Transport,
	logs hraft.LogStore, stable hraft.StableStore, snaps hraft.SnapshotStore,
	enabled []uint64,
	lat *raft.Latency, event *raft.Event,
	leaderOut chan struct{},
	id uint64,
	checkQuorum bool,
) *Wrapper {
	w := &Wrapper{
		id:      cfg.LocalID,
		sm:      sm,
		servers: servers,
		lat:     lat,
		event:   event,
		logger:  logger,
	}

	node, err := hraft.NewRaft(cfg, w, logs, stable, snaps, trans, event, checkQuorum)
	if err != nil {
		panic(err)
	}

	voters := make([]hraft.Server, len(enabled))

	for i, id := range enabled {
		voters[i] = servers[id-1]
	}

	w.conf = hraft.Configuration{Servers: voters}

	if servers[id-1].Suffrage == hraft.Voter {
		f := node.BootstrapCluster(w.conf)
		if err := f.Error(); err != nil {
			panic(err)
		}
	}

	w.n = node
	rmetrics.leader.Set(0)

	go func() {
		for {
			if <-node.LeaderCh() {
				atomic.StoreUint64(&w.leader, 1)
				event.Record(raft.EventBecomeLeader)
				rmetrics.leader.Set(float64(id))
				select {
				case leaderOut <- struct{}{}:
					w.logger.Warnln("Sent become leader")
				default:
					w.logger.Warnln("Skipped sending become leader")
				}
			} else {
				atomic.StoreUint64(&w.leader, 0)
				rmetrics.leader.Set(0)
			}
		}
	}()

	return w
}

func (w *Wrapper) ProposeCmd(ctx context.Context, req []byte) (raft.Future, error) {
	deadline, _ := ctx.Deadline()
	timeout := time.Until(deadline)
	ff := &future{lat: w.lat, start: time.Now(), res: make(chan raft.Result, 1)}
	ff.apply = w.n.Apply(req, timeout)

	return ff, nil
}

func (w *Wrapper) ReadCmd(context.Context, []byte) (raft.Future, error) {
	panic("ReadCmd not implemented")
}

func (w *Wrapper) ProposeConf(ctx context.Context, req *commonpb.ReconfRequest) (raft.Future, error) {
	deadline, _ := ctx.Deadline()
	timeout := time.Until(deadline)
	server := w.servers[req.ServerID-1]
	ff := &future{lat: w.lat, start: time.Now(), res: make(chan raft.Result, 1)}

	switch req.ReconfType {
	case commonpb.ReconfAdd:
		w.event.Record(raft.EventProposeAddServer)
		ff.index = w.n.AddVoter(server.ID, server.Address, 0, timeout)
	case commonpb.ReconfRemove:
		w.event.Record(raft.EventProposeRemoveServer)
		ff.index = w.n.RemoveServer(server.ID, 0, timeout)
	default:
		panic("invalid reconf type")
	}

	return ff, nil
}

func (w *Wrapper) Apply(logentry *hraft.Log) interface{} {
	rmetrics.commitIndex.Set(float64(logentry.Index))
	if atomic.LoadUint64(&w.leader) != 1 {
		w.lat.Record(time.Now())
	}

	switch logentry.Type {
	case hraft.LogCommand:
		res := w.sm.Apply(&commonpb.Entry{
			Term:      logentry.Term,
			Index:     logentry.Index,
			EntryType: commonpb.EntryNormal,
			Data:      logentry.Data,
		})
		return res
	case hraft.LogConfiguration:
		var configuration hraft.Configuration
		if err := decodeMsgPack(logentry.Data, &configuration); err != nil {
			panic(fmt.Errorf("failed to decode configuration: %v", err))
		}
		// If the server didn't have a vote in the previous conf., but
		// have a vote in the new configuration, this follower have
		// recently been added and are now caught up.
		if !hasVote(w.conf, w.id) && hasVote(configuration, w.id) {
			w.event.Record(raft.EventCaughtUp)
		}
		w.conf = configuration
	}

	panic(fmt.Sprintf("no case for logtype: %v", logentry.Type))
}

func (w *Wrapper) Snapshot() (hraft.FSMSnapshot, error) { return &snapStore{}, nil }
func (w *Wrapper) Restore(io.ReadCloser) error          { return nil }

type snapStore struct{}

func (s *snapStore) Persist(sink hraft.SnapshotSink) error { return nil }
func (s *snapStore) Release()                              {}

// Decode reverses the encode operation on a byte slice input.
// From hashicorp/raft/util.go.
func decodeMsgPack(buf []byte, out interface{}) error {
	r := bytes.NewBuffer(buf)
	hd := codec.MsgpackHandle{}
	dec := codec.NewDecoder(r, &hd)
	return dec.Decode(out)
}

// hasVote returns true if the server identified by 'id' is a Voter in the
// provided Configuration.
// From hashicorp/raft/configuration.go.
func hasVote(configuration hraft.Configuration, id hraft.ServerID) bool {
	for _, server := range configuration.Servers {
		if server.ID == id {
			return server.Suffrage == hraft.Voter
		}
	}
	return false
}
<commit_msg>hashicorp/raft.go: Record add and remove server events<commit_after>package hashicorp

import (
	"bytes"
	"fmt"
	"io"
	"sync/atomic"
	"time"

	"golang.org/x/net/context"

	"github.com/Sirupsen/logrus"
	"github.com/hashicorp/go-msgpack/codec"
	hraft "github.com/hashicorp/raft"
	"github.com/relab/raft"
	"github.com/relab/raft/commonpb"
)

type future struct {
	apply hraft.ApplyFuture
	index hraft.IndexFuture
	res   chan raft.Result
	start time.Time
	lat   *raft.Latency
}

func (f *future) ResultCh() <-chan raft.Result {
	go func() {
		confChange := false
		var g hraft.Future = f.apply
		if g == nil {
			confChange = true
			g = f.index
		}
		err := g.Error()

		if err != nil {
			f.res <- raft.Result{
				Value: err,
			}
			return
		}

		f.lat.Record(f.start)

		if !confChange {
			f.res <- raft.Result{
				Index: f.apply.Index(),
				Value: f.apply.Response(),
			}
			return
		}
		f.res <- raft.Result{
			Index: f.index.Index(),
			Value: &commonpb.ReconfResponse{
				Status: commonpb.ReconfOK,
			},
		}
	}()

	return f.res
}

// Wrapper wraps a hashicorp/raft.Raft and implements relab/raft.Raft.
type Wrapper struct {
	id      hraft.ServerID
	n       *hraft.Raft
	sm      raft.StateMachine
	servers []hraft.Server
	conf    hraft.Configuration
	lat     *raft.Latency
	event   *raft.Event
	leader  uint64
	logger  logrus.FieldLogger
}

func NewRaft(logger logrus.FieldLogger,
	sm raft.StateMachine, cfg *hraft.Config, servers []hraft.Server, trans hraft.Transport,
	logs hraft.LogStore, stable hraft.StableStore, snaps hraft.SnapshotStore,
	enabled []uint64,
	lat *raft.Latency, event *raft.Event,
	leaderOut chan struct{},
	id uint64,
	checkQuorum bool,
) *Wrapper {
	w := &Wrapper{
		id:      cfg.LocalID,
		sm:      sm,
		servers: servers,
		lat:     lat,
		event:   event,
		logger:  logger,
	}

	node, err := hraft.NewRaft(cfg, w, logs, stable, snaps, trans, event, checkQuorum)
	if err != nil {
		panic(err)
	}

	voters := make([]hraft.Server, len(enabled))

	for i, id := range enabled {
		voters[i] = servers[id-1]
	}

	w.conf = hraft.Configuration{Servers: voters}

	if servers[id-1].Suffrage == hraft.Voter {
		f := node.BootstrapCluster(w.conf)
		if err := f.Error(); err != nil {
			panic(err)
		}
	}

	w.n = node
	rmetrics.leader.Set(0)

	go func() {
		for {
			if <-node.LeaderCh() {
				atomic.StoreUint64(&w.leader, 1)
				event.Record(raft.EventBecomeLeader)
				rmetrics.leader.Set(float64(id))
				select {
				case leaderOut <- struct{}{}:
					w.logger.Warnln("Sent become leader")
				default:
					w.logger.Warnln("Skipped sending become leader")
				}
			} else {
				atomic.StoreUint64(&w.leader, 0)
				rmetrics.leader.Set(0)
			}
		}
	}()

	return w
}

func (w *Wrapper) ProposeCmd(ctx context.Context, req []byte) (raft.Future, error) {
	deadline, _ := ctx.Deadline()
	timeout := time.Until(deadline)
	ff := &future{lat: w.lat, start: time.Now(), res: make(chan raft.Result, 1)}
	ff.apply = w.n.Apply(req, timeout)

	return ff, nil
}

func (w *Wrapper) ReadCmd(context.Context, []byte) (raft.Future, error) {
	panic("ReadCmd not implemented")
}

func (w *Wrapper) ProposeConf(ctx context.Context, req *commonpb.ReconfRequest) (raft.Future, error) {
	deadline, _ := ctx.Deadline()
	timeout := time.Until(deadline)
	server := w.servers[req.ServerID-1]
	ff := &future{lat: w.lat, start: time.Now(), res: make(chan raft.Result, 1)}

	switch req.ReconfType {
	case commonpb.ReconfAdd:
		w.event.Record(raft.EventProposeAddServer)
		ff.index = w.n.AddVoter(server.ID, server.Address, 0, timeout)
	case commonpb.ReconfRemove:
		w.event.Record(raft.EventProposeRemoveServer)
		ff.index = w.n.RemoveServer(server.ID, 0, timeout)
	default:
		panic("invalid reconf type")
	}

	return ff, nil
}

func (w *Wrapper) Apply(logentry *hraft.Log) interface{} {
	rmetrics.commitIndex.Set(float64(logentry.Index))
	if atomic.LoadUint64(&w.leader) != 1 {
		w.lat.Record(time.Now())
	}

	switch logentry.Type {
	case hraft.LogCommand:
		res := w.sm.Apply(&commonpb.Entry{
			Term:      logentry.Term,
			Index:     logentry.Index,
			EntryType: commonpb.EntryNormal,
			Data:      logentry.Data,
		})
		return res
	case hraft.LogConfiguration:
		var configuration hraft.Configuration
		if err := decodeMsgPack(logentry.Data, &configuration); err != nil {
			panic(fmt.Errorf("failed to decode configuration: %v", err))
		}
		// If the server didn't have a vote in the previous conf., but
		// have a vote in the new configuration, this follower have
		// recently been added and are now caught up.
		if !hasVote(w.conf, w.id) && hasVote(configuration, w.id) {
			w.event.Record(raft.EventCaughtUp)
		}
		if len(w.conf.Servers) < len(configuration.Servers) {
			w.event.Record(raft.EventAdded)
		} else {
			w.event.Record(raft.EventRemoved)
		}
		w.conf = configuration
	}

	panic(fmt.Sprintf("no case for logtype: %v", logentry.Type))
}

func (w *Wrapper) Snapshot() (hraft.FSMSnapshot, error) { return &snapStore{}, nil }
func (w *Wrapper) Restore(io.ReadCloser) error          { return nil }

type snapStore struct{}

func (s *snapStore) Persist(sink hraft.SnapshotSink) error { return nil }
func (s *snapStore) Release()                              {}

// Decode reverses the encode operation on a byte slice input.
// From hashicorp/raft/util.go.
func decodeMsgPack(buf []byte, out interface{}) error {
	r := bytes.NewBuffer(buf)
	hd := codec.MsgpackHandle{}
	dec := codec.NewDecoder(r, &hd)
	return dec.Decode(out)
}

// hasVote returns true if the server identified by 'id' is a Voter in the
// provided Configuration.
// From hashicorp/raft/configuration.go.
func hasVote(configuration hraft.Configuration, id hraft.ServerID) bool {
	for _, server := range configuration.Servers {
		if server.ID == id {
			return server.Suffrage == hraft.Voter
		}
	}
	return false
}
<|endoftext|>


<commit_before>package netflowlegacy

import (
	"bytes"
	"fmt"

	"github.com/cloudflare/goflow/v3/decoders/utils"
)

type ErrorVersion struct {
	version uint16
}

func NewErrorVersion(version uint16) *ErrorVersion {
	return &ErrorVersion{
		version: version,
	}
}

func (e *ErrorVersion) Error() string {
	return fmt.Sprintf("Unknown NetFlow version %v (only decodes v5)", e.version)
}

func DecodeMessage(payload *bytes.Buffer) (interface{}, error) {
	var version uint16
	utils.BinaryDecoder(payload, &version)
	packet := PacketNetFlowV5{}
	if version == 5 {
		packet.Version = version

		utils.BinaryDecoder(payload,
			&(packet.Count),
			&(packet.SysUptime),
			&(packet.UnixSecs),
			&(packet.UnixNSecs),
			&(packet.FlowSequence),
			&(packet.EngineType),
			&(packet.EngineId),
			&(packet.SamplingInterval),
		)

		packet.Records = make([]RecordsNetFlowV5, int(packet.Count))
		for i := 0; i < int(packet.Count) && payload.Len() >= 48; i++ {
			record := RecordsNetFlowV5{}
			utils.BinaryDecoder(payload, &record)
			packet.Records[i] = record
		}

		return packet, nil
	} else {
		return nil, NewErrorVersion(version)
	}
}
<commit_msg>Fix DOS vector in legacy netflow packet handling<commit_after>package netflowlegacy

import (
	"bytes"
	"fmt"

	"github.com/cloudflare/goflow/v3/decoders/utils"
)

const MAX_UDP_PKT_SIZE = 65535
const FLOW_SIZE = 48
const MAX_FLOWS_PER_PACKET = MAX_UDP_PKT_SIZE / FLOW_SIZE

type ErrorVersion struct {
	version uint16
}

func NewErrorVersion(version uint16) *ErrorVersion {
	return &ErrorVersion{
		version: version,
	}
}

func (e *ErrorVersion) Error() string {
	return fmt.Sprintf("Unknown NetFlow version %v (only decodes v5)", e.version)
}

func DecodeMessage(payload *bytes.Buffer) (interface{}, error) {
	var version uint16
	utils.BinaryDecoder(payload, &version)
	packet := PacketNetFlowV5{}
	if version == 5 {
		packet.Version = version

		utils.BinaryDecoder(payload,
			&(packet.Count),
			&(packet.SysUptime),
			&(packet.UnixSecs),
			&(packet.UnixNSecs),
			&(packet.FlowSequence),
			&(packet.EngineType),
			&(packet.EngineId),
			&(packet.SamplingInterval),
		)

		if packet.Count > MAX_FLOWS_PER_PACKET {
			return nil, fmt.Errorf("Invalid amount of flows: %d", packet.Count)
		}

		packet.Records = make([]RecordsNetFlowV5, int(packet.Count))
		for i := 0; i < int(packet.Count) && payload.Len() >= FLOW_SIZE; i++ {
			record := RecordsNetFlowV5{}
			utils.BinaryDecoder(payload, &record)
			packet.Records[i] = record
		}

		return packet, nil
	} else {
		return nil, NewErrorVersion(version)
	}
}
<|endoftext|>


<commit_before>package principal

import (
	"fmt"
	"strings"

	vsecurity "veyron.io/veyron/veyron/security"

	"veyron.io/veyron/veyron2/naming"
	"veyron.io/veyron/veyron2/security"
)

type context struct {
	method string
	local  security.Principal
}

func (c *context) Method() string                            { return c.method }
func (c *context) Name() string                              { return "" }
func (c *context) Suffix() string                            { return "" }
func (c *context) Label() security.Label                     { return 0 }
func (c *context) Discharges() map[string]security.Discharge { return nil }
func (c *context) LocalPrincipal() security.Principal        { return c.local }
func (c *context) LocalBlessings() security.Blessings        { return nil }
func (c *context) RemoteBlessings() security.Blessings       { return nil }
func (c *context) LocalEndpoint() naming.Endpoint            { return nil }
func (c *context) RemoteEndpoint() naming.Endpoint           { return nil }

func newPrincipal() security.Principal {
	p, err := vsecurity.NewPrincipal()
	if err != nil {
		panic(err)
	}
	return p
}

func blessSelf(p security.Principal, name string) security.Blessings {
	b, err := p.BlessSelf(name)
	if err != nil {
		panic(err)
	}
	return b
}

func matchesError(got error, want string) error {
	if (got == nil) && len(want) == 0 {
		return nil
	}
	if got == nil {
		return fmt.Errorf("Got nil error, wanted to match %q", want)
	}
	if !strings.Contains(got.Error(), want) {
		return fmt.Errorf("Got error %q, wanted to match %q", got, want)
	}
	return nil
}
<commit_msg>veyron/services/wsprd/principal: Changes correpsonding to https://veyron-review.googlesource.com/6273<commit_after>package principal

import (
	"fmt"
	"strings"
	"time"

	vsecurity "veyron.io/veyron/veyron/security"

	"veyron.io/veyron/veyron2/naming"
	"veyron.io/veyron/veyron2/security"
)

type context struct {
	method string
	local  security.Principal
}

func (c *context) Timestamp() (t time.Time)                  { return t }
func (c *context) Method() string                            { return c.method }
func (c *context) MethodTags() []interface{}                 { return nil }
func (c *context) Name() string                              { return "" }
func (c *context) Suffix() string                            { return "" }
func (c *context) Label() security.Label                     { return 0 }
func (c *context) Discharges() map[string]security.Discharge { return nil }
func (c *context) LocalPrincipal() security.Principal        { return c.local }
func (c *context) LocalBlessings() security.Blessings        { return nil }
func (c *context) RemoteBlessings() security.Blessings       { return nil }
func (c *context) LocalEndpoint() naming.Endpoint            { return nil }
func (c *context) RemoteEndpoint() naming.Endpoint           { return nil }

func newPrincipal() security.Principal {
	p, err := vsecurity.NewPrincipal()
	if err != nil {
		panic(err)
	}
	return p
}

func blessSelf(p security.Principal, name string) security.Blessings {
	b, err := p.BlessSelf(name)
	if err != nil {
		panic(err)
	}
	return b
}

func matchesError(got error, want string) error {
	if (got == nil) && len(want) == 0 {
		return nil
	}
	if got == nil {
		return fmt.Errorf("Got nil error, wanted to match %q", want)
	}
	if !strings.Contains(got.Error(), want) {
		return fmt.Errorf("Got error %q, wanted to match %q", got, want)
	}
	return nil
}
<|endoftext|>


<commit_before>// This file is part of Monsti, a web content management system.
// Copyright 2012-2013 Christian Neumann
//
// Monsti is free software: you can redistribute it and/or modify it under the
// terms of the GNU Affero General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option) any
// later version.
//
// Monsti is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
// details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Monsti.  If not, see <http://www.gnu.org/licenses/>.

/*
 Monsti is a simple and resource efficient CMS for low dynamic
 private and small business sites with mostly static pages and simple
 structure.

 This package implements monsti's http daemon.
*/
package main

import (
	"flag"
	"github.com/monsti/service"
	"github.com/monsti/util"
	"github.com/monsti/util/l10n"
	"github.com/monsti/util/template"
	"log"
	"net/http"
	"os"
	"path/filepath"
)

func main() {
	logger := log.New(os.Stderr, "httpd ", log.LstdFlags)

	// Load configuration
	flag.Parse()
	if flag.NArg() != 1 {
		logger.Fatal("Expecting configuration path.")
	}
	cfgPath := util.GetConfigPath(flag.Arg(0))
	var settings settings
	if err := util.LoadModuleSettings("httpd", cfgPath, &settings); err != nil {
		logger.Fatal("Could not load settings: ", err)
	}
	if err := (&settings).LoadSiteSettings(); err != nil {
		logger.Fatal("Could not load site settings: ", err)
	}

	l10n.DefaultSettings.Domain = "monsti-httpd"
	l10n.DefaultSettings.Directory = settings.Monsti.GetLocalePath()

	// Connect to INFO service
	infoPath := flag.Arg(1)
	info, err := service.NewInfoConnection(infoPath)
	if err != nil {
		logger.Fatalf("Could not connect to INFO service: %v", err)
	}

	handler := nodeHandler{
		Info:     info,
		Renderer: template.Renderer{Root: settings.Monsti.GetTemplatesPath()},
		Settings: &settings,
		Log:      logger}
	http.Handle("/static/", http.FileServer(http.Dir(
		filepath.Dir(settings.Monsti.GetStaticsPath()))))
	handler.Hosts = make(map[string]string)
	for site_title, site := range settings.Sites {
		for _, host := range site.Hosts {
			handler.Hosts[host] = site_title
			http.Handle(host+"/site-static/", http.FileServer(http.Dir(
				filepath.Dir(settings.Monsti.GetSiteStaticsPath(site_title)))))
		}
	}
	http.Handle("/", &handler)
	c := make(chan int)
	go func() {
		if err := http.ListenAndServe(settings.Listen, nil); err != nil {
			logger.Fatal("HTTP Listener failed: ", err)
		}
		c <- 1
	}()
	logger.Printf("monsti-httpd is up and running. Listening on %q.", settings.Listen)
	<-c
}
<commit_msg>Use GetServicePath to get Info path.<commit_after>// This file is part of Monsti, a web content management system.
// Copyright 2012-2013 Christian Neumann
//
// Monsti is free software: you can redistribute it and/or modify it under the
// terms of the GNU Affero General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option) any
// later version.
//
// Monsti is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
// A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
// details.
//
// You should have received a copy of the GNU Affero General Public License
// along with Monsti.  If not, see <http://www.gnu.org/licenses/>.

/*
 Monsti is a simple and resource efficient CMS for low dynamic
 private and small business sites with mostly static pages and simple
 structure.

 This package implements monsti's http daemon.
*/
package main

import (
	"flag"
	"github.com/monsti/service"
	"github.com/monsti/util"
	"github.com/monsti/util/l10n"
	"github.com/monsti/util/template"
	"log"
	"net/http"
	"os"
	"path/filepath"
)

func main() {
	logger := log.New(os.Stderr, "httpd ", log.LstdFlags)

	// Load configuration
	flag.Parse()
	if flag.NArg() != 1 {
		logger.Fatal("Expecting configuration path.")
	}
	cfgPath := util.GetConfigPath(flag.Arg(0))
	var settings settings
	if err := util.LoadModuleSettings("httpd", cfgPath, &settings); err != nil {
		logger.Fatal("Could not load settings: ", err)
	}
	if err := (&settings).LoadSiteSettings(); err != nil {
		logger.Fatal("Could not load site settings: ", err)
	}

	l10n.DefaultSettings.Domain = "monsti-httpd"
	l10n.DefaultSettings.Directory = settings.Monsti.GetLocalePath()

	// Connect to INFO service
	info, err := service.NewInfoConnection(
		settings.Monsti.GetServicePath(service.Info.String()))
	if err != nil {
		logger.Fatalf("Could not connect to INFO service: %v", err)
	}

	handler := nodeHandler{
		Info:     info,
		Renderer: template.Renderer{Root: settings.Monsti.GetTemplatesPath()},
		Settings: &settings,
		Log:      logger}
	http.Handle("/static/", http.FileServer(http.Dir(
		filepath.Dir(settings.Monsti.GetStaticsPath()))))
	handler.Hosts = make(map[string]string)
	for site_title, site := range settings.Sites {
		for _, host := range site.Hosts {
			handler.Hosts[host] = site_title
			http.Handle(host+"/site-static/", http.FileServer(http.Dir(
				filepath.Dir(settings.Monsti.GetSiteStaticsPath(site_title)))))
		}
	}
	http.Handle("/", &handler)
	c := make(chan int)
	go func() {
		if err := http.ListenAndServe(settings.Listen, nil); err != nil {
			logger.Fatal("HTTP Listener failed: ", err)
		}
		c <- 1
	}()
	logger.Printf("monsti-httpd is up and running. Listening on %q.", settings.Listen)
	<-c
}
<|endoftext|>


<commit_before>package rx

import (
	"sync/atomic"
	"time"
)

//jig:template Connectable<Foo>
//jig:embeds Observable<Foo>
//jig:needs SubscribeOptions

// ConnectableFoo is an ObservableFoo that has an additional method Connect()
// used to Subscribe to the parent observable and then multicasting values to
// all subscribers of ConnectableFoo.
type ConnectableFoo struct {
	ObservableFoo
	connect func(options []SubscribeOptionSetter) Subscription
}

//jig:template Connectable<Foo> Connect
//jig:needs Connectable<Foo>

// Connect instructs a connectable Observable to begin emitting items to its
// subscribers. All values will then be passed on to the observers that
// subscribed to this connectable observable
func (c ConnectableFoo) Connect(setters ...SubscribeOptionSetter) Subscription {
	return c.connect(setters)
}

//jig:template Observable<Foo> Multicast
//jig:needs Observable<Foo> Subscribe, Connectable<Foo>

// Multicast converts an ordinary Observable into a connectable Observable.
// A connectable observable will only start emitting values after its Connect
// method has been called. The factory method passed in should return a
// new SubjectFoo that implements the actual multicasting behavior.
func (o ObservableFoo) Multicast(factory func() SubjectFoo) ConnectableFoo {
	const (
		active int32 = iota
		notifying
		terminated
	)
	var subject struct {
		state int32
		atomic.Value
	}
	subject.Store(factory())
	observable := func(observe FooObserveFunc, subscribeOn Scheduler, subscriber Subscriber) {
		if s, ok := subject.Load().(SubjectFoo); ok {
			s.ObservableFoo(observe, subscribeOn, subscriber)
		}
	}
	observer := func(next foo, err error, done bool) {
		if atomic.CompareAndSwapInt32(&subject.state, active, notifying) {
			if s, ok := subject.Load().(SubjectFoo); ok {
				s.FooObserveFunc(next, err, done)
			}
			if !done {
				atomic.CompareAndSwapInt32(&subject.state, notifying, active)
			} else {
				atomic.CompareAndSwapInt32(&subject.state, notifying, terminated)
			}
		}
	}
	const (
		unsubscribed int32 = iota
		subscribed
	)
	var subscriber struct {
		state int32
		atomic.Value
	}
	connect := func(setters []SubscribeOptionSetter) Subscription {
		if atomic.CompareAndSwapInt32(&subject.state, terminated, active) {
			subject.Store(factory())
		}
		if atomic.CompareAndSwapInt32(&subscriber.state, unsubscribed, subscribed) {
			scheduler := NewGoroutine()
			setter := SubscribeOn(scheduler, setters...)
			subscription := o.Subscribe(observer, setter)
			subscriber.Store(subscription)
			subscription.Add(func() {
				atomic.CompareAndSwapInt32(&subscriber.state, subscribed, unsubscribed)
			})
		}
		subscription := subscriber.Load().(Subscriber)
		return subscription.Add(func() { subscription.Unsubscribe() })
	}
	return ConnectableFoo{ObservableFoo: observable, connect: connect}
}

//jig:template Observable<Foo> Publish
//jig:needs Observable<Foo> Multicast, NewSubject<Foo>, Connectable<Foo>

// Publish uses Multicast to control the subscription of a Subject to a
// source observable and turns the subject it into a connnectable observable.
// A Subject emits to an observer only those items that are emitted by
// the source Observable subsequent to the time of the subscription.
//
// If the source completed and as a result the internal Subject terminated, then
// calling Connect again will replace the old Subject with a newly created one.
// So this Publish operator is re-connectable, unlike the RxJS 5 behavior that
// isn't. To simulate the RxJS 5 behavior use Publish().AutoConnect(1) this will
// connect on the first subscription but will never re-connect.
func (o ObservableFoo) Publish() ConnectableFoo {
	return o.Multicast(NewSubjectFoo)
}

//jig:template Observable<Foo> PublishReplay
//jig:needs Observable<Foo> Multicast, NewReplaySubject<Foo>, Connectable<Foo>

// Replay uses Multicast to control the subscription of a ReplaySubject to a
// source observable and turns the subject into a connectable observable.
// A ReplaySubject emits to any observer all of the items that were emitted by
// the source observable, regardless of when the observer subscribes.
//
// If the source completed and as a result the internal ReplaySubject
// terminated, then calling Connect again will replace the old ReplaySubject
// with a newly created one.
func (o ObservableFoo) PublishReplay(bufferCapacity int, windowDuration time.Duration) ConnectableFoo {
	factory := func() SubjectFoo {
		return NewReplaySubjectFoo(bufferCapacity, windowDuration)
	}
	return o.Multicast(factory)
}

//jig:template Connectable<Foo> RefCount
//jig:needs Connectable<Foo>, SubscribeOptions

// RefCount makes a ConnectableFoo behave like an ordinary ObservableFoo.
func (o ConnectableFoo) RefCount(setters ...SubscribeOptionSetter) ObservableFoo {
	var (
		refcount   int32
		connection Subscription
	)
	observable := func(observe FooObserveFunc, subscribeOn Scheduler, subscriber Subscriber) {
		if atomic.AddInt32(&refcount, 1) == 1 {
			connection = o.connect(setters)
		}
		o.ObservableFoo(observe, subscribeOn, subscriber.Add(func() {
			if atomic.AddInt32(&refcount, -1) == 0 {
				connection.Unsubscribe()
			}
		}))
	}
	return observable
}

//jig:template Connectable<Foo> AutoConnect
//jig:needs Connectable<Foo>, SubscribeOptions

// AutoConnect makes a ConnectableFoo behave like an ordinary ObservableFoo that
// automatically connects when the specified number of clients subscribe to it.
// If count is 0, then AutoConnect will immediately call connect on the
// ConnectableFoo before returning the ObservableFoo part of the ConnectableFoo.
func (o ConnectableFoo) AutoConnect(count int, setters ...SubscribeOptionSetter) ObservableFoo {
	if count == 0 {
		o.connect(setters)
		return o.ObservableFoo
	}
	var refcount int32
	observable := func(observe FooObserveFunc, subscribeOn Scheduler, subscriber Subscriber) {
		if atomic.AddInt32(&refcount, 1) == int32(count) {
			o.connect(setters)
		}
		o.ObservableFoo(observe, subscribeOn, subscriber)
	}
	return observable
}
<commit_msg>Update RefCount comment and correct jig:needs clauses.<commit_after>package rx

import (
	"sync/atomic"
	"time"
)

//jig:template Connectable<Foo>
//jig:embeds Observable<Foo>
//jig:needs SubscribeOptions

// ConnectableFoo is an ObservableFoo that has an additional method Connect()
// used to Subscribe to the parent observable and then multicasting values to
// all subscribers of ConnectableFoo.
type ConnectableFoo struct {
	ObservableFoo
	connect func(options []SubscribeOptionSetter) Subscription
}

//jig:template Connectable<Foo> Connect
//jig:needs Connectable<Foo>

// Connect instructs a connectable Observable to begin emitting items to its
// subscribers. All values will then be passed on to the observers that
// subscribed to this connectable observable
func (c ConnectableFoo) Connect(setters ...SubscribeOptionSetter) Subscription {
	return c.connect(setters)
}

//jig:template Observable<Foo> Multicast
//jig:needs Observable<Foo> Subscribe, Connectable<Foo>

// Multicast converts an ordinary Observable into a connectable Observable.
// A connectable observable will only start emitting values after its Connect
// method has been called. The factory method passed in should return a
// new SubjectFoo that implements the actual multicasting behavior.
func (o ObservableFoo) Multicast(factory func() SubjectFoo) ConnectableFoo {
	const (
		active int32 = iota
		notifying
		terminated
	)
	var subject struct {
		state int32
		atomic.Value
	}
	subject.Store(factory())
	observable := func(observe FooObserveFunc, subscribeOn Scheduler, subscriber Subscriber) {
		if s, ok := subject.Load().(SubjectFoo); ok {
			s.ObservableFoo(observe, subscribeOn, subscriber)
		}
	}
	observer := func(next foo, err error, done bool) {
		if atomic.CompareAndSwapInt32(&subject.state, active, notifying) {
			if s, ok := subject.Load().(SubjectFoo); ok {
				s.FooObserveFunc(next, err, done)
			}
			if !done {
				atomic.CompareAndSwapInt32(&subject.state, notifying, active)
			} else {
				atomic.CompareAndSwapInt32(&subject.state, notifying, terminated)
			}
		}
	}
	const (
		unsubscribed int32 = iota
		subscribed
	)
	var subscriber struct {
		state int32
		atomic.Value
	}
	connect := func(setters []SubscribeOptionSetter) Subscription {
		if atomic.CompareAndSwapInt32(&subject.state, terminated, active) {
			subject.Store(factory())
		}
		if atomic.CompareAndSwapInt32(&subscriber.state, unsubscribed, subscribed) {
			scheduler := NewGoroutine()
			setter := SubscribeOn(scheduler, setters...)
			subscription := o.Subscribe(observer, setter)
			subscriber.Store(subscription)
			subscription.Add(func() {
				atomic.CompareAndSwapInt32(&subscriber.state, subscribed, unsubscribed)
			})
		}
		subscription := subscriber.Load().(Subscriber)
		return subscription.Add(func() { subscription.Unsubscribe() })
	}
	return ConnectableFoo{ObservableFoo: observable, connect: connect}
}

//jig:template Observable<Foo> Publish
//jig:needs Observable<Foo> Multicast, NewSubject<Foo>, Connectable<Foo>

// Publish uses Multicast to control the subscription of a Subject to a
// source observable and turns the subject it into a connnectable observable.
// A Subject emits to an observer only those items that are emitted by
// the source Observable subsequent to the time of the subscription.
//
// If the source completed and as a result the internal Subject terminated, then
// calling Connect again will replace the old Subject with a newly created one.
// So this Publish operator is re-connectable, unlike the RxJS 5 behavior that
// isn't. To simulate the RxJS 5 behavior use Publish().AutoConnect(1) this will
// connect on the first subscription but will never re-connect.
func (o ObservableFoo) Publish() ConnectableFoo {
	return o.Multicast(NewSubjectFoo)
}

//jig:template Observable<Foo> PublishReplay
//jig:needs Observable<Foo> Multicast, NewReplaySubject<Foo>, Connectable<Foo>

// Replay uses Multicast to control the subscription of a ReplaySubject to a
// source observable and turns the subject into a connectable observable.
// A ReplaySubject emits to any observer all of the items that were emitted by
// the source observable, regardless of when the observer subscribes.
//
// If the source completed and as a result the internal ReplaySubject
// terminated, then calling Connect again will replace the old ReplaySubject
// with a newly created one.
func (o ObservableFoo) PublishReplay(bufferCapacity int, windowDuration time.Duration) ConnectableFoo {
	factory := func() SubjectFoo {
		return NewReplaySubjectFoo(bufferCapacity, windowDuration)
	}
	return o.Multicast(factory)
}

//jig:template Connectable<Foo> RefCount
//jig:needs Observable<Foo>, SubscribeOptions

// RefCount makes a ConnectableFoo behave like an ordinary ObservableFoo. On
// first Subscribe it will call Connect on its ConnectableFoo and when its last
// subscriber is Unsubscribed it will cancel the connection by calling
// Unsubscribe on the subscription returned by the call to Connect.
func (o ConnectableFoo) RefCount(setters ...SubscribeOptionSetter) ObservableFoo {
	var (
		refcount   int32
		connection Subscription
	)
	observable := func(observe FooObserveFunc, subscribeOn Scheduler, subscriber Subscriber) {
		if atomic.AddInt32(&refcount, 1) == 1 {
			connection = o.connect(setters)
		}
		o.ObservableFoo(observe, subscribeOn, subscriber.Add(func() {
			if atomic.AddInt32(&refcount, -1) == 0 {
				connection.Unsubscribe()
			}
		}))
	}
	return observable
}

//jig:template Connectable<Foo> AutoConnect
//jig:needs Observable<Foo>, SubscribeOptions

// AutoConnect makes a ConnectableFoo behave like an ordinary ObservableFoo that
// automatically connects when the specified number of clients subscribe to it.
// If count is 0, then AutoConnect will immediately call connect on the
// ConnectableFoo before returning the ObservableFoo part of the ConnectableFoo.
func (o ConnectableFoo) AutoConnect(count int, setters ...SubscribeOptionSetter) ObservableFoo {
	if count == 0 {
		o.connect(setters)
		return o.ObservableFoo
	}
	var refcount int32
	observable := func(observe FooObserveFunc, subscribeOn Scheduler, subscriber Subscriber) {
		if atomic.AddInt32(&refcount, 1) == int32(count) {
			o.connect(setters)
		}
		o.ObservableFoo(observe, subscribeOn, subscriber)
	}
	return observable
}
<|endoftext|>


<commit_before>package main

import (
	"errors"
	"flag"
	"log"
	"net"
	"os"

	"github.com/divtxt/lockd/raftlock"

	"fmt"

	"github.com/divtxt/lockd/ginx"
	"github.com/divtxt/lockd/httpimpl"
	"github.com/divtxt/lockd/lockimpl"
	"github.com/divtxt/lockd/util"
	"github.com/divtxt/raft"
	"github.com/gin-gonic/gin"
)

func main() {
	// Reset standard log flags (undo Gin's settings)
	log.SetFlags(log.LstdFlags)

	// Disable Gin debug logging
	gin.SetMode(gin.ReleaseMode)

	// Parse command line args
	args, err := parseArgs()
	if err != nil {
		fmt.Fprintln(os.Stderr, "Error:", err.Error())
		flag.Usage()
		os.Exit(2)
	}

	// Make a logger
	logger := log.New(os.Stderr, "", log.Flags())

	// Process args
	logger.Println("[lockd] initializing")
	logger.Println("[lockd] thisServerId:", args.thisServerId)
	cd, err := util.LoadClusterDefinition(args.cluster)
	if err != nil {
		logger.Printf("[lockd] Error loading cluster definition:", err)
		os.Exit(2)
	}
	logger.Println("[lockd] cluster:", cd)

	// Calculate lisen host port using port from cluster info
	_, listenPort, err := net.SplitHostPort(cd.GetHostPort(args.thisServerId))
	listenAddr := fmt.Sprintf("localhost:%s", listenPort)
	logger.Println("[lockd] calculated listenAddr:", listenAddr)

	// Instantiate a lock service
	var rl raftlock.RaftLock
	var rcm raft.IConsensusModule
	rl, rcm, err = lockimpl.NewLockApiImpl(cd, args.thisServerId, logger)
	if err != nil {
		panic(err)
	}

	// Configure http service
	r := gin.New()
	r.Use(ginx.RequestLogger(logger))
	r.Use(ginx.LogAndRepanic(logger))

	httpimpl.AddRaftRpcEndpoints(r, rcm)
	httpimpl.AddLockApiEndpoints(r, rl)

	// Run forever / till stopped
	logger.Println("[lockd] Starting server on address:", listenAddr)
	err = r.Run(listenAddr)
	if err != nil {
		panic(err)
	}
}

type lockdArgs struct {
	cluster      string
	thisServerId raft.ServerId
}

func parseArgs() (*lockdArgs, error) {
	var args lockdArgs

	// Parse command line args
	flag.StringVar(
		&args.cluster,
		"cluster",
		"",
		"cluster definition file - json file that describes the lockd cluster\n"+
			"    \t    the json should be of the form: {\"server-id\": \"host:port\", ...}\n"+
			"    \t    server ids should be positive integers, but as strings since json keys must be strings\n"+
			"    \t    example: {\"1\": \"lockd1:2081\", \"2\": \"lockd2:2082\", \"3\": \"lockd3:2083\"}",
	)
	flag.Uint64Var(
		(*uint64)(&args.thisServerId),
		"id",
		0,
		"server id of this server - this id should be in the cluster definition",
	)
	flag.Parse()

	// Check required args
	if args.cluster == "" {
		return nil, errors.New("flag -cluster is required")
	}
	if args.thisServerId == 0 {
		return nil, errors.New("flag -id is required and must not be 0")
	}

	return &args, nil
}
<commit_msg>Disable http access logging by default<commit_after>package main

import (
	"errors"
	"flag"
	"log"
	"net"
	"os"

	"github.com/divtxt/lockd/raftlock"

	"fmt"

	"github.com/divtxt/lockd/ginx"
	"github.com/divtxt/lockd/httpimpl"
	"github.com/divtxt/lockd/lockimpl"
	"github.com/divtxt/lockd/util"
	"github.com/divtxt/raft"
	"github.com/gin-gonic/gin"
)

func main() {
	// Reset standard log flags (undo Gin's settings)
	log.SetFlags(log.LstdFlags)

	// Disable Gin debug logging
	gin.SetMode(gin.ReleaseMode)

	// Parse command line args
	args, err := parseArgs()
	if err != nil {
		fmt.Fprintln(os.Stderr, "Error:", err.Error())
		flag.Usage()
		os.Exit(2)
	}

	// Make a logger
	logger := log.New(os.Stderr, "", log.Flags())

	// Process args
	logger.Println("[lockd] initializing")
	logger.Println("[lockd] thisServerId:", args.thisServerId)
	cd, err := util.LoadClusterDefinition(args.cluster)
	if err != nil {
		logger.Printf("[lockd] Error loading cluster definition:", err)
		os.Exit(2)
	}
	logger.Println("[lockd] cluster:", cd)

	// Calculate lisen host port using port from cluster info
	_, listenPort, err := net.SplitHostPort(cd.GetHostPort(args.thisServerId))
	listenAddr := fmt.Sprintf("localhost:%s", listenPort)
	logger.Println("[lockd] calculated listenAddr:", listenAddr)

	// Instantiate a lock service
	var rl raftlock.RaftLock
	var rcm raft.IConsensusModule
	rl, rcm, err = lockimpl.NewLockApiImpl(cd, args.thisServerId, logger)
	if err != nil {
		panic(err)
	}

	// Configure http service
	r := gin.New()
	// Uncomment for HTTP logs - very verbose!
	// r.Use(ginx.RequestLogger(logger))
	r.Use(ginx.LogAndRepanic(logger))

	httpimpl.AddRaftRpcEndpoints(r, rcm)
	httpimpl.AddLockApiEndpoints(r, rl)

	// Run forever / till stopped
	logger.Println("[lockd] Starting server on address:", listenAddr)
	err = r.Run(listenAddr)
	if err != nil {
		panic(err)
	}
}

type lockdArgs struct {
	cluster      string
	thisServerId raft.ServerId
}

func parseArgs() (*lockdArgs, error) {
	var args lockdArgs

	// Parse command line args
	flag.StringVar(
		&args.cluster,
		"cluster",
		"",
		"cluster definition file - json file that describes the lockd cluster\n"+
			"    \t    the json should be of the form: {\"server-id\": \"host:port\", ...}\n"+
			"    \t    server ids should be positive integers, but as strings since json keys must be strings\n"+
			"    \t    example: {\"1\": \"lockd1:2081\", \"2\": \"lockd2:2082\", \"3\": \"lockd3:2083\"}",
	)
	flag.Uint64Var(
		(*uint64)(&args.thisServerId),
		"id",
		0,
		"server id of this server - this id should be in the cluster definition",
	)
	flag.Parse()

	// Check required args
	if args.cluster == "" {
		return nil, errors.New("flag -cluster is required")
	}
	if args.thisServerId == 0 {
		return nil, errors.New("flag -id is required and must not be 0")
	}

	return &args, nil
}
<|endoftext|>