<commit_before>package structs

import (
	"bytes"
	"fmt"
	"github.com/ugorji/go/codec"
	"time"
)

var (
	ErrNoLeader  = fmt.Errorf("No cluster leader")
	ErrNoDCPath  = fmt.Errorf("No path to datacenter")
	ErrNoServers = fmt.Errorf("No known Consul servers")
)

type MessageType uint8

const (
	RegisterRequestType MessageType = iota
	DeregisterRequestType
	KVSRequestType
)

const (
	HealthUnknown  = "unknown"
	HealthPassing  = "passing"
	HealthWarning  = "warning"
	HealthCritical = "critical"
)

// BlockingQuery is used to block on a query and wait for a change.
// Either both fields, or neither must be provided.
type BlockingQuery struct {
	// If set, wait until query exceeds given index
	MinQueryIndex uint64

	// Provided with MinQueryIndex to wait for change
	MaxQueryTime time.Duration
}

// RegisterRequest is used for the Catalog.Register endpoint
// to register a node as providing a service. If no service
// is provided, the node is registered.
type RegisterRequest struct {
	Datacenter string
	Node       string
	Address    string
	Service    *NodeService
	Check      *HealthCheck
}

// DeregisterRequest is used for the Catalog.Deregister endpoint
// to deregister a node as providing a service. If no service is
// provided the entire node is deregistered.
type DeregisterRequest struct {
	Datacenter string
	Node       string
	ServiceID  string
	CheckID    string
}

// DCSpecificRequest is used to query about a specific DC
type DCSpecificRequest struct {
	Datacenter string
	BlockingQuery
}

// ServiceSpecificRequest is used to query about a specific node
type ServiceSpecificRequest struct {
	Datacenter  string
	ServiceName string
	ServiceTag  string
	TagFilter   bool // Controls tag filtering
	BlockingQuery
}

// NodeSpecificRequest is used to request the information about a single node
type NodeSpecificRequest struct {
	Datacenter string
	Node       string
	BlockingQuery
}

// ChecksInStateRequest is used to query for nodes in a state
type ChecksInStateRequest struct {
	Datacenter string
	State      string
	BlockingQuery
}

// Used to return information about a node
type Node struct {
	Node    string
	Address string
}
type Nodes []Node

// Used to return information about a provided services.
// Maps service name to available tags
type Services map[string][]string

// ServiceNode represents a node that is part of a service
type ServiceNode struct {
	Node        string
	Address     string
	ServiceID   string
	ServiceName string
	ServiceTags []string
	ServicePort int
}
type ServiceNodes []ServiceNode

// NodeService is a service provided by a node
type NodeService struct {
	ID      string
	Service string
	Tags    []string
	Port    int
}
type NodeServices struct {
	Node     Node
	Services map[string]*NodeService
}

// HealthCheck represents a single check on a given node
type HealthCheck struct {
	Node        string
	CheckID     string // Unique per-node ID
	Name        string // Check name
	Status      string // The current check status
	Notes       string // Additional notes with the status
	ServiceID   string // optional associated service
	ServiceName string // optional service name
}
type HealthChecks []*HealthCheck

// CheckServiceNode is used to provide the node, it's service
// definition, as well as a HealthCheck that is associated
type CheckServiceNode struct {
	Node    Node
	Service NodeService
	Checks  HealthChecks
}
type CheckServiceNodes []CheckServiceNode

type IndexedNodes struct {
	Index uint64
	Nodes Nodes
}

type IndexedServices struct {
	Index    uint64
	Services Services
}

type IndexedServiceNodes struct {
	Index        uint64
	ServiceNodes ServiceNodes
}

type IndexedNodeServices struct {
	Index        uint64
	NodeServices *NodeServices
}

type IndexedHealthChecks struct {
	Index        uint64
	HealthChecks HealthChecks
}

type IndexedCheckServiceNodes struct {
	Index uint64
	Nodes CheckServiceNodes
}

// DirEntry is used to represent a directory entry. This is
// used for values in our Key-Value store.
type DirEntry struct {
	CreateIndex uint64
	ModifyIndex uint64
	Key         string
	Flags       uint64
	Value       []byte
}
type DirEntries []*DirEntry

type KVSOp string

const (
	KVSSet        KVSOp = "set"
	KVSDelete           = "delete"
	KVSDeleteTree       = "delete-tree"
	KVSCAS              = "cas" // Check-and-set
)

// KVSRequest is used to operate on the Key-Value store
type KVSRequest struct {
	Datacenter string
	Op         KVSOp    // Which operation are we performing
	DirEnt     DirEntry // Which directory entry
}

// KeyRequest is used to request a key, or key prefix
type KeyRequest struct {
	Datacenter string
	Key        string
	BlockingQuery
}

type IndexedDirEntries struct {
	Index   uint64
	Entries DirEntries
}

// Decode is used to decode a MsgPack encoded object
func Decode(buf []byte, out interface{}) error {
	var handle codec.MsgpackHandle
	return codec.NewDecoder(bytes.NewReader(buf), &handle).Decode(out)
}

// Encode is used to encode a MsgPack object with type prefix
func Encode(t MessageType, msg interface{}) ([]byte, error) {
	buf := bytes.NewBuffer(nil)
	buf.WriteByte(uint8(t))

	handle := codec.MsgpackHandle{}
	encoder := codec.NewEncoder(buf, &handle)
	err := encoder.Encode(msg)
	return buf.Bytes(), err
}
<commit_msg>consul: Adding additional query options and return meta data<commit_after>package structs

import (
	"bytes"
	"fmt"
	"github.com/ugorji/go/codec"
	"time"
)

var (
	ErrNoLeader  = fmt.Errorf("No cluster leader")
	ErrNoDCPath  = fmt.Errorf("No path to datacenter")
	ErrNoServers = fmt.Errorf("No known Consul servers")
)

type MessageType uint8

const (
	RegisterRequestType MessageType = iota
	DeregisterRequestType
	KVSRequestType
)

const (
	HealthUnknown  = "unknown"
	HealthPassing  = "passing"
	HealthWarning  = "warning"
	HealthCritical = "critical"
)

// BlockingQuery is used to block on a query and wait for a change.
// Either both fields, or neither must be provided.
type BlockingQuery struct {
	// If set, wait until query exceeds given index
	MinQueryIndex uint64

	// Provided with MinQueryIndex to wait for change
	MaxQueryTime time.Duration
}

// QueryOptions is used to specify various flags for read queries
type QueryOptions struct {
	// If set, any follower can service the request. Results
	// may be arbitrarily stale.
	AllowStale bool

	// If set, the leader must verify leadership prior to
	// servicing the request. Prevents a stale read.
	RequireConsistent bool
}

// QueryMeta allows a query response to include potentially
// useful metadata about a query
type QueryMeta struct {
	// If AllowStale is used, this is time elapsed since
	// last contact between the follower and leader. This
	// can be used to gauge staleness.
	LastContact time.Duration

	// Used to indicate if there is a known leader node
	KnownLeader bool
}

// RegisterRequest is used for the Catalog.Register endpoint
// to register a node as providing a service. If no service
// is provided, the node is registered.
type RegisterRequest struct {
	Datacenter string
	Node       string
	Address    string
	Service    *NodeService
	Check      *HealthCheck
}

// DeregisterRequest is used for the Catalog.Deregister endpoint
// to deregister a node as providing a service. If no service is
// provided the entire node is deregistered.
type DeregisterRequest struct {
	Datacenter string
	Node       string
	ServiceID  string
	CheckID    string
}

// DCSpecificRequest is used to query about a specific DC
type DCSpecificRequest struct {
	Datacenter string
	BlockingQuery
	QueryOptions
}

// ServiceSpecificRequest is used to query about a specific node
type ServiceSpecificRequest struct {
	Datacenter  string
	ServiceName string
	ServiceTag  string
	TagFilter   bool // Controls tag filtering
	BlockingQuery
	QueryOptions
}

// NodeSpecificRequest is used to request the information about a single node
type NodeSpecificRequest struct {
	Datacenter string
	Node       string
	BlockingQuery
	QueryOptions
}

// ChecksInStateRequest is used to query for nodes in a state
type ChecksInStateRequest struct {
	Datacenter string
	State      string
	BlockingQuery
	QueryOptions
}

// Used to return information about a node
type Node struct {
	Node    string
	Address string
}
type Nodes []Node

// Used to return information about a provided services.
// Maps service name to available tags
type Services map[string][]string

// ServiceNode represents a node that is part of a service
type ServiceNode struct {
	Node        string
	Address     string
	ServiceID   string
	ServiceName string
	ServiceTags []string
	ServicePort int
}
type ServiceNodes []ServiceNode

// NodeService is a service provided by a node
type NodeService struct {
	ID      string
	Service string
	Tags    []string
	Port    int
}
type NodeServices struct {
	Node     Node
	Services map[string]*NodeService
}

// HealthCheck represents a single check on a given node
type HealthCheck struct {
	Node        string
	CheckID     string // Unique per-node ID
	Name        string // Check name
	Status      string // The current check status
	Notes       string // Additional notes with the status
	ServiceID   string // optional associated service
	ServiceName string // optional service name
}
type HealthChecks []*HealthCheck

// CheckServiceNode is used to provide the node, it's service
// definition, as well as a HealthCheck that is associated
type CheckServiceNode struct {
	Node    Node
	Service NodeService
	Checks  HealthChecks
}
type CheckServiceNodes []CheckServiceNode

type IndexedNodes struct {
	Index uint64
	Nodes Nodes
	QueryMeta
}

type IndexedServices struct {
	Index    uint64
	Services Services
	QueryMeta
}

type IndexedServiceNodes struct {
	Index        uint64
	ServiceNodes ServiceNodes
	QueryMeta
}

type IndexedNodeServices struct {
	Index        uint64
	NodeServices *NodeServices
	QueryMeta
}

type IndexedHealthChecks struct {
	Index        uint64
	HealthChecks HealthChecks
	QueryMeta
}

type IndexedCheckServiceNodes struct {
	Index uint64
	Nodes CheckServiceNodes
	QueryMeta
}

// DirEntry is used to represent a directory entry. This is
// used for values in our Key-Value store.
type DirEntry struct {
	CreateIndex uint64
	ModifyIndex uint64
	Key         string
	Flags       uint64
	Value       []byte
}
type DirEntries []*DirEntry

type KVSOp string

const (
	KVSSet        KVSOp = "set"
	KVSDelete           = "delete"
	KVSDeleteTree       = "delete-tree"
	KVSCAS              = "cas" // Check-and-set
)

// KVSRequest is used to operate on the Key-Value store
type KVSRequest struct {
	Datacenter string
	Op         KVSOp    // Which operation are we performing
	DirEnt     DirEntry // Which directory entry
}

// KeyRequest is used to request a key, or key prefix
type KeyRequest struct {
	Datacenter string
	Key        string
	BlockingQuery
	QueryOptions
}

type IndexedDirEntries struct {
	Index   uint64
	Entries DirEntries
	QueryMeta
}

// Decode is used to decode a MsgPack encoded object
func Decode(buf []byte, out interface{}) error {
	var handle codec.MsgpackHandle
	return codec.NewDecoder(bytes.NewReader(buf), &handle).Decode(out)
}

// Encode is used to encode a MsgPack object with type prefix
func Encode(t MessageType, msg interface{}) ([]byte, error) {
	buf := bytes.NewBuffer(nil)
	buf.WriteByte(uint8(t))

	handle := codec.MsgpackHandle{}
	encoder := codec.NewEncoder(buf, &handle)
	err := encoder.Encode(msg)
	return buf.Bytes(), err
}
<|endoftext|>


<commit_before>// +build go1.11

package storage

import (
	"context"

	"cloud.google.com/go/storage"
	"github.com/instana/go-sensor/instrumentation/cloud.google.com/go/internal"
	ot "github.com/opentracing/opentracing-go"
)

// ACLHandle is an instrumented wrapper for cloud.google.com/go/storage.ACLHandle
// that traces calls made to Google Cloud Storage API.
//
// See https://pkg.go.dev/cloud.google.com/go/storage?tab=doc#ACLHandle for furter details on wrapped type.
type ACLHandle struct {
	*storage.ACLHandle
	Bucket  string
	Object  string
	Default bool
}

// Delete calls and traces the Delete() method of the wrapped cloud.google.com/go/storage.ACLHandle.
//
// See https://pkg.go.dev/cloud.google.com/go/storage?tab=doc#ACLHandle.Delete for furter details on wrapped method.
func (a *ACLHandle) Delete(ctx context.Context, entity storage.ACLEntity) (err error) {
	ctx = internal.StartExitSpan(ctx, "gcs", ot.Tags{
		"gcs.op":     aclOpPrefix(a) + ".delete",
		"gcs.bucket": a.Bucket,
		"gcs.object": a.Object,
	})

	defer func() { internal.FinishSpan(ctx, err) }()

	return a.ACLHandle.Delete(ctx, entity)
}

// Set calls and traces the Set() method of the wrapped cloud.google.com/go/storage.ACLHandle.
//
// See https://pkg.go.dev/cloud.google.com/go/storage?tab=doc#ACLHandle.Set for furter details on wrapped method.
func (a *ACLHandle) Set(ctx context.Context, entity storage.ACLEntity, role storage.ACLRole) (err error) {
	ctx = internal.StartExitSpan(ctx, "gcs", ot.Tags{
		"gcs.op":     aclOpPrefix(a) + ".update",
		"gcs.bucket": a.Bucket,
		"gcs.object": a.Object,
	})

	defer func() { internal.FinishSpan(ctx, err) }()

	return a.ACLHandle.Set(ctx, entity, role)
}

// List calls and traces the List() method of the wrapped cloud.google.com/go/storage.ACLHandle.
//
// See https://pkg.go.dev/cloud.google.com/go/storage?tab=doc#ACLHandle.List for furter details on wrapped method.
func (a *ACLHandle) List(ctx context.Context) (rules []storage.ACLRule, err error) {
	ctx = internal.StartExitSpan(ctx, "gcs", ot.Tags{
		"gcs.op":     aclOpPrefix(a) + ".list",
		"gcs.bucket": a.Bucket,
		"gcs.object": a.Object,
	})

	defer func() { internal.FinishSpan(ctx, err) }()

	return a.ACLHandle.List(ctx)
}

func aclOpPrefix(a *ACLHandle) string {
	switch {
	case a.Object != "": // object-specific ACL
		return "objectAcls"
	case a.Default: // default object ACL for a bucket
		return "defaultAcls"
	default: // bucket ACL
		return "bucketAcls"
	}
}
<commit_msg>Add GCS ACL entity to the span tags<commit_after>// +build go1.11

package storage

import (
	"context"

	"cloud.google.com/go/storage"
	"github.com/instana/go-sensor/instrumentation/cloud.google.com/go/internal"
	ot "github.com/opentracing/opentracing-go"
)

// ACLHandle is an instrumented wrapper for cloud.google.com/go/storage.ACLHandle
// that traces calls made to Google Cloud Storage API.
//
// See https://pkg.go.dev/cloud.google.com/go/storage?tab=doc#ACLHandle for furter details on wrapped type.
type ACLHandle struct {
	*storage.ACLHandle
	Bucket  string
	Object  string
	Default bool
}

// Delete calls and traces the Delete() method of the wrapped cloud.google.com/go/storage.ACLHandle.
//
// See https://pkg.go.dev/cloud.google.com/go/storage?tab=doc#ACLHandle.Delete for furter details on wrapped method.
func (a *ACLHandle) Delete(ctx context.Context, entity storage.ACLEntity) (err error) {
	ctx = internal.StartExitSpan(ctx, "gcs", ot.Tags{
		"gcs.op":     aclOpPrefix(a) + ".delete",
		"gcs.bucket": a.Bucket,
		"gcs.object": a.Object,
		"gcs.entity": string(entity),
	})

	defer func() { internal.FinishSpan(ctx, err) }()

	return a.ACLHandle.Delete(ctx, entity)
}

// Set calls and traces the Set() method of the wrapped cloud.google.com/go/storage.ACLHandle.
//
// See https://pkg.go.dev/cloud.google.com/go/storage?tab=doc#ACLHandle.Set for furter details on wrapped method.
func (a *ACLHandle) Set(ctx context.Context, entity storage.ACLEntity, role storage.ACLRole) (err error) {
	ctx = internal.StartExitSpan(ctx, "gcs", ot.Tags{
		"gcs.op":     aclOpPrefix(a) + ".update",
		"gcs.bucket": a.Bucket,
		"gcs.object": a.Object,
		"gcs.entity": string(entity),
	})

	defer func() { internal.FinishSpan(ctx, err) }()

	return a.ACLHandle.Set(ctx, entity, role)
}

// List calls and traces the List() method of the wrapped cloud.google.com/go/storage.ACLHandle.
//
// See https://pkg.go.dev/cloud.google.com/go/storage?tab=doc#ACLHandle.List for furter details on wrapped method.
func (a *ACLHandle) List(ctx context.Context) (rules []storage.ACLRule, err error) {
	ctx = internal.StartExitSpan(ctx, "gcs", ot.Tags{
		"gcs.op":     aclOpPrefix(a) + ".list",
		"gcs.bucket": a.Bucket,
		"gcs.object": a.Object,
	})

	defer func() { internal.FinishSpan(ctx, err) }()

	return a.ACLHandle.List(ctx)
}

func aclOpPrefix(a *ACLHandle) string {
	switch {
	case a.Object != "": // object-specific ACL
		return "objectAcls"
	case a.Default: // default object ACL for a bucket
		return "defaultAcls"
	default: // bucket ACL
		return "bucketAcls"
	}
}
<|endoftext|>


<commit_before>// Copyright (c) 2013-2014 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package main

import (
	"github.com/conformal/btcchain"
	"github.com/conformal/btcwire"
	"math/big"
)

// activeNetParams is a pointer to the parameters specific to the
// currently active bitcoin network.
var activeNetParams = netParams(defaultBtcnet)

// params is used to group parameters for various networks such as the main
// network and test networks.
type params struct {
	netName      string
	btcnet       btcwire.BitcoinNet
	genesisBlock *btcwire.MsgBlock
	genesisHash  *btcwire.ShaHash
	powLimit     *big.Int
	powLimitBits uint32
	peerPort     string
	listenPort   string
	rpcPort      string
	dnsSeeds     []string
}

// mainNetParams contains parameters specific to the main network
// (btcwire.MainNet).  NOTE: The RPC port is intentionally different than the
// reference implementation because btcd does not handle wallet requests.  The
// separate wallet process listens on the well-known port and forwards requests
// it does not handle on to btcd.  This approach allows the wallet process
// to emulate the full reference implementation RPC API.
var mainNetParams = params{
	netName:      "mainnet",
	btcnet:       btcwire.MainNet,
	genesisBlock: btcchain.ChainParams(btcwire.MainNet).GenesisBlock,
	genesisHash:  btcchain.ChainParams(btcwire.MainNet).GenesisHash,
	powLimit:     btcchain.ChainParams(btcwire.MainNet).PowLimit,
	powLimitBits: btcchain.ChainParams(btcwire.MainNet).PowLimitBits,
	listenPort:   btcwire.MainPort,
	peerPort:     btcwire.MainPort,
	rpcPort:      "8334",
	dnsSeeds: []string{
		"seed.bitcoin.sipa.be",
		"dnsseed.bluematt.me",
		"dnsseed.bitcoin.dashjr.org",
		"seed.bitcoinstats.com",
		"bitseed.xf2.org",
	},
}

// regressionParams contains parameters specific to the regression test network
// (btcwire.TestNet).  NOTE: The RPC port is intentionally different than the
// reference implementation - see the mainNetParams comment for details.
var regressionParams = params{
	netName:      "regtest",
	btcnet:       btcwire.TestNet,
	genesisBlock: btcchain.ChainParams(btcwire.TestNet).GenesisBlock,
	genesisHash:  btcchain.ChainParams(btcwire.TestNet).GenesisHash,
	powLimit:     btcchain.ChainParams(btcwire.TestNet).PowLimit,
	powLimitBits: btcchain.ChainParams(btcwire.TestNet).PowLimitBits,
	listenPort:   btcwire.RegressionTestPort,
	peerPort:     btcwire.TestNetPort,
	rpcPort:      "18334",
	dnsSeeds:     []string{},
}

// testNet3Params contains parameters specific to the test network (version 3)
// (btcwire.TestNet3).  NOTE: The RPC port is intentionally different than the
// reference implementation - see the mainNetParams comment for details.
var testNet3Params = params{
	netName:      "testnet",
	btcnet:       btcwire.TestNet3,
	genesisBlock: btcchain.ChainParams(btcwire.TestNet3).GenesisBlock,
	genesisHash:  btcchain.ChainParams(btcwire.TestNet3).GenesisHash,
	powLimit:     btcchain.ChainParams(btcwire.TestNet3).PowLimit,
	powLimitBits: btcchain.ChainParams(btcwire.TestNet3).PowLimitBits,
	listenPort:   btcwire.TestNetPort,
	peerPort:     btcwire.TestNetPort,
	rpcPort:      "18334",
	dnsSeeds: []string{
		"testnet-seed.bitcoin.petertodd.org",
		"testnet-seed.bluematt.me",
	},
}

// netParams returns parameters specific to the passed bitcoin network.
func netParams(btcnet btcwire.BitcoinNet) *params {
	switch btcnet {
	case btcwire.TestNet:
		return &regressionParams

	case btcwire.TestNet3:
		return &testNet3Params

	// Return main net by default.
	case btcwire.MainNet:
		fallthrough
	default:
		return &mainNetParams
	}
}
<commit_msg>add new dns seed, seed.bitnodes.io<commit_after>// Copyright (c) 2013-2014 Conformal Systems LLC.
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.

package main

import (
	"github.com/conformal/btcchain"
	"github.com/conformal/btcwire"
	"math/big"
)

// activeNetParams is a pointer to the parameters specific to the
// currently active bitcoin network.
var activeNetParams = netParams(defaultBtcnet)

// params is used to group parameters for various networks such as the main
// network and test networks.
type params struct {
	netName      string
	btcnet       btcwire.BitcoinNet
	genesisBlock *btcwire.MsgBlock
	genesisHash  *btcwire.ShaHash
	powLimit     *big.Int
	powLimitBits uint32
	peerPort     string
	listenPort   string
	rpcPort      string
	dnsSeeds     []string
}

// mainNetParams contains parameters specific to the main network
// (btcwire.MainNet).  NOTE: The RPC port is intentionally different than the
// reference implementation because btcd does not handle wallet requests.  The
// separate wallet process listens on the well-known port and forwards requests
// it does not handle on to btcd.  This approach allows the wallet process
// to emulate the full reference implementation RPC API.
var mainNetParams = params{
	netName:      "mainnet",
	btcnet:       btcwire.MainNet,
	genesisBlock: btcchain.ChainParams(btcwire.MainNet).GenesisBlock,
	genesisHash:  btcchain.ChainParams(btcwire.MainNet).GenesisHash,
	powLimit:     btcchain.ChainParams(btcwire.MainNet).PowLimit,
	powLimitBits: btcchain.ChainParams(btcwire.MainNet).PowLimitBits,
	listenPort:   btcwire.MainPort,
	peerPort:     btcwire.MainPort,
	rpcPort:      "8334",
	dnsSeeds: []string{
		"seed.bitcoin.sipa.be",
		"dnsseed.bluematt.me",
		"dnsseed.bitcoin.dashjr.org",
		"seed.bitcoinstats.com",
		"seed.bitnodes.io",
		"bitseed.xf2.org",
	},
}

// regressionParams contains parameters specific to the regression test network
// (btcwire.TestNet).  NOTE: The RPC port is intentionally different than the
// reference implementation - see the mainNetParams comment for details.
var regressionParams = params{
	netName:      "regtest",
	btcnet:       btcwire.TestNet,
	genesisBlock: btcchain.ChainParams(btcwire.TestNet).GenesisBlock,
	genesisHash:  btcchain.ChainParams(btcwire.TestNet).GenesisHash,
	powLimit:     btcchain.ChainParams(btcwire.TestNet).PowLimit,
	powLimitBits: btcchain.ChainParams(btcwire.TestNet).PowLimitBits,
	listenPort:   btcwire.RegressionTestPort,
	peerPort:     btcwire.TestNetPort,
	rpcPort:      "18334",
	dnsSeeds:     []string{},
}

// testNet3Params contains parameters specific to the test network (version 3)
// (btcwire.TestNet3).  NOTE: The RPC port is intentionally different than the
// reference implementation - see the mainNetParams comment for details.
var testNet3Params = params{
	netName:      "testnet",
	btcnet:       btcwire.TestNet3,
	genesisBlock: btcchain.ChainParams(btcwire.TestNet3).GenesisBlock,
	genesisHash:  btcchain.ChainParams(btcwire.TestNet3).GenesisHash,
	powLimit:     btcchain.ChainParams(btcwire.TestNet3).PowLimit,
	powLimitBits: btcchain.ChainParams(btcwire.TestNet3).PowLimitBits,
	listenPort:   btcwire.TestNetPort,
	peerPort:     btcwire.TestNetPort,
	rpcPort:      "18334",
	dnsSeeds: []string{
		"testnet-seed.bitcoin.petertodd.org",
		"testnet-seed.bluematt.me",
	},
}

// netParams returns parameters specific to the passed bitcoin network.
func netParams(btcnet btcwire.BitcoinNet) *params {
	switch btcnet {
	case btcwire.TestNet:
		return &regressionParams

	case btcwire.TestNet3:
		return &testNet3Params

	// Return main net by default.
	case btcwire.MainNet:
		fallthrough
	default:
		return &mainNetParams
	}
}
<|endoftext|>


<commit_before>package cryptopals

import "math/big"

type privateKey struct {
	e *big.Int
	n *big.Int
	d *big.Int
}

type publicKey struct {
	e *big.Int
	n *big.Int
}

func generateRsaPrivateKey(bits int) *privateKey {
	p := randPrime(bits / 2)
	q := randPrime(bits / 2)

	e := big.NewInt(3)
	n := new(big.Int).Mul(p, q)

	t1 := new(big.Int).Sub(p, big.NewInt(1))
	t2 := new(big.Int).Sub(q, big.NewInt(1))

	t := new(big.Int).Mul(t1, t2)
	d := new(big.Int).ModInverse(e, t)

	return &privateKey{e: e, n: n, d: d}
}

func (key *privateKey) publicKey() *publicKey {
	return &publicKey{e: key.e, n: key.n}
}

func (key *publicKey) encrypt(m *big.Int) *big.Int {
	return new(big.Int).Exp(m, key.e, key.n)
}

func (key *privateKey) decrypt(c *big.Int) *big.Int {
	return new(big.Int).Exp(c, key.d, key.n)
}
<commit_msg>Fix RSA bug where check if t was divisible by e was missing<commit_after>package cryptopals

import "math/big"

type privateKey struct {
	e *big.Int
	n *big.Int
	d *big.Int
}

type publicKey struct {
	e *big.Int
	n *big.Int
}

func generateRsaPrivateKey(bits int) *privateKey {
	e := big.NewInt(3)

	for {
		p := randPrime(bits / 2)
		t1 := new(big.Int).Sub(p, big.NewInt(1))

		if new(big.Int).Mod(t1, e).Int64() == 0 {
			continue
		}

		q := randPrime(bits / 2)
		t2 := new(big.Int).Sub(q, big.NewInt(1))

		if new(big.Int).Mod(t2, e).Int64() == 0 {
			continue
		}

		n := new(big.Int).Mul(p, q)
		t := new(big.Int).Mul(t1, t2)
		d := new(big.Int).ModInverse(e, t)

		return &privateKey{e: e, n: n, d: d}
	}
}

func (key *privateKey) publicKey() *publicKey {
	return &publicKey{e: key.e, n: key.n}
}

func (key *publicKey) encrypt(m *big.Int) *big.Int {
	return new(big.Int).Exp(m, key.e, key.n)
}

func (key *privateKey) decrypt(c *big.Int) *big.Int {
	return new(big.Int).Exp(c, key.d, key.n)
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013 Santiago Arias | Remy Jourde | Carlos Bernal
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package models

import (
	"crypto/rand"
	"errors"
	"fmt"
	"io"
	"net/http"
	"time"

	"appengine"
	"appengine/datastore"

	"github.com/santiaago/purple-wing/helpers/log"
)

type User struct {
	Id                    int64
	Email                 string
	Username              string
	Name                  string
	IsAdmin               bool    // is user gonawin admin.
	Auth                  string  // authentication auth token
	PredictIds            []int64 // current user predicts.
	ArchivedPredictInds   []int64 // archived user predicts.
	TournamentIds         []int64 // current tournament ids of user <=> tournaments user subscribed.
	ArchivedTournamentIds []int64 // archived tournament ids of user <=> finnished tournametns user subscribed.
	TeamIds               []int64 // current team ids of user <=> teams user belongs to.
	Score                 int64   // overall user score.
	Created               time.Time
}

type UserJson struct {
	Id                    *int64     `json:",omitempty"`
	Email                 *string    `json:",omitempty"`
	Username              *string    `json:",omitempty"`
	Name                  *string    `json:",omitempty"`
	IsAdmin               *bool      `json:",omitempty"`
	Auth                  *string    `json:",omitempty"`
	PredictIds            *[]int64   `json:",omitempty"`
	ArchivedPredictInds   *[]int64   `json:",omitempty"`
	TournamentIds         *[]int64   `json:",omitempty"`
	ArchivedTournamentIds *[]int64   `json:",omitempty"`
	TeamIds               *[]int64   `json:",omitempty"`
	Score                 *int64     `json:",omitempty"`
	Created               *time.Time `json:",omitempty"`
}

// Creates a user entity.
func CreateUser(c appengine.Context, email string, username string, name string, isAdmin bool, auth string) (*User, error) {
	// create new user
	userId, _, err := datastore.AllocateIDs(c, "User", nil, 1)
	if err != nil {
		log.Errorf(c, " User.Create: %v", err)
	}

	key := datastore.NewKey(c, "User", "", userId, nil)

	emptyArray := make([]int64, 0)

	user := &User{userId, email, username, name, isAdmin, auth, emptyArray, emptyArray, emptyArray, emptyArray, emptyArray, int64(0), time.Now()}

	_, err = datastore.Put(c, key, user)
	if err != nil {
		log.Errorf(c, "User.Create: %v", err)
		return nil, errors.New("model/user: Unable to put user in Datastore")
	}

	return user, nil
}

// Search for a user entity given a filter and value.
func FindUser(c appengine.Context, filter string, value interface{}) *User {

	q := datastore.NewQuery("User").Filter(filter+" =", value)

	var users []*User

	if _, err := q.GetAll(c, &users); err == nil && len(users) > 0 {
		return users[0]
	} else if len(users) == 0 {
		log.Infof(c, " User.Find, error occurred during GetAll")
	} else {
		log.Errorf(c, " User.Find, error occurred during GetAll: %v", err)
	}
	return nil
}

// Find all users present in datastore.
func FindAllUsers(c appengine.Context) []*User {
	q := datastore.NewQuery("User")

	var users []*User

	if _, err := q.GetAll(c, &users); err != nil {
		log.Errorf(c, "FindAllUser, error occurred during GetAll call: %v", err)
	}

	return users
}

// Find a user entity by id.
func UserById(c appengine.Context, id int64) (*User, error) {

	var u User
	key := datastore.NewKey(c, "User", "", id, nil)

	if err := datastore.Get(c, key, &u); err != nil {
		log.Errorf(c, " user not found : %v", err)
		return nil, err
	}
	return &u, nil
}

// Get key pointer given a user id.
func UserKeyById(c appengine.Context, id int64) *datastore.Key {

	key := datastore.NewKey(c, "User", "", id, nil)

	return key
}

// Update user given a user pointer.
func (u *User) Update(c appengine.Context) error {
	k := UserKeyById(c, u.Id)
	if _, err := datastore.Put(c, k, u); err != nil {
		return err
	}
	return nil
}

// Create user from params in datastore and return a pointer to it.
func SigninUser(w http.ResponseWriter, r *http.Request, queryName string, email string, username string, name string) (*User, error) {

	c := appengine.NewContext(r)
	var user *User

	queryValue := ""
	if queryName == "Email" {
		queryValue = email
	} else if queryName == "Username" {
		queryValue = username
	} else {
		return nil, errors.New("models/user: no valid query name.")
	}

	// find user
	if user = FindUser(c, queryName, queryValue); user == nil {
		// create user if it does not exist
		isAdmin := false
		if userCreate, err := CreateUser(c, email, username, name, isAdmin, GenerateAuthKey()); err != nil {
			log.Errorf(c, "Signup: %v", err)
			return nil, errors.New("models/user: Unable to create user.")
		} else {
			user = userCreate
		}
		// publish new activity
		user.Publish(c, "welcome", "joined gonawin", ActivityEntity{}, ActivityEntity{})
	}

	return user, nil
}

// Generate authentication string key.
func GenerateAuthKey() string {
	b := make([]byte, 16)
	if _, err := io.ReadFull(rand.Reader, b); err != nil {
		return ""
	}
	return fmt.Sprintf("%x", b)
}

// From a user id returns an array of teams the user iq involved participates.
func (u *User) Teams(c appengine.Context) []*Team {

	var teams []*Team

	for _, tId := range u.TeamIds {
		t, err := TeamById(c, tId)
		if err != nil {
			log.Errorf(c, "Teams, cannot find team with ID=%", tId)
		} else {
			teams = append(teams, t)
		}
	}

	return teams
}

// Adds a predict Id in the PredictId array.
func (u *User) AddPredictId(c appengine.Context, pId int64) error {

	u.PredictIds = append(u.PredictIds, pId)
	if err := u.Update(c); err != nil {
		return err
	}
	return nil
}

// Adds a tournament Id in the TournamentId array.
func (u *User) AddTournamentId(c appengine.Context, tId int64) error {

	if hasTournament, _ := u.ContainsTournamentId(tId); hasTournament {
		return errors.New(fmt.Sprintf("AddTournamentId, allready a member."))
	}

	u.TournamentIds = append(u.TournamentIds, tId)
	if err := u.Update(c); err != nil {
		return err
	}
	return nil
}

// Adds a tournament Id in the TournamentId array.
func (u *User) RemoveTournamentId(c appengine.Context, tId int64) error {

	if hasTournament, i := u.ContainsTournamentId(tId); !hasTournament {
		return errors.New(fmt.Sprintf("RemoveTournamentId, not a member."))
	} else {
		// as the order of index in tournamentsId is not important,
		// replace elem at index i with last element and resize slice.
		u.TournamentIds[i] = u.TournamentIds[len(u.TournamentIds)-1]
		u.TournamentIds = u.TournamentIds[0 : len(u.TournamentIds)-1]
	}
	if err := u.Update(c); err != nil {
		return err
	}
	return nil
}

func (u *User) ContainsTournamentId(id int64) (bool, int) {

	for i, tId := range u.TournamentIds {
		if tId == id {
			return true, i
		}
	}
	return false, -1
}

// from a user return an array of tournament the user is involved in.
func (u *User) Tournaments(c appengine.Context) []*Tournament {

	var tournaments []*Tournament

	for _, tId := range u.TournamentIds {
		t, err := TournamentById(c, tId)
		if err != nil {
			log.Errorf(c, " Tournaments, cannot find team with ID=%", tId)
		} else {
			tournaments = append(tournaments, t)
		}
	}

	return tournaments
}

// Adds a team Id in the TeamId array.
func (u *User) AddTeamId(c appengine.Context, tId int64) error {

	if hasTeam, _ := u.ContainsTeamId(tId); hasTeam {
		return errors.New(fmt.Sprintf("AddTeamId, allready a member."))
	}

	u.TeamIds = append(u.TeamIds, tId)
	if err := u.Update(c); err != nil {
		return err
	}
	return nil
}

// Adds a team Id in the TeamId array.
func (u *User) RemoveTeamId(c appengine.Context, tId int64) error {

	if hasTeam, i := u.ContainsTeamId(tId); !hasTeam {
		return errors.New(fmt.Sprintf("RemoveTeamId, not a member."))
	} else {
		// as the order of index in teamsId is not important,
		// replace elem at index i with last element and resize slice.
		u.TeamIds[i] = u.TeamIds[len(u.TeamIds)-1]
		u.TeamIds = u.TeamIds[0 : len(u.TeamIds)-1]
	}
	if err := u.Update(c); err != nil {
		return err
	}
	return nil
}

func (u *User) ContainsTeamId(id int64) (bool, int) {

	for i, tId := range u.TeamIds {
		if tId == id {
			return true, i
		}
	}
	return false, -1
}

// Update an array of users.
func UpdateUsers(c appengine.Context, users []*User) error {
	keys := make([]*datastore.Key, len(users))
	for i, _ := range keys {
		keys[i] = UserKeyById(c, users[i].Id)
	}
	if _, err := datastore.PutMulti(c, keys, users); err != nil {
		return err
	}
	return nil
}

func (u *User) PredictFromMatchId(c appengine.Context, mId int64) (*Predict, error) {
	predicts := PredictsByIds(c, u.PredictIds)
	for i, p := range predicts {
		if p.MatchId == mId {
			return predicts[i], nil
		}
	}
	return nil, nil
}

func (u *User) ScoreForMatch(c appengine.Context, m *Tmatch) (int64, error) {
	desc := "Score for match:"
	var p *Predict
	var err1 error
	if p, err1 = u.PredictFromMatchId(c, m.Id); err1 == nil && p == nil {
		return 0, nil
	} else if err1 != nil {
		log.Errorf(c, "%s unable to get predict for current user %v: %v", desc, u.Id, err1)
		return 0, nil
	}
	return computeScore(m, p), nil
}

// Sort users by score
type UserByScore []*User

func (a UserByScore) Len() int           { return len(a) }
func (a UserByScore) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a UserByScore) Less(i, j int) bool { return a[i].Score < a[j].Score }

// Find all activities
func (u *User) Activities(c appengine.Context) []*Activity {
	q := datastore.NewQuery("Activity").Filter("CreatorID=", u.Id).Order("-Published")

	var activities []*Activity

	if _, err := q.GetAll(c, &activities); err != nil {
		log.Errorf(c, "model/activity, FindAll: error occurred during GetAll call: %v", err)
	}

	return activities
}

func (u *User) Publish(c appengine.Context, activityType string, verb string, object ActivityEntity, target ActivityEntity) error {
	var activity Activity
	activity.Type = activityType
	activity.Verb = verb
	activity.Actor = ActivityEntity{ID: u.Id, Type: "user", DisplayName: u.Username}
	activity.Object = object
	activity.Target = target
	activity.Published = time.Now()
	activity.CreatorID = u.Id

	return activity.save(c)
}
<commit_msg>user now has array of score entity to keep track of each tournament progression involves #174<commit_after>/*
 * Copyright (c) 2013 Santiago Arias | Remy Jourde | Carlos Bernal
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

package models

import (
	"crypto/rand"
	"errors"
	"fmt"
	"io"
	"net/http"
	"time"

	"appengine"
	"appengine/datastore"

	"github.com/santiaago/purple-wing/helpers/log"
)

// Accuracy of Tournament
type ScoreOfTournament struct {
	ScoreId      int64 // id of score entity
	TournamentId int64 // id of tournament
}

type User struct {
	Id                    int64
	Email                 string
	Username              string
	Name                  string
	IsAdmin               bool                // is user gonawin admin.
	Auth                  string              // authentication auth token
	PredictIds            []int64             // current user predicts.
	ArchivedPredictInds   []int64             // archived user predicts.
	TournamentIds         []int64             // current tournament ids of user <=> tournaments user subscribed.
	ArchivedTournamentIds []int64             // archived tournament ids of user <=> finnished tournametns user subscribed.
	TeamIds               []int64             // current team ids of user <=> teams user belongs to.
	Score                 int64               // overall user score.
	ScoreOfTournaments    []ScoreOfTournament // ids of Scores for each tournament the user is participating on.
	Created               time.Time
}

type UserJson struct {
	Id                    *int64               `json:",omitempty"`
	Email                 *string              `json:",omitempty"`
	Username              *string              `json:",omitempty"`
	Name                  *string              `json:",omitempty"`
	IsAdmin               *bool                `json:",omitempty"`
	Auth                  *string              `json:",omitempty"`
	PredictIds            *[]int64             `json:",omitempty"`
	ArchivedPredictInds   *[]int64             `json:",omitempty"`
	TournamentIds         *[]int64             `json:",omitempty"`
	ArchivedTournamentIds *[]int64             `json:",omitempty"`
	TeamIds               *[]int64             `json:",omitempty"`
	Score                 *int64               `json:",omitempty"`
	ScoreOfTournaments    *[]ScoreOfTournament `json:",omitempty"`
	Created               *time.Time           `json:",omitempty"`
}

// Creates a user entity.
func CreateUser(c appengine.Context, email string, username string, name string, isAdmin bool, auth string) (*User, error) {
	// create new user
	userId, _, err := datastore.AllocateIDs(c, "User", nil, 1)
	if err != nil {
		log.Errorf(c, " User.Create: %v", err)
	}

	key := datastore.NewKey(c, "User", "", userId, nil)

	emptyArray := make([]int64, 0)
	emptyScores := make([]ScoreOfTournament, 0)
	user := &User{userId, email, username, name, isAdmin, auth, emptyArray, emptyArray, emptyArray, emptyArray, emptyArray, int64(0), emptyScores, time.Now()}

	_, err = datastore.Put(c, key, user)
	if err != nil {
		log.Errorf(c, "User.Create: %v", err)
		return nil, errors.New("model/user: Unable to put user in Datastore")
	}

	return user, nil
}

// Search for a user entity given a filter and value.
func FindUser(c appengine.Context, filter string, value interface{}) *User {

	q := datastore.NewQuery("User").Filter(filter+" =", value)

	var users []*User

	if _, err := q.GetAll(c, &users); err == nil && len(users) > 0 {
		return users[0]
	} else if len(users) == 0 {
		log.Infof(c, " User.Find, error occurred during GetAll")
	} else {
		log.Errorf(c, " User.Find, error occurred during GetAll: %v", err)
	}
	return nil
}

// Find all users present in datastore.
func FindAllUsers(c appengine.Context) []*User {
	q := datastore.NewQuery("User")

	var users []*User

	if _, err := q.GetAll(c, &users); err != nil {
		log.Errorf(c, "FindAllUser, error occurred during GetAll call: %v", err)
	}

	return users
}

// Find a user entity by id.
func UserById(c appengine.Context, id int64) (*User, error) {

	var u User
	key := datastore.NewKey(c, "User", "", id, nil)

	if err := datastore.Get(c, key, &u); err != nil {
		log.Errorf(c, " user not found : %v", err)
		return nil, err
	}
	return &u, nil
}

// Get key pointer given a user id.
func UserKeyById(c appengine.Context, id int64) *datastore.Key {

	key := datastore.NewKey(c, "User", "", id, nil)

	return key
}

// Update user given a user pointer.
func (u *User) Update(c appengine.Context) error {
	k := UserKeyById(c, u.Id)
	if _, err := datastore.Put(c, k, u); err != nil {
		return err
	}
	return nil
}

// Create user from params in datastore and return a pointer to it.
func SigninUser(w http.ResponseWriter, r *http.Request, queryName string, email string, username string, name string) (*User, error) {

	c := appengine.NewContext(r)
	var user *User

	queryValue := ""
	if queryName == "Email" {
		queryValue = email
	} else if queryName == "Username" {
		queryValue = username
	} else {
		return nil, errors.New("models/user: no valid query name.")
	}

	// find user
	if user = FindUser(c, queryName, queryValue); user == nil {
		// create user if it does not exist
		isAdmin := false
		if userCreate, err := CreateUser(c, email, username, name, isAdmin, GenerateAuthKey()); err != nil {
			log.Errorf(c, "Signup: %v", err)
			return nil, errors.New("models/user: Unable to create user.")
		} else {
			user = userCreate
		}
		// publish new activity
		user.Publish(c, "welcome", "joined gonawin", ActivityEntity{}, ActivityEntity{})
	}

	return user, nil
}

// Generate authentication string key.
func GenerateAuthKey() string {
	b := make([]byte, 16)
	if _, err := io.ReadFull(rand.Reader, b); err != nil {
		return ""
	}
	return fmt.Sprintf("%x", b)
}

// From a user id returns an array of teams the user iq involved participates.
func (u *User) Teams(c appengine.Context) []*Team {

	var teams []*Team

	for _, tId := range u.TeamIds {
		t, err := TeamById(c, tId)
		if err != nil {
			log.Errorf(c, "Teams, cannot find team with ID=%", tId)
		} else {
			teams = append(teams, t)
		}
	}

	return teams
}

// Adds a predict Id in the PredictId array.
func (u *User) AddPredictId(c appengine.Context, pId int64) error {

	u.PredictIds = append(u.PredictIds, pId)
	if err := u.Update(c); err != nil {
		return err
	}
	return nil
}

// Adds a tournament Id in the TournamentId array.
func (u *User) AddTournamentId(c appengine.Context, tId int64) error {

	if hasTournament, _ := u.ContainsTournamentId(tId); hasTournament {
		return errors.New(fmt.Sprintf("AddTournamentId, allready a member."))
	}

	u.TournamentIds = append(u.TournamentIds, tId)
	if err := u.Update(c); err != nil {
		return err
	}
	return nil
}

// Adds a tournament Id in the TournamentId array.
func (u *User) RemoveTournamentId(c appengine.Context, tId int64) error {

	if hasTournament, i := u.ContainsTournamentId(tId); !hasTournament {
		return errors.New(fmt.Sprintf("RemoveTournamentId, not a member."))
	} else {
		// as the order of index in tournamentsId is not important,
		// replace elem at index i with last element and resize slice.
		u.TournamentIds[i] = u.TournamentIds[len(u.TournamentIds)-1]
		u.TournamentIds = u.TournamentIds[0 : len(u.TournamentIds)-1]
	}
	if err := u.Update(c); err != nil {
		return err
	}
	return nil
}

func (u *User) ContainsTournamentId(id int64) (bool, int) {

	for i, tId := range u.TournamentIds {
		if tId == id {
			return true, i
		}
	}
	return false, -1
}

// from a user return an array of tournament the user is involved in.
func (u *User) Tournaments(c appengine.Context) []*Tournament {

	var tournaments []*Tournament

	for _, tId := range u.TournamentIds {
		t, err := TournamentById(c, tId)
		if err != nil {
			log.Errorf(c, " Tournaments, cannot find team with ID=%", tId)
		} else {
			tournaments = append(tournaments, t)
		}
	}

	return tournaments
}

// Adds a team Id in the TeamId array.
func (u *User) AddTeamId(c appengine.Context, tId int64) error {

	if hasTeam, _ := u.ContainsTeamId(tId); hasTeam {
		return errors.New(fmt.Sprintf("AddTeamId, allready a member."))
	}

	u.TeamIds = append(u.TeamIds, tId)
	if err := u.Update(c); err != nil {
		return err
	}
	return nil
}

// Adds a team Id in the TeamId array.
func (u *User) RemoveTeamId(c appengine.Context, tId int64) error {

	if hasTeam, i := u.ContainsTeamId(tId); !hasTeam {
		return errors.New(fmt.Sprintf("RemoveTeamId, not a member."))
	} else {
		// as the order of index in teamsId is not important,
		// replace elem at index i with last element and resize slice.
		u.TeamIds[i] = u.TeamIds[len(u.TeamIds)-1]
		u.TeamIds = u.TeamIds[0 : len(u.TeamIds)-1]
	}
	if err := u.Update(c); err != nil {
		return err
	}
	return nil
}

func (u *User) ContainsTeamId(id int64) (bool, int) {

	for i, tId := range u.TeamIds {
		if tId == id {
			return true, i
		}
	}
	return false, -1
}

// Update an array of users.
func UpdateUsers(c appengine.Context, users []*User) error {
	keys := make([]*datastore.Key, len(users))
	for i, _ := range keys {
		keys[i] = UserKeyById(c, users[i].Id)
	}
	if _, err := datastore.PutMulti(c, keys, users); err != nil {
		return err
	}
	return nil
}

func (u *User) PredictFromMatchId(c appengine.Context, mId int64) (*Predict, error) {
	predicts := PredictsByIds(c, u.PredictIds)
	for i, p := range predicts {
		if p.MatchId == mId {
			return predicts[i], nil
		}
	}
	return nil, nil
}

func (u *User) ScoreForMatch(c appengine.Context, m *Tmatch) (int64, error) {
	desc := "Score for match:"
	var p *Predict
	var err1 error
	if p, err1 = u.PredictFromMatchId(c, m.Id); err1 == nil && p == nil {
		return 0, nil
	} else if err1 != nil {
		log.Errorf(c, "%s unable to get predict for current user %v: %v", desc, u.Id, err1)
		return 0, nil
	}
	return computeScore(m, p), nil
}

// Sort users by score
type UserByScore []*User

func (a UserByScore) Len() int           { return len(a) }
func (a UserByScore) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
func (a UserByScore) Less(i, j int) bool { return a[i].Score < a[j].Score }

// Find all activities
func (u *User) Activities(c appengine.Context) []*Activity {
	q := datastore.NewQuery("Activity").Filter("CreatorID=", u.Id).Order("-Published")

	var activities []*Activity

	if _, err := q.GetAll(c, &activities); err != nil {
		log.Errorf(c, "model/activity, FindAll: error occurred during GetAll call: %v", err)
	}

	return activities
}

func (u *User) Publish(c appengine.Context, activityType string, verb string, object ActivityEntity, target ActivityEntity) error {
	var activity Activity
	activity.Type = activityType
	activity.Verb = verb
	activity.Actor = ActivityEntity{ID: u.Id, Type: "user", DisplayName: u.Username}
	activity.Object = object
	activity.Target = target
	activity.Published = time.Now()
	activity.CreatorID = u.Id

	return activity.save(c)
}
<|endoftext|>


<commit_before>package q

import (
	"fmt"
	"time"
)

// Run starts a local worker
func (q *Queue) Run(handler func([]byte) error, mc int) error {
	c := make(chan struct{}, mc)
	errCh := make(chan error)

	go func() {
		defer func() {
			if x := recover(); x != nil {
				err, ok := x.(error)
				if !ok {
					err = fmt.Errorf("%q", err)
				}
				errCh <- err
			}
		}()

		for {
			select {
			case <-time.After(time.Minute):
				err := q.HouseKeeping()
				if err != nil {
					errCh <- err
				}
			}
		}
	}()

	for {
		select {
		case err := <-errCh:
			return err
		case c <- struct{}{}:
			go func() {
				defer func() {
					if x := recover(); x != nil {
						err, ok := x.(error)
						if !ok {
							err = fmt.Errorf("%q", err)
						}
						errCh <- err
					}

					<-c
				}()

				err := q.Handle(handler)
				if err != nil {
					errCh <- err
				}
			}()
		}
	}
}
<commit_msg>run a single for loop<commit_after>package q

import (
	"fmt"
	"time"
)

// Run starts a local worker
func (q *Queue) Run(handler func([]byte) error, mc int) error {
	c := make(chan struct{}, mc)
	errCh := make(chan error)

	for {
		select {
		case <-time.After(time.Minute):
			go func() {
				err := q.HouseKeeping()
				if err != nil {
					errCh <- err
				}
			}()
		case err := <-errCh:
			return err
		case c <- struct{}{}:
			go func() {
				defer func() {
					if x := recover(); x != nil {
						err, ok := x.(error)
						if !ok {
							err = fmt.Errorf("%q", err)
						}
						errCh <- err
					}

					<-c
				}()

				err := q.Handle(handler)
				if err != nil {
					errCh <- err
				}
			}()
		}
	}
}
<|endoftext|>


<commit_before>package models

import (
	"fmt"

	"github.com/wantedly/developers-account-mapper/services"
)

// User stores login user name and accounts information
type User struct {
	LoginName      string
	GitHubUsername string
	SlackUsername  string
	SlackUserId    string
}

// NewUser creates new User instance
func NewUser(loginName string, githubUsername string, slackUsername string, slackUserId string) *User {
	return &User{
		LoginName: loginName,
		GitHubUsername: githubUsername,
		SlackUsername: slackUsername,
		SlackUserId: slackUserId,
	}
}

func (u *User) SetSlackUserId(newId string) *User {
	u.SlackUserId = newId
	return u
}

func (u *User) RetrieveSlackUserId() error {
	nameIdMap, err := services.SlackUserList()
	if err != nil {
		return err
	}
	u.SetSlackUserId(nameIdMap[u.SlackUsername])
	return nil
}

func (u *User) String() string {
	if u.SlackUserId == "" {
		u.RetrieveSlackUserId()
	}
	return fmt.Sprintf("%v:@%v:<@%v:%v>", u.LoginName, u.GitHubUsername, u.SlackUsername, u.SlackUserId)
}
<commit_msg>Assign attributes directly<commit_after>package models

import (
	"fmt"

	"github.com/wantedly/developers-account-mapper/services"
)

// User stores login user name and accounts information
type User struct {
	LoginName      string
	GitHubUsername string
	SlackUsername  string
	SlackUserId    string
}

// NewUser creates new User instance
func NewUser(loginName string, githubUsername string, slackUsername string, slackUserId string) *User {
	return &User{
		LoginName: loginName,
		GitHubUsername: githubUsername,
		SlackUsername: slackUsername,
		SlackUserId: slackUserId,
	}
}

func (u *User) RetrieveSlackUserId() error {
	nameIdMap, err := services.SlackUserList()
	if err != nil {
		return err
	}
	u.SlackUserId = nameIdMap[u.SlackUsername]
	return nil
}

func (u *User) String() string {
	if u.SlackUserId == "" {
		u.RetrieveSlackUserId()
	}
	return fmt.Sprintf("%v:@%v:<@%v:%v>", u.LoginName, u.GitHubUsername, u.SlackUsername, u.SlackUserId)
}
<|endoftext|>


<commit_before>package main

import "fmt"

func main() {

	radix := node{}

	insertToRadix(&radix)

	//printRecursive(&radix, 0)

	node, params := radix.lookUp("/user/someone/")

	fmt.Println(string(node.path), params)
}

func insertToRadix(radix *node) {

	// HTTP Router:
	radix.insert("/something/")
	radix.insert("/user/")
	radix.insert("/admin/")
	radix.insert("/admin/auth/")
	radix.insert("/user/profile/")
	radix.insert("/user/:name/")
	radix.insert("/user/:name/view/")
	radix.insert("/user/:name/likes/")
	radix.insert("/uses/")
	radix.insert("/admin/products/")
	radix.insert("/admin/products/:id/view/")
	radix.insert("/admin/products/:id/edit/")
	radix.insert("/admin/more/")
	radix.insert("/search/")
	radix.insert("/support/")

	// Trivial Example 1:
	//radix.insert("romane")
	//radix.insert("romanus")
	//radix.insert("romulus")
	//radix.insert("rubens")
	//radix.insert("ruber")
	//radix.insert("rubicon")
	//radix.insert("rubicundus")

	// Trivial Example 2:
	//radix.insert(" ")
	//radix.insert(" test")
	//radix.insert(" toaster")
	//radix.insert(" toasting")
	//radix.insert(" slow")
	//radix.insert(" slowly")
}

func printRecursive(n *node, level int) {
	fmt.Println(string(n.path), " - ", level)
	if len(n.children) > 0 {
		for _, c := range n.children {
			printRecursive(c, level+1)
		}
	}
}
<commit_msg>Before SoC<commit_after>package main

import "fmt"

func main() {

	radix := node{}

	insertToRadix(&radix)

	node, params := radix.lookUp("ruby")

	if node != nil {
		fmt.Println(string(node.path), params)
	} else {
		fmt.Println("Nothing found.")
	}
}

func insertToRadix(radix *node) {

	// HTTP Router:
	// radix.insert("/something/")
	// radix.insert("/user/")
	// radix.insert("/admin/")
	// radix.insert("/admin/auth/")
	// radix.insert("/user/profile/")
	// radix.insert("/user/:name/")
	// radix.insert("/user/:name/view/")
	// radix.insert("/user/:name/likes/")
	// radix.insert("/uses/")
	// radix.insert("/admin/products/")
	// radix.insert("/admin/products/:id/view/")
	// radix.insert("/admin/products/:id/edit/")
	// radix.insert("/admin/more/")
	// radix.insert("/search/")
	// radix.insert("/support/")

	// Trivial Example 1:
	radix.insert("romane")
	radix.insert("romanus")
	radix.insert("romulus")
	radix.insert("rubens")
	radix.insert("ruber")
	radix.insert("rubicon")
	radix.insert("rubicundus")

	// Trivial Example 2:
	//radix.insert(" ")
	//radix.insert(" test")
	//radix.insert(" toaster")
	//radix.insert(" toasting")
	//radix.insert(" slow")
	//radix.insert(" slowly")
}

func printRecursive(n *node, level int) {
	fmt.Println(string(n.path), " - ", level)
	if len(n.children) > 0 {
		for _, c := range n.children {
			printRecursive(c, level+1)
		}
	}
}
<|endoftext|>


<commit_before>// Copyright 2014 Jeff Hodges. Copied out of golang's mime/multipart
// and exposed for others to use.
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// The file define a quoted-printable decoder, as specified in RFC 2045.
// Deviations:
// 1. in addition to "=\r\n", "=\n" is also treated as soft line break.
// 2. it will pass through a '\r' or '\n' not preceded by '=', consistent
//    with other broken QP encoders & decoders.

package quotedprintable

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
)

type QPReader struct {
	br   *bufio.Reader
	rerr error  // last read error
	line []byte // to be consumed before more of br
}

func NewQuotedPrintableReader(r io.Reader) io.Reader {
	br, ok := r.(*bufio.Reader)
	if !ok {
		br = bufio.NewReader(r)
	}
	return &QPReader{br: br}
}
func fromHex(b byte) (byte, error) {
	switch {
	case b >= '0' && b <= '9':
		return b - '0', nil
	case b >= 'A' && b <= 'F':
		return b - 'A' + 10, nil
	}
	return 0, fmt.Errorf("multipart: invalid quoted-printable hex byte 0x%02x", b)
}

func (q *QPReader) readHexByte(v []byte) (b byte, err error) {
	if len(v) < 2 {
		return 0, io.ErrUnexpectedEOF
	}
	var hb, lb byte
	if hb, err = fromHex(v[0]); err != nil {
		return 0, err
	}
	if lb, err = fromHex(v[1]); err != nil {
		return 0, err
	}
	return hb<<4 | lb, nil
}

func isQPDiscardWhitespace(r rune) bool {
	switch r {
	case '\n', '\r', ' ', '\t':
		return true
	}
	return false
}

var (
	crlf       = []byte("\r\n")
	lf         = []byte("\n")
	softSuffix = []byte("=")
)

func (q *QPReader) Read(p []byte) (n int, err error) {
	for len(p) > 0 {
		if len(q.line) == 0 {
			if q.rerr != nil {
				return n, q.rerr
			}
			q.line, q.rerr = q.br.ReadSlice('\n')

			// Does the line end in CRLF instead of just LF?
			hasLF := bytes.HasSuffix(q.line, lf)
			hasCR := bytes.HasSuffix(q.line, crlf)
			wholeLine := q.line
			q.line = bytes.TrimRightFunc(wholeLine, isQPDiscardWhitespace)
			if bytes.HasSuffix(q.line, softSuffix) {
				rightStripped := wholeLine[len(q.line):]
				q.line = q.line[:len(q.line)-1]
				if !bytes.HasPrefix(rightStripped, lf) && !bytes.HasPrefix(rightStripped, crlf) {
					q.rerr = fmt.Errorf("multipart: invalid bytes after =: %q", rightStripped)
				}
			} else if hasLF {
				if hasCR {
					q.line = append(q.line, '\r', '\n')
				} else {
					q.line = append(q.line, '\n')
				}
			}
			continue
		}
		b := q.line[0]

		switch {
		case b == '=':
			b, err = q.readHexByte(q.line[1:])
			if err != nil {
				return n, err
			}
			q.line = q.line[2:] // 2 of the 3; other 1 is done below
		case b == '\t' || b == '\r' || b == '\n':
			break
		case b < ' ' || b > '~':
			return n, fmt.Errorf("multipart: invalid unescaped byte 0x%02x in quoted-printable body", b)
		}
		p[0] = b
		p = p[1:]
		q.line = q.line[1:]
		n++
	}
	return n, nil
}
<commit_msg>add a tiny amount of godoc<commit_after>// Copyright 2014 Jeff Hodges. Copied out of golang's mime/multipart
// and exposed for others to use.
// Copyright 2012 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// The file define a quoted-printable decoder, as specified in RFC 2045.
// Deviations:
// 1. in addition to "=\r\n", "=\n" is also treated as soft line break.
// 2. it will pass through a '\r' or '\n' not preceded by '=', consistent
//    with other broken QP encoders & decoders.

package quotedprintable

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
)

type QPReader struct {
	br   *bufio.Reader
	rerr error  // last read error
	line []byte // to be consumed before more of br
}

// NewQuotedPrintableReader decodes quoted-printable data as it is
// read. If the reader passed in is not a *bufio.Reader, it will wrap
// it in one.
func NewQuotedPrintableReader(r io.Reader) io.Reader {
	br, ok := r.(*bufio.Reader)
	if !ok {
		br = bufio.NewReader(r)
	}
	return &QPReader{br: br}
}
func fromHex(b byte) (byte, error) {
	switch {
	case b >= '0' && b <= '9':
		return b - '0', nil
	case b >= 'A' && b <= 'F':
		return b - 'A' + 10, nil
	}
	return 0, fmt.Errorf("multipart: invalid quoted-printable hex byte 0x%02x", b)
}

func (q *QPReader) readHexByte(v []byte) (b byte, err error) {
	if len(v) < 2 {
		return 0, io.ErrUnexpectedEOF
	}
	var hb, lb byte
	if hb, err = fromHex(v[0]); err != nil {
		return 0, err
	}
	if lb, err = fromHex(v[1]); err != nil {
		return 0, err
	}
	return hb<<4 | lb, nil
}

func isQPDiscardWhitespace(r rune) bool {
	switch r {
	case '\n', '\r', ' ', '\t':
		return true
	}
	return false
}

var (
	crlf       = []byte("\r\n")
	lf         = []byte("\n")
	softSuffix = []byte("=")
)

func (q *QPReader) Read(p []byte) (n int, err error) {
	for len(p) > 0 {
		if len(q.line) == 0 {
			if q.rerr != nil {
				return n, q.rerr
			}
			q.line, q.rerr = q.br.ReadSlice('\n')

			// Does the line end in CRLF instead of just LF?
			hasLF := bytes.HasSuffix(q.line, lf)
			hasCR := bytes.HasSuffix(q.line, crlf)
			wholeLine := q.line
			q.line = bytes.TrimRightFunc(wholeLine, isQPDiscardWhitespace)
			if bytes.HasSuffix(q.line, softSuffix) {
				rightStripped := wholeLine[len(q.line):]
				q.line = q.line[:len(q.line)-1]
				if !bytes.HasPrefix(rightStripped, lf) && !bytes.HasPrefix(rightStripped, crlf) {
					q.rerr = fmt.Errorf("multipart: invalid bytes after =: %q", rightStripped)
				}
			} else if hasLF {
				if hasCR {
					q.line = append(q.line, '\r', '\n')
				} else {
					q.line = append(q.line, '\n')
				}
			}
			continue
		}
		b := q.line[0]

		switch {
		case b == '=':
			b, err = q.readHexByte(q.line[1:])
			if err != nil {
				return n, err
			}
			q.line = q.line[2:] // 2 of the 3; other 1 is done below
		case b == '\t' || b == '\r' || b == '\n':
			break
		case b < ' ' || b > '~':
			return n, fmt.Errorf("multipart: invalid unescaped byte 0x%02x in quoted-printable body", b)
		}
		p[0] = b
		p = p[1:]
		q.line = q.line[1:]
		n++
	}
	return n, nil
}
<|endoftext|>


<commit_before>// Copyright  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 apachereceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/apachereceiver"

import (
	"context"
	"errors"
	"fmt"
	"io"
	"net/http"
	"strconv"
	"strings"
	"time"

	"go.opentelemetry.io/collector/component"
	"go.opentelemetry.io/collector/featuregate"
	"go.opentelemetry.io/collector/pdata/pcommon"
	"go.opentelemetry.io/collector/pdata/pmetric"
	"go.opentelemetry.io/collector/receiver/scrapererror"
	"go.uber.org/zap"

	"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/apachereceiver/internal/metadata"
)

const (
	readmeURL                         = "https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/receiver/apachereceiver/README.md"
	EmitServerNameAsResourceAttribute = "receiver.apache.emitServerNameAsResourceAttribute"
	EmitPortAsResourceAttribute       = "receiver.apache.emitPortAsResourceAttribute"
)

func init() {
	featuregate.GetRegistry().MustRegisterID(
		EmitServerNameAsResourceAttribute,
		featuregate.StageAlpha,
		featuregate.WithRegisterDescription("When enabled, the name of the server will be sent as an apache.server.name resource attribute instead of a metric-level server_name attribute."),
	)
	featuregate.GetRegistry().MustRegisterID(
		EmitPortAsResourceAttribute,
		featuregate.StageAlpha,
		featuregate.WithRegisterDescription("When enabled, the port of the server will be sent as an apache.server.name resource attribute."),
	)
}

type apacheScraper struct {
	settings   component.TelemetrySettings
	cfg        *Config
	httpClient *http.Client
	mb         *metadata.MetricsBuilder
	serverName string
	port       string

	// Feature gates regarding resource attributes
	emitMetricsWithServerNameAsResourceAttribute bool
	emitMetricsWithPortAsResourceAttribute       bool
}

func newApacheScraper(
	settings component.ReceiverCreateSettings,
	cfg *Config,
	serverName string,
	port string,
) *apacheScraper {
	a := &apacheScraper{
		settings:   settings.TelemetrySettings,
		cfg:        cfg,
		mb:         metadata.NewMetricsBuilder(cfg.Metrics, settings.BuildInfo),
		serverName: serverName,
		port:       port,
		emitMetricsWithServerNameAsResourceAttribute: featuregate.GetRegistry().IsEnabled(EmitServerNameAsResourceAttribute),
		emitMetricsWithPortAsResourceAttribute:       featuregate.GetRegistry().IsEnabled(EmitPortAsResourceAttribute),
	}

	if !a.emitMetricsWithServerNameAsResourceAttribute {
		settings.Logger.Warn(
			fmt.Sprintf("Feature gate %s is not enabled. Please see the README for more information: %s", EmitServerNameAsResourceAttribute, readmeURL),
		)
	}

	if !a.emitMetricsWithPortAsResourceAttribute {
		settings.Logger.Warn(
			fmt.Sprintf("Feature gate %s is not enabled. Please see the README for more information: %s", EmitPortAsResourceAttribute, readmeURL),
		)
	}

	return a
}

func (r *apacheScraper) start(_ context.Context, host component.Host) error {
	httpClient, err := r.cfg.ToClient(host, r.settings)
	if err != nil {
		return err
	}
	r.httpClient = httpClient
	return nil
}

func (r *apacheScraper) scrape(context.Context) (pmetric.Metrics, error) {
	if r.httpClient == nil {
		return pmetric.Metrics{}, errors.New("failed to connect to Apache HTTPd")
	}

	stats, err := r.GetStats()
	if err != nil {
		r.settings.Logger.Error("failed to fetch Apache Httpd stats", zap.Error(err))
		return pmetric.Metrics{}, err
	}

	emitWith := []metadata.ResourceMetricsOption{}

	if r.emitMetricsWithServerNameAsResourceAttribute {
		err = r.scrapeWithoutServerNameAttr(stats)
		emitWith = append(emitWith, metadata.WithApacheServerName(r.serverName))
	} else {
		err = r.scrapeWithServerNameAttr(stats)
	}

	if r.emitMetricsWithPortAsResourceAttribute {
		emitWith = append(emitWith, metadata.WithApacheServerPort(r.port))
	}

	return r.mb.Emit(emitWith...), err
}

func (r *apacheScraper) scrapeWithServerNameAttr(stats string) error {
	errs := &scrapererror.ScrapeErrors{}
	now := pcommon.NewTimestampFromTime(time.Now())
	for metricKey, metricValue := range parseStats(stats) {
		switch metricKey {
		case "ServerUptimeSeconds":
			addPartialIfError(errs, r.mb.RecordApacheUptimeDataPointWithServerName(now, metricValue, r.serverName))
		case "ConnsTotal":
			addPartialIfError(errs, r.mb.RecordApacheCurrentConnectionsDataPointWithServerName(now, metricValue, r.serverName))
		case "BusyWorkers":
			addPartialIfError(errs, r.mb.RecordApacheWorkersDataPointWithServerName(now, metricValue, r.serverName,
				metadata.AttributeWorkersStateBusy))
		case "IdleWorkers":
			addPartialIfError(errs, r.mb.RecordApacheWorkersDataPointWithServerName(now, metricValue, r.serverName,
				metadata.AttributeWorkersStateIdle))
		case "Total Accesses":
			addPartialIfError(errs, r.mb.RecordApacheRequestsDataPointWithServerName(now, metricValue, r.serverName))
		case "Total kBytes":
			i, err := strconv.ParseInt(metricValue, 10, 64)
			if err != nil {
				errs.AddPartial(1, err)
			} else {
				r.mb.RecordApacheTrafficDataPointWithServerName(now, kbytesToBytes(i), r.serverName)
			}
		case "CPUChildrenSystem":
			addPartialIfError(
				errs,
				r.mb.RecordApacheCPUTimeDataPointWithServerName(now, metricValue, r.serverName, metadata.AttributeCPULevelChildren, metadata.AttributeCPUModeSystem),
			)
		case "CPUChildrenUser":
			addPartialIfError(
				errs,
				r.mb.RecordApacheCPUTimeDataPointWithServerName(now, metricValue, r.serverName, metadata.AttributeCPULevelChildren, metadata.AttributeCPUModeUser),
			)
		case "CPUSystem":
			addPartialIfError(
				errs,
				r.mb.RecordApacheCPUTimeDataPointWithServerName(now, metricValue, r.serverName, metadata.AttributeCPULevelSelf, metadata.AttributeCPUModeSystem),
			)
		case "CPUUser":
			addPartialIfError(
				errs,
				r.mb.RecordApacheCPUTimeDataPointWithServerName(now, metricValue, r.serverName, metadata.AttributeCPULevelSelf, metadata.AttributeCPUModeUser),
			)
		case "CPULoad":
			addPartialIfError(errs, r.mb.RecordApacheCPULoadDataPointWithServerName(now, metricValue, r.serverName))
		case "Load1":
			addPartialIfError(errs, r.mb.RecordApacheLoad1DataPointWithServerName(now, metricValue, r.serverName))
		case "Load5":
			addPartialIfError(errs, r.mb.RecordApacheLoad5DataPointWithServerName(now, metricValue, r.serverName))
		case "Load15":
			addPartialIfError(errs, r.mb.RecordApacheLoad15DataPointWithServerName(now, metricValue, r.serverName))
		case "Total Duration":
			addPartialIfError(errs, r.mb.RecordApacheRequestTimeDataPointWithServerName(now, metricValue, r.serverName))
		case "Scoreboard":
			scoreboardMap := parseScoreboard(metricValue)
			for state, score := range scoreboardMap {
				r.mb.RecordApacheScoreboardDataPointWithServerName(now, score, r.serverName, state)
			}
		}
	}

	return errs.Combine()
}

func (r *apacheScraper) scrapeWithoutServerNameAttr(stats string) error {
	errs := &scrapererror.ScrapeErrors{}
	now := pcommon.NewTimestampFromTime(time.Now())
	for metricKey, metricValue := range parseStats(stats) {
		switch metricKey {
		case "ServerUptimeSeconds":
			addPartialIfError(errs, r.mb.RecordApacheUptimeDataPoint(now, metricValue))
		case "ConnsTotal":
			addPartialIfError(errs, r.mb.RecordApacheCurrentConnectionsDataPoint(now, metricValue))
		case "BusyWorkers":
			addPartialIfError(errs, r.mb.RecordApacheWorkersDataPoint(now, metricValue, metadata.AttributeWorkersStateBusy))
		case "IdleWorkers":
			addPartialIfError(errs, r.mb.RecordApacheWorkersDataPoint(now, metricValue, metadata.AttributeWorkersStateIdle))
		case "Total Accesses":
			addPartialIfError(errs, r.mb.RecordApacheRequestsDataPoint(now, metricValue))
		case "Total kBytes":
			i, err := strconv.ParseInt(metricValue, 10, 64)
			if err != nil {
				errs.AddPartial(1, err)
			} else {
				r.mb.RecordApacheTrafficDataPoint(now, kbytesToBytes(i))
			}
		case "CPUChildrenSystem":
			addPartialIfError(
				errs,
				r.mb.RecordApacheCPUTimeDataPoint(now, metricValue, metadata.AttributeCPULevelChildren, metadata.AttributeCPUModeSystem),
			)
		case "CPUChildrenUser":
			addPartialIfError(
				errs,
				r.mb.RecordApacheCPUTimeDataPoint(now, metricValue, metadata.AttributeCPULevelChildren, metadata.AttributeCPUModeUser),
			)
		case "CPUSystem":
			addPartialIfError(
				errs,
				r.mb.RecordApacheCPUTimeDataPoint(now, metricValue, metadata.AttributeCPULevelSelf, metadata.AttributeCPUModeSystem),
			)
		case "CPUUser":
			addPartialIfError(
				errs,
				r.mb.RecordApacheCPUTimeDataPoint(now, metricValue, metadata.AttributeCPULevelSelf, metadata.AttributeCPUModeUser),
			)
		case "CPULoad":
			addPartialIfError(errs, r.mb.RecordApacheCPULoadDataPoint(now, metricValue))
		case "Load1":
			addPartialIfError(errs, r.mb.RecordApacheLoad1DataPoint(now, metricValue))
		case "Load5":
			addPartialIfError(errs, r.mb.RecordApacheLoad5DataPoint(now, metricValue))
		case "Load15":
			addPartialIfError(errs, r.mb.RecordApacheLoad15DataPoint(now, metricValue))
		case "Total Duration":
			addPartialIfError(errs, r.mb.RecordApacheRequestTimeDataPoint(now, metricValue))
		case "Scoreboard":
			scoreboardMap := parseScoreboard(metricValue)
			for state, score := range scoreboardMap {
				r.mb.RecordApacheScoreboardDataPoint(now, score, state)
			}
		}
	}

	return errs.Combine()
}

func addPartialIfError(errs *scrapererror.ScrapeErrors, err error) {
	if err != nil {
		errs.AddPartial(1, err)
	}
}

// GetStats collects metric stats by making a get request at an endpoint.
func (r *apacheScraper) GetStats() (string, error) {
	resp, err := r.httpClient.Get(r.cfg.Endpoint)
	if err != nil {
		return "", err
	}

	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	return string(body), nil
}

// parseStats converts a response body key:values into a map.
func parseStats(resp string) map[string]string {
	metrics := make(map[string]string)

	fields := strings.Split(resp, "\n")
	for _, field := range fields {
		index := strings.Index(field, ": ")
		if index == -1 {
			continue
		}
		metrics[field[:index]] = field[index+2:]
	}
	return metrics
}

type scoreboardCountsByLabel map[metadata.AttributeScoreboardState]int64

// parseScoreboard quantifies the symbolic mapping of the scoreboard.
func parseScoreboard(values string) scoreboardCountsByLabel {
	scoreboard := scoreboardCountsByLabel{
		metadata.AttributeScoreboardStateWaiting:     0,
		metadata.AttributeScoreboardStateStarting:    0,
		metadata.AttributeScoreboardStateReading:     0,
		metadata.AttributeScoreboardStateSending:     0,
		metadata.AttributeScoreboardStateKeepalive:   0,
		metadata.AttributeScoreboardStateDnslookup:   0,
		metadata.AttributeScoreboardStateClosing:     0,
		metadata.AttributeScoreboardStateLogging:     0,
		metadata.AttributeScoreboardStateFinishing:   0,
		metadata.AttributeScoreboardStateIdleCleanup: 0,
		metadata.AttributeScoreboardStateOpen:        0,
	}

	for _, char := range values {
		switch string(char) {
		case "_":
			scoreboard[metadata.AttributeScoreboardStateWaiting]++
		case "S":
			scoreboard[metadata.AttributeScoreboardStateStarting]++
		case "R":
			scoreboard[metadata.AttributeScoreboardStateReading]++
		case "W":
			scoreboard[metadata.AttributeScoreboardStateSending]++
		case "K":
			scoreboard[metadata.AttributeScoreboardStateKeepalive]++
		case "D":
			scoreboard[metadata.AttributeScoreboardStateDnslookup]++
		case "C":
			scoreboard[metadata.AttributeScoreboardStateClosing]++
		case "L":
			scoreboard[metadata.AttributeScoreboardStateLogging]++
		case "G":
			scoreboard[metadata.AttributeScoreboardStateFinishing]++
		case "I":
			scoreboard[metadata.AttributeScoreboardStateIdleCleanup]++
		case ".":
			scoreboard[metadata.AttributeScoreboardStateOpen]++
		default:
			scoreboard[metadata.AttributeScoreboardStateUnknown]++
		}
	}
	return scoreboard
}

// kbytesToBytes converts 1 Kibibyte to 1024 bytes.
func kbytesToBytes(i int64) int64 {
	return 1024 * i
}
<commit_msg>[chore]: fix port feature gate's description in apachereceiver (#16280)<commit_after>// Copyright  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 apachereceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/apachereceiver"

import (
	"context"
	"errors"
	"fmt"
	"io"
	"net/http"
	"strconv"
	"strings"
	"time"

	"go.opentelemetry.io/collector/component"
	"go.opentelemetry.io/collector/featuregate"
	"go.opentelemetry.io/collector/pdata/pcommon"
	"go.opentelemetry.io/collector/pdata/pmetric"
	"go.opentelemetry.io/collector/receiver/scrapererror"
	"go.uber.org/zap"

	"github.com/open-telemetry/opentelemetry-collector-contrib/receiver/apachereceiver/internal/metadata"
)

const (
	readmeURL                         = "https://github.com/open-telemetry/opentelemetry-collector-contrib/blob/main/receiver/apachereceiver/README.md"
	EmitServerNameAsResourceAttribute = "receiver.apache.emitServerNameAsResourceAttribute"
	EmitPortAsResourceAttribute       = "receiver.apache.emitPortAsResourceAttribute"
)

func init() {
	featuregate.GetRegistry().MustRegisterID(
		EmitServerNameAsResourceAttribute,
		featuregate.StageAlpha,
		featuregate.WithRegisterDescription("When enabled, the name of the server will be sent as an apache.server.name resource attribute instead of a metric-level server_name attribute."),
	)
	featuregate.GetRegistry().MustRegisterID(
		EmitPortAsResourceAttribute,
		featuregate.StageAlpha,
		featuregate.WithRegisterDescription("When enabled, the port of the server will be sent as an apache.server.port resource attribute."),
	)
}

type apacheScraper struct {
	settings   component.TelemetrySettings
	cfg        *Config
	httpClient *http.Client
	mb         *metadata.MetricsBuilder
	serverName string
	port       string

	// Feature gates regarding resource attributes
	emitMetricsWithServerNameAsResourceAttribute bool
	emitMetricsWithPortAsResourceAttribute       bool
}

func newApacheScraper(
	settings component.ReceiverCreateSettings,
	cfg *Config,
	serverName string,
	port string,
) *apacheScraper {
	a := &apacheScraper{
		settings:   settings.TelemetrySettings,
		cfg:        cfg,
		mb:         metadata.NewMetricsBuilder(cfg.Metrics, settings.BuildInfo),
		serverName: serverName,
		port:       port,
		emitMetricsWithServerNameAsResourceAttribute: featuregate.GetRegistry().IsEnabled(EmitServerNameAsResourceAttribute),
		emitMetricsWithPortAsResourceAttribute:       featuregate.GetRegistry().IsEnabled(EmitPortAsResourceAttribute),
	}

	if !a.emitMetricsWithServerNameAsResourceAttribute {
		settings.Logger.Warn(
			fmt.Sprintf("Feature gate %s is not enabled. Please see the README for more information: %s", EmitServerNameAsResourceAttribute, readmeURL),
		)
	}

	if !a.emitMetricsWithPortAsResourceAttribute {
		settings.Logger.Warn(
			fmt.Sprintf("Feature gate %s is not enabled. Please see the README for more information: %s", EmitPortAsResourceAttribute, readmeURL),
		)
	}

	return a
}

func (r *apacheScraper) start(_ context.Context, host component.Host) error {
	httpClient, err := r.cfg.ToClient(host, r.settings)
	if err != nil {
		return err
	}
	r.httpClient = httpClient
	return nil
}

func (r *apacheScraper) scrape(context.Context) (pmetric.Metrics, error) {
	if r.httpClient == nil {
		return pmetric.Metrics{}, errors.New("failed to connect to Apache HTTPd")
	}

	stats, err := r.GetStats()
	if err != nil {
		r.settings.Logger.Error("failed to fetch Apache Httpd stats", zap.Error(err))
		return pmetric.Metrics{}, err
	}

	emitWith := []metadata.ResourceMetricsOption{}

	if r.emitMetricsWithServerNameAsResourceAttribute {
		err = r.scrapeWithoutServerNameAttr(stats)
		emitWith = append(emitWith, metadata.WithApacheServerName(r.serverName))
	} else {
		err = r.scrapeWithServerNameAttr(stats)
	}

	if r.emitMetricsWithPortAsResourceAttribute {
		emitWith = append(emitWith, metadata.WithApacheServerPort(r.port))
	}

	return r.mb.Emit(emitWith...), err
}

func (r *apacheScraper) scrapeWithServerNameAttr(stats string) error {
	errs := &scrapererror.ScrapeErrors{}
	now := pcommon.NewTimestampFromTime(time.Now())
	for metricKey, metricValue := range parseStats(stats) {
		switch metricKey {
		case "ServerUptimeSeconds":
			addPartialIfError(errs, r.mb.RecordApacheUptimeDataPointWithServerName(now, metricValue, r.serverName))
		case "ConnsTotal":
			addPartialIfError(errs, r.mb.RecordApacheCurrentConnectionsDataPointWithServerName(now, metricValue, r.serverName))
		case "BusyWorkers":
			addPartialIfError(errs, r.mb.RecordApacheWorkersDataPointWithServerName(now, metricValue, r.serverName,
				metadata.AttributeWorkersStateBusy))
		case "IdleWorkers":
			addPartialIfError(errs, r.mb.RecordApacheWorkersDataPointWithServerName(now, metricValue, r.serverName,
				metadata.AttributeWorkersStateIdle))
		case "Total Accesses":
			addPartialIfError(errs, r.mb.RecordApacheRequestsDataPointWithServerName(now, metricValue, r.serverName))
		case "Total kBytes":
			i, err := strconv.ParseInt(metricValue, 10, 64)
			if err != nil {
				errs.AddPartial(1, err)
			} else {
				r.mb.RecordApacheTrafficDataPointWithServerName(now, kbytesToBytes(i), r.serverName)
			}
		case "CPUChildrenSystem":
			addPartialIfError(
				errs,
				r.mb.RecordApacheCPUTimeDataPointWithServerName(now, metricValue, r.serverName, metadata.AttributeCPULevelChildren, metadata.AttributeCPUModeSystem),
			)
		case "CPUChildrenUser":
			addPartialIfError(
				errs,
				r.mb.RecordApacheCPUTimeDataPointWithServerName(now, metricValue, r.serverName, metadata.AttributeCPULevelChildren, metadata.AttributeCPUModeUser),
			)
		case "CPUSystem":
			addPartialIfError(
				errs,
				r.mb.RecordApacheCPUTimeDataPointWithServerName(now, metricValue, r.serverName, metadata.AttributeCPULevelSelf, metadata.AttributeCPUModeSystem),
			)
		case "CPUUser":
			addPartialIfError(
				errs,
				r.mb.RecordApacheCPUTimeDataPointWithServerName(now, metricValue, r.serverName, metadata.AttributeCPULevelSelf, metadata.AttributeCPUModeUser),
			)
		case "CPULoad":
			addPartialIfError(errs, r.mb.RecordApacheCPULoadDataPointWithServerName(now, metricValue, r.serverName))
		case "Load1":
			addPartialIfError(errs, r.mb.RecordApacheLoad1DataPointWithServerName(now, metricValue, r.serverName))
		case "Load5":
			addPartialIfError(errs, r.mb.RecordApacheLoad5DataPointWithServerName(now, metricValue, r.serverName))
		case "Load15":
			addPartialIfError(errs, r.mb.RecordApacheLoad15DataPointWithServerName(now, metricValue, r.serverName))
		case "Total Duration":
			addPartialIfError(errs, r.mb.RecordApacheRequestTimeDataPointWithServerName(now, metricValue, r.serverName))
		case "Scoreboard":
			scoreboardMap := parseScoreboard(metricValue)
			for state, score := range scoreboardMap {
				r.mb.RecordApacheScoreboardDataPointWithServerName(now, score, r.serverName, state)
			}
		}
	}

	return errs.Combine()
}

func (r *apacheScraper) scrapeWithoutServerNameAttr(stats string) error {
	errs := &scrapererror.ScrapeErrors{}
	now := pcommon.NewTimestampFromTime(time.Now())
	for metricKey, metricValue := range parseStats(stats) {
		switch metricKey {
		case "ServerUptimeSeconds":
			addPartialIfError(errs, r.mb.RecordApacheUptimeDataPoint(now, metricValue))
		case "ConnsTotal":
			addPartialIfError(errs, r.mb.RecordApacheCurrentConnectionsDataPoint(now, metricValue))
		case "BusyWorkers":
			addPartialIfError(errs, r.mb.RecordApacheWorkersDataPoint(now, metricValue, metadata.AttributeWorkersStateBusy))
		case "IdleWorkers":
			addPartialIfError(errs, r.mb.RecordApacheWorkersDataPoint(now, metricValue, metadata.AttributeWorkersStateIdle))
		case "Total Accesses":
			addPartialIfError(errs, r.mb.RecordApacheRequestsDataPoint(now, metricValue))
		case "Total kBytes":
			i, err := strconv.ParseInt(metricValue, 10, 64)
			if err != nil {
				errs.AddPartial(1, err)
			} else {
				r.mb.RecordApacheTrafficDataPoint(now, kbytesToBytes(i))
			}
		case "CPUChildrenSystem":
			addPartialIfError(
				errs,
				r.mb.RecordApacheCPUTimeDataPoint(now, metricValue, metadata.AttributeCPULevelChildren, metadata.AttributeCPUModeSystem),
			)
		case "CPUChildrenUser":
			addPartialIfError(
				errs,
				r.mb.RecordApacheCPUTimeDataPoint(now, metricValue, metadata.AttributeCPULevelChildren, metadata.AttributeCPUModeUser),
			)
		case "CPUSystem":
			addPartialIfError(
				errs,
				r.mb.RecordApacheCPUTimeDataPoint(now, metricValue, metadata.AttributeCPULevelSelf, metadata.AttributeCPUModeSystem),
			)
		case "CPUUser":
			addPartialIfError(
				errs,
				r.mb.RecordApacheCPUTimeDataPoint(now, metricValue, metadata.AttributeCPULevelSelf, metadata.AttributeCPUModeUser),
			)
		case "CPULoad":
			addPartialIfError(errs, r.mb.RecordApacheCPULoadDataPoint(now, metricValue))
		case "Load1":
			addPartialIfError(errs, r.mb.RecordApacheLoad1DataPoint(now, metricValue))
		case "Load5":
			addPartialIfError(errs, r.mb.RecordApacheLoad5DataPoint(now, metricValue))
		case "Load15":
			addPartialIfError(errs, r.mb.RecordApacheLoad15DataPoint(now, metricValue))
		case "Total Duration":
			addPartialIfError(errs, r.mb.RecordApacheRequestTimeDataPoint(now, metricValue))
		case "Scoreboard":
			scoreboardMap := parseScoreboard(metricValue)
			for state, score := range scoreboardMap {
				r.mb.RecordApacheScoreboardDataPoint(now, score, state)
			}
		}
	}

	return errs.Combine()
}

func addPartialIfError(errs *scrapererror.ScrapeErrors, err error) {
	if err != nil {
		errs.AddPartial(1, err)
	}
}

// GetStats collects metric stats by making a get request at an endpoint.
func (r *apacheScraper) GetStats() (string, error) {
	resp, err := r.httpClient.Get(r.cfg.Endpoint)
	if err != nil {
		return "", err
	}

	defer resp.Body.Close()

	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	return string(body), nil
}

// parseStats converts a response body key:values into a map.
func parseStats(resp string) map[string]string {
	metrics := make(map[string]string)

	fields := strings.Split(resp, "\n")
	for _, field := range fields {
		index := strings.Index(field, ": ")
		if index == -1 {
			continue
		}
		metrics[field[:index]] = field[index+2:]
	}
	return metrics
}

type scoreboardCountsByLabel map[metadata.AttributeScoreboardState]int64

// parseScoreboard quantifies the symbolic mapping of the scoreboard.
func parseScoreboard(values string) scoreboardCountsByLabel {
	scoreboard := scoreboardCountsByLabel{
		metadata.AttributeScoreboardStateWaiting:     0,
		metadata.AttributeScoreboardStateStarting:    0,
		metadata.AttributeScoreboardStateReading:     0,
		metadata.AttributeScoreboardStateSending:     0,
		metadata.AttributeScoreboardStateKeepalive:   0,
		metadata.AttributeScoreboardStateDnslookup:   0,
		metadata.AttributeScoreboardStateClosing:     0,
		metadata.AttributeScoreboardStateLogging:     0,
		metadata.AttributeScoreboardStateFinishing:   0,
		metadata.AttributeScoreboardStateIdleCleanup: 0,
		metadata.AttributeScoreboardStateOpen:        0,
	}

	for _, char := range values {
		switch string(char) {
		case "_":
			scoreboard[metadata.AttributeScoreboardStateWaiting]++
		case "S":
			scoreboard[metadata.AttributeScoreboardStateStarting]++
		case "R":
			scoreboard[metadata.AttributeScoreboardStateReading]++
		case "W":
			scoreboard[metadata.AttributeScoreboardStateSending]++
		case "K":
			scoreboard[metadata.AttributeScoreboardStateKeepalive]++
		case "D":
			scoreboard[metadata.AttributeScoreboardStateDnslookup]++
		case "C":
			scoreboard[metadata.AttributeScoreboardStateClosing]++
		case "L":
			scoreboard[metadata.AttributeScoreboardStateLogging]++
		case "G":
			scoreboard[metadata.AttributeScoreboardStateFinishing]++
		case "I":
			scoreboard[metadata.AttributeScoreboardStateIdleCleanup]++
		case ".":
			scoreboard[metadata.AttributeScoreboardStateOpen]++
		default:
			scoreboard[metadata.AttributeScoreboardStateUnknown]++
		}
	}
	return scoreboard
}

// kbytesToBytes converts 1 Kibibyte to 1024 bytes.
func kbytesToBytes(i int64) int64 {
	return 1024 * i
}
<|endoftext|>


<commit_before>// Copyright 2020, 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.

//go:build !windows
// +build !windows

package podmanreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/podmanreceiver"

import (
	"fmt"
	"time"

	"go.opentelemetry.io/collector/model/pdata"
	conventions "go.opentelemetry.io/collector/model/semconv/v1.6.1"
)

type point struct {
	intVal     uint64
	doubleVal  float64
	attributes map[string]string
}

func translateStatsToMetrics(stats *containerStats, ts time.Time, rm pdata.ResourceMetrics) {
	pbts := pdata.NewTimestampFromTime(ts)

	resource := rm.Resource()
	resource.Attributes().InsertString(conventions.AttributeContainerRuntime, "podman")
	resource.Attributes().InsertString("container.name", stats.Name)
	resource.Attributes().InsertString("container.id", stats.ContainerID)

	ms := rm.InstrumentationLibraryMetrics().AppendEmpty().Metrics()
	appendIOMetrics(ms, stats, pbts)
	appendCPUMetrics(ms, stats, pbts)
	appendNetworkMetrics(ms, stats, pbts)
	appendMemoryMetrics(ms, stats, pbts)
}

func appendMemoryMetrics(ms pdata.MetricSlice, stats *containerStats, ts pdata.Timestamp) {
	gaugeI(ms, "memory.usage.limit", "By", []point{{intVal: stats.MemLimit}}, ts)
	gaugeI(ms, "memory.usage.total", "By", []point{{intVal: stats.MemUsage}}, ts)
	gaugeF(ms, "memory.percent", "1", []point{{doubleVal: stats.MemPerc}}, ts)
}

func appendNetworkMetrics(ms pdata.MetricSlice, stats *containerStats, ts pdata.Timestamp) {
	sum(ms, "network.io.usage.tx_bytes", "By", []point{{intVal: stats.NetInput}}, ts)
	sum(ms, "network.io.usage.rx_bytes", "By", []point{{intVal: stats.NetOutput}}, ts)
}

func appendIOMetrics(ms pdata.MetricSlice, stats *containerStats, ts pdata.Timestamp) {
	sum(ms, "blockio.io_service_bytes_recursive.write", "By", []point{{intVal: stats.BlockOutput}}, ts)
	sum(ms, "blockio.io_service_bytes_recursive.read", "By", []point{{intVal: stats.BlockInput}}, ts)
}

func appendCPUMetrics(ms pdata.MetricSlice, stats *containerStats, ts pdata.Timestamp) {
	sum(ms, "cpu.usage.system", "ns", []point{{intVal: stats.CPUSystemNano}}, ts)
	sum(ms, "cpu.usage.total", "ns", []point{{intVal: stats.CPUNano}}, ts)
	gaugeF(ms, "cpu.percent", "1", []point{{doubleVal: stats.CPU}}, ts)

	points := make([]point, len(stats.PerCPU))
	for i, cpu := range stats.PerCPU {
		points[i] = point{
			intVal: cpu,
			attributes: map[string]string{
				"core": fmt.Sprintf("cpu%d", i),
			},
		}
	}
	sum(ms, "cpu.usage.percpu", "ns", points, ts)
}

func initMetric(ms pdata.MetricSlice, name, unit string) pdata.Metric {
	m := ms.AppendEmpty()
	m.SetName(fmt.Sprintf("container.%s", name))
	m.SetUnit(unit)
	return m
}

func sum(ilm pdata.MetricSlice, metricName string, unit string, points []point, ts pdata.Timestamp) {
	metric := initMetric(ilm, metricName, unit)

	metric.SetDataType(pdata.MetricDataTypeSum)
	sum := metric.Sum()
	sum.SetIsMonotonic(true)
	sum.SetAggregationTemporality(pdata.MetricAggregationTemporalityCumulative)

	dataPoints := sum.DataPoints()

	for _, pt := range points {
		dataPoint := dataPoints.AppendEmpty()
		dataPoint.SetTimestamp(ts)
		dataPoint.SetIntVal(int64(pt.intVal))
		setDataPointAttributes(dataPoint, pt.attributes)
	}
}

func gauge(ms pdata.MetricSlice, metricName string, unit string) pdata.NumberDataPointSlice {
	metric := initMetric(ms, metricName, unit)
	metric.SetDataType(pdata.MetricDataTypeGauge)

	gauge := metric.Gauge()
	return gauge.DataPoints()
}

func gaugeI(ms pdata.MetricSlice, metricName string, unit string, points []point, ts pdata.Timestamp) {
	dataPoints := gauge(ms, metricName, unit)
	for _, pt := range points {
		dataPoint := dataPoints.AppendEmpty()
		dataPoint.SetTimestamp(ts)
		dataPoint.SetIntVal(int64(pt.intVal))
		setDataPointAttributes(dataPoint, pt.attributes)
	}
}

func gaugeF(ms pdata.MetricSlice, metricName string, unit string, points []point, ts pdata.Timestamp) {
	dataPoints := gauge(ms, metricName, unit)
	for _, pt := range points {
		dataPoint := dataPoints.AppendEmpty()
		dataPoint.SetTimestamp(ts)
		dataPoint.SetDoubleVal(pt.doubleVal)
		setDataPointAttributes(dataPoint, pt.attributes)
	}
}

func setDataPointAttributes(dataPoint pdata.NumberDataPoint, attributes map[string]string) {
	for k, v := range attributes {
		dataPoint.Attributes().InsertString(k, v)
	}
}
<commit_msg>[receiver/podman] update string to semconv (#8315)<commit_after>// Copyright 2020, 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.

//go:build !windows
// +build !windows

package podmanreceiver // import "github.com/open-telemetry/opentelemetry-collector-contrib/receiver/podmanreceiver"

import (
	"fmt"
	"time"

	"go.opentelemetry.io/collector/model/pdata"
	conventions "go.opentelemetry.io/collector/model/semconv/v1.6.1"
)

type point struct {
	intVal     uint64
	doubleVal  float64
	attributes map[string]string
}

func translateStatsToMetrics(stats *containerStats, ts time.Time, rm pdata.ResourceMetrics) {
	pbts := pdata.NewTimestampFromTime(ts)

	resource := rm.Resource()
	resource.Attributes().InsertString(conventions.AttributeContainerRuntime, "podman")
	resource.Attributes().InsertString(conventions.AttributeContainerName, stats.Name)
	resource.Attributes().InsertString(conventions.AttributeContainerID, stats.ContainerID)

	ms := rm.InstrumentationLibraryMetrics().AppendEmpty().Metrics()
	appendIOMetrics(ms, stats, pbts)
	appendCPUMetrics(ms, stats, pbts)
	appendNetworkMetrics(ms, stats, pbts)
	appendMemoryMetrics(ms, stats, pbts)
}

func appendMemoryMetrics(ms pdata.MetricSlice, stats *containerStats, ts pdata.Timestamp) {
	gaugeI(ms, "memory.usage.limit", "By", []point{{intVal: stats.MemLimit}}, ts)
	gaugeI(ms, "memory.usage.total", "By", []point{{intVal: stats.MemUsage}}, ts)
	gaugeF(ms, "memory.percent", "1", []point{{doubleVal: stats.MemPerc}}, ts)
}

func appendNetworkMetrics(ms pdata.MetricSlice, stats *containerStats, ts pdata.Timestamp) {
	sum(ms, "network.io.usage.tx_bytes", "By", []point{{intVal: stats.NetInput}}, ts)
	sum(ms, "network.io.usage.rx_bytes", "By", []point{{intVal: stats.NetOutput}}, ts)
}

func appendIOMetrics(ms pdata.MetricSlice, stats *containerStats, ts pdata.Timestamp) {
	sum(ms, "blockio.io_service_bytes_recursive.write", "By", []point{{intVal: stats.BlockOutput}}, ts)
	sum(ms, "blockio.io_service_bytes_recursive.read", "By", []point{{intVal: stats.BlockInput}}, ts)
}

func appendCPUMetrics(ms pdata.MetricSlice, stats *containerStats, ts pdata.Timestamp) {
	sum(ms, "cpu.usage.system", "ns", []point{{intVal: stats.CPUSystemNano}}, ts)
	sum(ms, "cpu.usage.total", "ns", []point{{intVal: stats.CPUNano}}, ts)
	gaugeF(ms, "cpu.percent", "1", []point{{doubleVal: stats.CPU}}, ts)

	points := make([]point, len(stats.PerCPU))
	for i, cpu := range stats.PerCPU {
		points[i] = point{
			intVal: cpu,
			attributes: map[string]string{
				"core": fmt.Sprintf("cpu%d", i),
			},
		}
	}
	sum(ms, "cpu.usage.percpu", "ns", points, ts)
}

func initMetric(ms pdata.MetricSlice, name, unit string) pdata.Metric {
	m := ms.AppendEmpty()
	m.SetName(fmt.Sprintf("container.%s", name))
	m.SetUnit(unit)
	return m
}

func sum(ilm pdata.MetricSlice, metricName string, unit string, points []point, ts pdata.Timestamp) {
	metric := initMetric(ilm, metricName, unit)

	metric.SetDataType(pdata.MetricDataTypeSum)
	sum := metric.Sum()
	sum.SetIsMonotonic(true)
	sum.SetAggregationTemporality(pdata.MetricAggregationTemporalityCumulative)

	dataPoints := sum.DataPoints()

	for _, pt := range points {
		dataPoint := dataPoints.AppendEmpty()
		dataPoint.SetTimestamp(ts)
		dataPoint.SetIntVal(int64(pt.intVal))
		setDataPointAttributes(dataPoint, pt.attributes)
	}
}

func gauge(ms pdata.MetricSlice, metricName string, unit string) pdata.NumberDataPointSlice {
	metric := initMetric(ms, metricName, unit)
	metric.SetDataType(pdata.MetricDataTypeGauge)

	gauge := metric.Gauge()
	return gauge.DataPoints()
}

func gaugeI(ms pdata.MetricSlice, metricName string, unit string, points []point, ts pdata.Timestamp) {
	dataPoints := gauge(ms, metricName, unit)
	for _, pt := range points {
		dataPoint := dataPoints.AppendEmpty()
		dataPoint.SetTimestamp(ts)
		dataPoint.SetIntVal(int64(pt.intVal))
		setDataPointAttributes(dataPoint, pt.attributes)
	}
}

func gaugeF(ms pdata.MetricSlice, metricName string, unit string, points []point, ts pdata.Timestamp) {
	dataPoints := gauge(ms, metricName, unit)
	for _, pt := range points {
		dataPoint := dataPoints.AppendEmpty()
		dataPoint.SetTimestamp(ts)
		dataPoint.SetDoubleVal(pt.doubleVal)
		setDataPointAttributes(dataPoint, pt.attributes)
	}
}

func setDataPointAttributes(dataPoint pdata.NumberDataPoint, attributes map[string]string) {
	for k, v := range attributes {
		dataPoint.Attributes().InsertString(k, v)
	}
}
<|endoftext|>