<commit_before>package collectors

import (
	"github.com/bosun-monitor/scollector/metadata"
	"github.com/bosun-monitor/scollector/opentsdb"
)

func init() {
	c := &IntervalCollector{
		F: c_iis_webservice,
	}
	c.init = wmiInit(c, func() interface{} { return &[]Win32_PerfRawData_W3SVC_WebService{} }, `WHERE Name <> '_Total'`, &iisQuery)
	collectors = append(collectors, c)
}

var (
	iisQuery string
)

func c_iis_webservice() (opentsdb.MultiDataPoint, error) {
	var dst []Win32_PerfRawData_W3SVC_WebService
	err := queryWmi(iisQuery, &dst)
	if err != nil {
		return nil, err
	}
	var md opentsdb.MultiDataPoint
	for _, v := range dst {
		Add(&md, "iis.bytes", v.BytesReceivedPersec, opentsdb.TagSet{"site": v.Name, "direction": "received"}, metadata.Counter, metadata.BytesPerSecond, descIISBytesReceivedPersec)
		Add(&md, "iis.bytes", v.BytesSentPersec, opentsdb.TagSet{"site": v.Name, "direction": "sent"}, metadata.Counter, metadata.BytesPerSecond, descIISBytesSentPersec)
		Add(&md, "iis.requests", v.CGIRequestsPersec, opentsdb.TagSet{"site": v.Name, "method": "cgi"}, metadata.Counter, metadata.PerSecond, descIISCGIRequestsPersec)
		Add(&md, "iis.connection_attempts", v.ConnectionAttemptsPersec, opentsdb.TagSet{"site": v.Name}, metadata.Counter, metadata.PerSecond, descIISConnectionAttemptsPersec)
		Add(&md, "iis.requests", v.CopyRequestsPersec, opentsdb.TagSet{"site": v.Name, "method": "copy"}, metadata.Counter, metadata.PerSecond, descIISCopyRequestsPersec)
		Add(&md, "iis.connections", v.CurrentConnections, opentsdb.TagSet{"site": v.Name}, metadata.Gauge, metadata.Count, descIISCurrentConnections)
		Add(&md, "iis.requests", v.DeleteRequestsPersec, opentsdb.TagSet{"site": v.Name, "method": "delete"}, metadata.Counter, metadata.PerSecond, descIISDeleteRequestsPersec)
		Add(&md, "iis.requests", v.GetRequestsPersec, opentsdb.TagSet{"site": v.Name, "method": "get"}, metadata.Counter, metadata.PerSecond, descIISGetRequestsPersec)
		Add(&md, "iis.requests", v.HeadRequestsPersec, opentsdb.TagSet{"site": v.Name, "method": "head"}, metadata.Counter, metadata.PerSecond, descIISHeadRequestsPersec)
		Add(&md, "iis.requests", v.ISAPIExtensionRequestsPersec, opentsdb.TagSet{"site": v.Name, "method": "isapi"}, metadata.Counter, metadata.PerSecond, descIISISAPIExtensionRequestsPersec)
		Add(&md, "iis.errors", v.LockedErrorsPersec, opentsdb.TagSet{"site": v.Name, "type": "locked"}, metadata.Counter, metadata.PerSecond, descIISLockedErrorsPersec)
		Add(&md, "iis.requests", v.LockRequestsPersec, opentsdb.TagSet{"site": v.Name, "method": "lock"}, metadata.Counter, metadata.PerSecond, descIISLockRequestsPersec)
		Add(&md, "iis.requests", v.MkcolRequestsPersec, opentsdb.TagSet{"site": v.Name, "method": "mkcol"}, metadata.Counter, metadata.PerSecond, descIISMkcolRequestsPersec)
		Add(&md, "iis.requests", v.MoveRequestsPersec, opentsdb.TagSet{"site": v.Name, "method": "move"}, metadata.Counter, metadata.PerSecond, descIISMoveRequestsPersec)
		Add(&md, "iis.errors", v.NotFoundErrorsPersec, opentsdb.TagSet{"site": v.Name, "type": "notfound"}, metadata.Counter, metadata.PerSecond, descIISNotFoundErrorsPersec)
		Add(&md, "iis.requests", v.OptionsRequestsPersec, opentsdb.TagSet{"site": v.Name, "method": "options"}, metadata.Counter, metadata.PerSecond, descIISOptionsRequestsPersec)
		Add(&md, "iis.requests", v.PostRequestsPersec, opentsdb.TagSet{"site": v.Name, "method": "post"}, metadata.Counter, metadata.PerSecond, descIISPostRequestsPersec)
		Add(&md, "iis.requests", v.PropfindRequestsPersec, opentsdb.TagSet{"site": v.Name, "method": "propfind"}, metadata.Counter, metadata.PerSecond, descIISPropfindRequestsPersec)
		Add(&md, "iis.requests", v.ProppatchRequestsPersec, opentsdb.TagSet{"site": v.Name, "method": "proppatch"}, metadata.Counter, metadata.PerSecond, descIISProppatchRequestsPersec)
		Add(&md, "iis.requests", v.PutRequestsPersec, opentsdb.TagSet{"site": v.Name, "method": "put"}, metadata.Counter, metadata.PerSecond, descIISPutRequestsPersec)
		Add(&md, "iis.requests", v.SearchRequestsPersec, opentsdb.TagSet{"site": v.Name, "method": "search"}, metadata.Counter, metadata.PerSecond, descIISSearchRequestsPersec)
		Add(&md, "iis.requests", v.TraceRequestsPersec, opentsdb.TagSet{"site": v.Name, "method": "trace"}, metadata.Counter, metadata.PerSecond, descIISTraceRequestsPersec)
		Add(&md, "iis.requests", v.UnlockRequestsPersec, opentsdb.TagSet{"site": v.Name, "method": "unlock"}, metadata.Counter, metadata.PerSecond, descIISUnlockRequestsPersec)
	}
	return md, nil
}

const (
	descIISBytesReceivedPersec          = "The rate that data bytes are received by the Web service."
	descIISBytesSentPersec              = "The rate data bytes are being sent by the Web service."
	descIISCGIRequestsPersec            = "The rate CGI requests are received by the Web service."
	descIISConnectionAttemptsPersec     = "The rate that connections to the Web service are being attempted."
	descIISCopyRequestsPersec           = "The rate HTTP requests using the COPY method are made.  Copy requests are used for copying files and directories."
	descIISCurrentConnections           = "The current number of connections established with the Web service."
	descIISDeleteRequestsPersec         = "The rate HTTP requests using the DELETE method are made.  Delete requests are generally used for file removals."
	descIISGetRequestsPersec            = "The rate HTTP requests using the GET method are made.  Get requests are the most common HTTP request."
	descIISHeadRequestsPersec           = "The rate HTTP requests using the HEAD method are made.  Head requests generally indicate a client is querying the state of a document they already have to see if it needs to be refreshed."
	descIISISAPIExtensionRequestsPersec = "The rate that ISAPI Extension requests are received by the Web service."
	descIISLockedErrorsPersec           = "The rate of errors due to requests that couldn't be satisfied by the server because the requested document was locked.  These are generally reported as an HTTP 423 error code to the client."
	descIISLockRequestsPersec           = "The rate HTTP requests using the LOCK method are made.  Lock requests are used to lock a file for one user so that only that user can modify the file."
	descIISMkcolRequestsPersec          = "The rate HTTP requests using the MKCOL method are made.  Mkcol requests are used to create directories on the server."
	descIISMoveRequestsPersec           = "The rate HTTP requests using the MOVE method are made.  Move requests are used for moving files and directories."
	descIISNotFoundErrorsPersec         = "The rate of errors due to requests that couldn't be satisfied by the server because the requested document could not be found.  These are generally reported as an HTTP 404 error code to the client."
	descIISOptionsRequestsPersec        = "The rate HTTP requests using the OPTIONS method are made."
	descIISPostRequestsPersec           = "The rate HTTP requests using the POST method are made."
	descIISPropfindRequestsPersec       = "The rate HTTP requests using the PROPFIND method are made.  Propfind requests retrieve property values on files and directories."
	descIISProppatchRequestsPersec      = "The rate HTTP requests using the PROPPATCH method are made.  Proppatch requests set property values on files and directories."
	descIISPutRequestsPersec            = "The rate HTTP requests using the PUT method are made."
	descIISSearchRequestsPersec         = "The rate HTTP requests using the SEARCH method are made.  Search requests are used to query the server to find resources that match a set of conditions provided by the client."
	descIISTraceRequestsPersec          = "The rate HTTP requests using the TRACE method are made.  Trace requests allow the client to see what is being received at the end of the request chain and use the information for diagnostic purposes."
	descIISUnlockRequestsPersec         = "The rate HTTP requests using the UNLOCK method are made.  Unlock requests are used to remove locks from files."
)

type Win32_PerfRawData_W3SVC_WebService struct {
	BytesReceivedPersec          uint64
	BytesSentPersec              uint64
	CGIRequestsPersec            uint32
	ConnectionAttemptsPersec     uint32
	CopyRequestsPersec           uint32
	CurrentConnections           uint32
	DeleteRequestsPersec         uint32
	GetRequestsPersec            uint32
	HeadRequestsPersec           uint32
	ISAPIExtensionRequestsPersec uint32
	LockRequestsPersec           uint32
	LockedErrorsPersec           uint32
	MkcolRequestsPersec          uint32
	MoveRequestsPersec           uint32
	Name                         string
	NotFoundErrorsPersec         uint32
	OptionsRequestsPersec        uint32
	PostRequestsPersec           uint32
	PropfindRequestsPersec       uint32
	ProppatchRequestsPersec      uint32
	PutRequestsPersec            uint32
	SearchRequestsPersec         uint32
	TraceRequestsPersec          uint32
	UnlockRequestsPersec         uint32
}
<commit_msg>cmd/scollector: Added application pool metrics from Win32_PerfRawData_APPPOOLCountersProvider_APPPOOLWAS<commit_after>package collectors

import (
	"github.com/StackExchange/wmi"
	"github.com/bosun-monitor/scollector/metadata"
	"github.com/bosun-monitor/scollector/opentsdb"
)

func init() {
	c := &IntervalCollector{
		F: c_iis_webservice,
	}
	c.init = wmiInit(c, func() interface{} { return &[]Win32_PerfRawData_W3SVC_WebService{} }, `WHERE Name <> '_Total'`, &iisQuery)
	collectors = append(collectors, c)
	collectors = append(collectors, &IntervalCollector{F: c_iis_apppool})
}

var (
	iisQuery string
)

func c_iis_webservice() (opentsdb.MultiDataPoint, error) {
	var dst []Win32_PerfRawData_W3SVC_WebService
	err := queryWmi(iisQuery, &dst)
	if err != nil {
		return nil, err
	}
	var md opentsdb.MultiDataPoint
	for _, v := range dst {
		Add(&md, "iis.bytes", v.BytesReceivedPersec, opentsdb.TagSet{"site": v.Name, "direction": "received"}, metadata.Counter, metadata.BytesPerSecond, descIISBytesReceivedPersec)
		Add(&md, "iis.bytes", v.BytesSentPersec, opentsdb.TagSet{"site": v.Name, "direction": "sent"}, metadata.Counter, metadata.BytesPerSecond, descIISBytesSentPersec)
		Add(&md, "iis.requests", v.CGIRequestsPersec, opentsdb.TagSet{"site": v.Name, "method": "cgi"}, metadata.Counter, metadata.PerSecond, descIISCGIRequestsPersec)
		Add(&md, "iis.connection_attempts", v.ConnectionAttemptsPersec, opentsdb.TagSet{"site": v.Name}, metadata.Counter, metadata.PerSecond, descIISConnectionAttemptsPersec)
		Add(&md, "iis.requests", v.CopyRequestsPersec, opentsdb.TagSet{"site": v.Name, "method": "copy"}, metadata.Counter, metadata.PerSecond, descIISCopyRequestsPersec)
		Add(&md, "iis.connections", v.CurrentConnections, opentsdb.TagSet{"site": v.Name}, metadata.Gauge, metadata.Count, descIISCurrentConnections)
		Add(&md, "iis.requests", v.DeleteRequestsPersec, opentsdb.TagSet{"site": v.Name, "method": "delete"}, metadata.Counter, metadata.PerSecond, descIISDeleteRequestsPersec)
		Add(&md, "iis.requests", v.GetRequestsPersec, opentsdb.TagSet{"site": v.Name, "method": "get"}, metadata.Counter, metadata.PerSecond, descIISGetRequestsPersec)
		Add(&md, "iis.requests", v.HeadRequestsPersec, opentsdb.TagSet{"site": v.Name, "method": "head"}, metadata.Counter, metadata.PerSecond, descIISHeadRequestsPersec)
		Add(&md, "iis.requests", v.ISAPIExtensionRequestsPersec, opentsdb.TagSet{"site": v.Name, "method": "isapi"}, metadata.Counter, metadata.PerSecond, descIISISAPIExtensionRequestsPersec)
		Add(&md, "iis.errors", v.LockedErrorsPersec, opentsdb.TagSet{"site": v.Name, "type": "locked"}, metadata.Counter, metadata.PerSecond, descIISLockedErrorsPersec)
		Add(&md, "iis.requests", v.LockRequestsPersec, opentsdb.TagSet{"site": v.Name, "method": "lock"}, metadata.Counter, metadata.PerSecond, descIISLockRequestsPersec)
		Add(&md, "iis.requests", v.MkcolRequestsPersec, opentsdb.TagSet{"site": v.Name, "method": "mkcol"}, metadata.Counter, metadata.PerSecond, descIISMkcolRequestsPersec)
		Add(&md, "iis.requests", v.MoveRequestsPersec, opentsdb.TagSet{"site": v.Name, "method": "move"}, metadata.Counter, metadata.PerSecond, descIISMoveRequestsPersec)
		Add(&md, "iis.errors", v.NotFoundErrorsPersec, opentsdb.TagSet{"site": v.Name, "type": "notfound"}, metadata.Counter, metadata.PerSecond, descIISNotFoundErrorsPersec)
		Add(&md, "iis.requests", v.OptionsRequestsPersec, opentsdb.TagSet{"site": v.Name, "method": "options"}, metadata.Counter, metadata.PerSecond, descIISOptionsRequestsPersec)
		Add(&md, "iis.requests", v.PostRequestsPersec, opentsdb.TagSet{"site": v.Name, "method": "post"}, metadata.Counter, metadata.PerSecond, descIISPostRequestsPersec)
		Add(&md, "iis.requests", v.PropfindRequestsPersec, opentsdb.TagSet{"site": v.Name, "method": "propfind"}, metadata.Counter, metadata.PerSecond, descIISPropfindRequestsPersec)
		Add(&md, "iis.requests", v.ProppatchRequestsPersec, opentsdb.TagSet{"site": v.Name, "method": "proppatch"}, metadata.Counter, metadata.PerSecond, descIISProppatchRequestsPersec)
		Add(&md, "iis.requests", v.PutRequestsPersec, opentsdb.TagSet{"site": v.Name, "method": "put"}, metadata.Counter, metadata.PerSecond, descIISPutRequestsPersec)
		Add(&md, "iis.requests", v.SearchRequestsPersec, opentsdb.TagSet{"site": v.Name, "method": "search"}, metadata.Counter, metadata.PerSecond, descIISSearchRequestsPersec)
		Add(&md, "iis.requests", v.TraceRequestsPersec, opentsdb.TagSet{"site": v.Name, "method": "trace"}, metadata.Counter, metadata.PerSecond, descIISTraceRequestsPersec)
		Add(&md, "iis.requests", v.UnlockRequestsPersec, opentsdb.TagSet{"site": v.Name, "method": "unlock"}, metadata.Counter, metadata.PerSecond, descIISUnlockRequestsPersec)
	}
	return md, nil
}

const (
	descIISBytesReceivedPersec          = "The rate that data bytes are received by the Web service."
	descIISBytesSentPersec              = "The rate data bytes are being sent by the Web service."
	descIISCGIRequestsPersec            = "The rate CGI requests are received by the Web service."
	descIISConnectionAttemptsPersec     = "The rate that connections to the Web service are being attempted."
	descIISCopyRequestsPersec           = "The rate HTTP requests using the COPY method are made.  Copy requests are used for copying files and directories."
	descIISCurrentConnections           = "The current number of connections established with the Web service."
	descIISDeleteRequestsPersec         = "The rate HTTP requests using the DELETE method are made.  Delete requests are generally used for file removals."
	descIISGetRequestsPersec            = "The rate HTTP requests using the GET method are made.  Get requests are the most common HTTP request."
	descIISHeadRequestsPersec           = "The rate HTTP requests using the HEAD method are made.  Head requests generally indicate a client is querying the state of a document they already have to see if it needs to be refreshed."
	descIISISAPIExtensionRequestsPersec = "The rate that ISAPI Extension requests are received by the Web service."
	descIISLockedErrorsPersec           = "The rate of errors due to requests that couldn't be satisfied by the server because the requested document was locked.  These are generally reported as an HTTP 423 error code to the client."
	descIISLockRequestsPersec           = "The rate HTTP requests using the LOCK method are made.  Lock requests are used to lock a file for one user so that only that user can modify the file."
	descIISMkcolRequestsPersec          = "The rate HTTP requests using the MKCOL method are made.  Mkcol requests are used to create directories on the server."
	descIISMoveRequestsPersec           = "The rate HTTP requests using the MOVE method are made.  Move requests are used for moving files and directories."
	descIISNotFoundErrorsPersec         = "The rate of errors due to requests that couldn't be satisfied by the server because the requested document could not be found.  These are generally reported as an HTTP 404 error code to the client."
	descIISOptionsRequestsPersec        = "The rate HTTP requests using the OPTIONS method are made."
	descIISPostRequestsPersec           = "The rate HTTP requests using the POST method are made."
	descIISPropfindRequestsPersec       = "The rate HTTP requests using the PROPFIND method are made.  Propfind requests retrieve property values on files and directories."
	descIISProppatchRequestsPersec      = "The rate HTTP requests using the PROPPATCH method are made.  Proppatch requests set property values on files and directories."
	descIISPutRequestsPersec            = "The rate HTTP requests using the PUT method are made."
	descIISSearchRequestsPersec         = "The rate HTTP requests using the SEARCH method are made.  Search requests are used to query the server to find resources that match a set of conditions provided by the client."
	descIISTraceRequestsPersec          = "The rate HTTP requests using the TRACE method are made.  Trace requests allow the client to see what is being received at the end of the request chain and use the information for diagnostic purposes."
	descIISUnlockRequestsPersec         = "The rate HTTP requests using the UNLOCK method are made.  Unlock requests are used to remove locks from files."
)

type Win32_PerfRawData_W3SVC_WebService struct {
	BytesReceivedPersec          uint64
	BytesSentPersec              uint64
	CGIRequestsPersec            uint32
	ConnectionAttemptsPersec     uint32
	CopyRequestsPersec           uint32
	CurrentConnections           uint32
	DeleteRequestsPersec         uint32
	GetRequestsPersec            uint32
	HeadRequestsPersec           uint32
	ISAPIExtensionRequestsPersec uint32
	LockRequestsPersec           uint32
	LockedErrorsPersec           uint32
	MkcolRequestsPersec          uint32
	MoveRequestsPersec           uint32
	Name                         string
	NotFoundErrorsPersec         uint32
	OptionsRequestsPersec        uint32
	PostRequestsPersec           uint32
	PropfindRequestsPersec       uint32
	ProppatchRequestsPersec      uint32
	PutRequestsPersec            uint32
	SearchRequestsPersec         uint32
	TraceRequestsPersec          uint32
	UnlockRequestsPersec         uint32
}

func c_iis_apppool() (opentsdb.MultiDataPoint, error) {
	var dst []Win32_PerfRawData_APPPOOLCountersProvider_APPPOOLWAS
	var q = wmi.CreateQuery(&dst, `WHERE Name <> '_Total'`)
	err := queryWmi(q, &dst)
	if err != nil {
		return nil, err
	}
	var md opentsdb.MultiDataPoint
	for _, v := range dst {
		tagsName := opentsdb.TagSet{"name": v.Name}
		uptime := (v.Timestamp_Object - v.CurrentApplicationPoolUptime) / v.Frequency_Object
		failtime := (v.Timestamp_Object - v.TimeSinceLastWorkerProcessFailure) / v.Frequency_Object
		Add(&md, "iis.apppool.state", v.CurrentApplicationPoolState, tagsName, metadata.Gauge, metadata.StatusCode, descIISAppPoolCurrentApplicationPoolState)
		Add(&md, "iis.apppool.uptime", uptime, tagsName, metadata.Gauge, metadata.Second, descIISAppPoolCurrentApplicationPoolUptime)
		Add(&md, "iis.apppool.time_since_failure", failtime, tagsName, metadata.Gauge, metadata.Second, descIISAppPoolTimeSinceLastWorkerProcessFailure)
		Add(&md, "iis.apppool.processes", v.CurrentWorkerProcesses, opentsdb.TagSet{"name": v.Name, "type": "current"}, metadata.Gauge, metadata.Count, descIISAppPoolCurrentWorkerProcesses)
		Add(&md, "iis.apppool.processes", v.MaximumWorkerProcesses, opentsdb.TagSet{"name": v.Name, "type": "maximum"}, metadata.Gauge, metadata.Count, descIISAppPoolMaximumWorkerProcesses)
		Add(&md, "iis.apppool.processes", v.RecentWorkerProcessFailures, opentsdb.TagSet{"name": v.Name, "type": "failed"}, metadata.Gauge, metadata.Count, descIISAppPoolRecentWorkerProcessFailures)
		Add(&md, "iis.apppool.events", v.TotalApplicationPoolRecycles, opentsdb.TagSet{"name": v.Name, "type": "recycled"}, metadata.Counter, metadata.Event, descIISAppPoolTotalApplicationPoolRecycles)
		Add(&md, "iis.apppool.events", v.TotalWorkerProcessesCreated, opentsdb.TagSet{"name": v.Name, "type": "created"}, metadata.Counter, metadata.Event, descIISAppPoolTotalWorkerProcessesCreated)
		Add(&md, "iis.apppool.events", v.TotalWorkerProcessFailures, opentsdb.TagSet{"name": v.Name, "type": "failed_crash"}, metadata.Counter, metadata.Event, descIISAppPoolTotalWorkerProcessFailures)
		Add(&md, "iis.apppool.events", v.TotalWorkerProcessPingFailures, opentsdb.TagSet{"name": v.Name, "type": "failed_ping"}, metadata.Counter, metadata.Event, descIISAppPoolTotalWorkerProcessPingFailures)
		Add(&md, "iis.apppool.events", v.TotalWorkerProcessShutdownFailures, opentsdb.TagSet{"name": v.Name, "type": "failed_shutdown"}, metadata.Counter, metadata.Event, descIISAppPoolTotalWorkerProcessShutdownFailures)
		Add(&md, "iis.apppool.events", v.TotalWorkerProcessStartupFailures, opentsdb.TagSet{"name": v.Name, "type": "failed_startup"}, metadata.Counter, metadata.Event, descIISAppPoolTotalWorkerProcessStartupFailures)
	}
	return md, nil
}

const (
	descIISAppPoolCurrentApplicationPoolState        = "The current status of the application pool (1 - Uninitialized, 2 - Initialized, 3 - Running, 4 - Disabling, 5 - Disabled, 6 - Shutdown Pending, 7 - Delete Pending)."
	descIISAppPoolCurrentApplicationPoolUptime       = "The length of time, in seconds, that the application pool has been running since it was started."
	descIISAppPoolCurrentWorkerProcesses             = "The current number of worker processes that are running in the application pool."
	descIISAppPoolMaximumWorkerProcesses             = "The maximum number of worker processes that have been created for the application pool since Windows Process Activation Service (WAS) started."
	descIISAppPoolRecentWorkerProcessFailures        = "The number of times that worker processes for the application pool failed during the rapid-fail protection interval."
	descIISAppPoolTimeSinceLastWorkerProcessFailure  = "The length of time, in seconds, since the last worker process failure occurred for the application pool."
	descIISAppPoolTotalApplicationPoolRecycles       = "The number of times that the application pool has been recycled since Windows Process Activation Service (WAS) started."
	descIISAppPoolTotalWorkerProcessesCreated        = "The number of worker processes created for the application pool since Windows Process Activation Service (WAS) started."
	descIISAppPoolTotalWorkerProcessFailures         = "The number of times that worker processes have crashed since the application pool was started."
	descIISAppPoolTotalWorkerProcessPingFailures     = "The number of times that Windows Process Activation Service (WAS) did not receive a response to ping messages sent to a worker process."
	descIISAppPoolTotalWorkerProcessShutdownFailures = "The number of times that Windows Process Activation Service (WAS) failed to shut down a worker process."
	descIISAppPoolTotalWorkerProcessStartupFailures  = "The number of times that Windows Process Activation Service (WAS) failed to start a worker process."
)

type Win32_PerfRawData_APPPOOLCountersProvider_APPPOOLWAS struct {
	CurrentApplicationPoolState        uint32
	CurrentApplicationPoolUptime       uint64
	CurrentWorkerProcesses             uint32
	Frequency_Object                   uint64
	MaximumWorkerProcesses             uint32
	Name                               string
	RecentWorkerProcessFailures        uint32
	TimeSinceLastWorkerProcessFailure  uint64
	Timestamp_Object                   uint64
	TotalApplicationPoolRecycles       uint32
	TotalWorkerProcessesCreated        uint32
	TotalWorkerProcessFailures         uint32
	TotalWorkerProcessPingFailures     uint32
	TotalWorkerProcessShutdownFailures uint32
	TotalWorkerProcessStartupFailures  uint32
}
<|endoftext|>


<commit_before>package collectors

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io"
	"os"
	"os/exec"
	"sync"
	"time"

	"github.com/StackExchange/scollector/opentsdb"
	"github.com/StackExchange/scollector/collect"
	"github.com/StackExchange/slog"
	"github.com/StackExchange/wmi"
)

var (
	wmiLock      sync.Mutex
	wmiReadLock  sync.Mutex
	wmiCount     = 0
	wmiCmd       *exec.Cmd
	wmiIn        io.WriteCloser
	wmiOut       io.ReadCloser
	wmiOutReader *bufio.Reader
)

func queryWmi(query string, dst interface{}) error {
	return queryWmiNamespace(query, dst, "")
}

func queryWmiNamespace(query string, dst interface{}, namespace string) (err error) {
	wmiLock.Lock()
	defer wmiLock.Unlock()
	collect.Add("wmi.queries", opentsdb.TagSet{}, 1)
	if wmiCount == 0 || wmiCmd == nil {
		collect.Add("wmi.exec", opentsdb.TagSet{}, 1)
		wmiCmd = exec.Command(os.Args[0], "-w")
		if wmiIn != nil {
			wmiIn.Close()
		}
		wmiIn, err = wmiCmd.StdinPipe()
		if err != nil {
			return
		}
		if wmiOut != nil {
			wmiOut.Close()
		}
		wmiOut, err = wmiCmd.StdoutPipe()
		if err != nil {
			return
		}
		wmiOutReader = bufio.NewReader(wmiOut)
		if err = wmiCmd.Start(); err != nil {
			wmiCmd = nil
			return
		}
	}
	wmiCount++
	defer func() {
		if wmiCount > 50 {
			if err := wmiCmd.Process.Kill(); err != nil {
				slog.Infoln(err)
			}
			wmiCmd = nil
			wmiCount = 0
		}
	}()

	q := wmi.WmiQuery{
		Query:     query,
		Namespace: namespace,
	}
	b, err := json.Marshal(&q)
	if err != nil {
		return err
	}
	fmt.Fprintln(wmiIn, string(b))
	done := make(chan error, 1)
	go func() {
		wmiReadLock.Lock()
		defer wmiReadLock.Unlock()
		b, err = wmiOutReader.ReadBytes('\n')
		if err != nil {
			done <- err
			return
		}
		done <- wmi.LoadJSON(b, dst)
	}()
	select {
	case err = <-done:
		// return
	case <-time.After(time.Second * 20):
		err = fmt.Errorf("wmi query timeout")
	}
	return
}
<commit_msg>cmd/scollector: Update wmi_windows.go<commit_after>package collectors

import (
	"bufio"
	"encoding/json"
	"fmt"
	"io"
	"os"
	"os/exec"
	"sync"
	"time"

	"github.com/StackExchange/scollector/collect"
	"github.com/StackExchange/slog"
	"github.com/StackExchange/wmi"
)

var (
	wmiLock      sync.Mutex
	wmiReadLock  sync.Mutex
	wmiCount     = 0
	wmiCmd       *exec.Cmd
	wmiIn        io.WriteCloser
	wmiOut       io.ReadCloser
	wmiOutReader *bufio.Reader
)

func queryWmi(query string, dst interface{}) error {
	return queryWmiNamespace(query, dst, "")
}

func queryWmiNamespace(query string, dst interface{}, namespace string) (err error) {
	wmiLock.Lock()
	defer wmiLock.Unlock()
	collect.Add("wmi.queries", nil, 1)
	if wmiCount == 0 || wmiCmd == nil {
		collect.Add("wmi.exec", nil, 1)
		wmiCmd = exec.Command(os.Args[0], "-w")
		if wmiIn != nil {
			wmiIn.Close()
		}
		wmiIn, err = wmiCmd.StdinPipe()
		if err != nil {
			return
		}
		if wmiOut != nil {
			wmiOut.Close()
		}
		wmiOut, err = wmiCmd.StdoutPipe()
		if err != nil {
			return
		}
		wmiOutReader = bufio.NewReader(wmiOut)
		if err = wmiCmd.Start(); err != nil {
			wmiCmd = nil
			return
		}
	}
	wmiCount++
	defer func() {
		if wmiCount > 50 {
			if err := wmiCmd.Process.Kill(); err != nil {
				slog.Infoln(err)
			}
			wmiCmd = nil
			wmiCount = 0
		}
	}()

	q := wmi.WmiQuery{
		Query:     query,
		Namespace: namespace,
	}
	b, err := json.Marshal(&q)
	if err != nil {
		return err
	}
	fmt.Fprintln(wmiIn, string(b))
	done := make(chan error, 1)
	go func() {
		wmiReadLock.Lock()
		defer wmiReadLock.Unlock()
		b, err = wmiOutReader.ReadBytes('\n')
		if err != nil {
			done <- err
			return
		}
		done <- wmi.LoadJSON(b, dst)
	}()
	select {
	case err = <-done:
		// return
	case <-time.After(time.Second * 20):
		err = fmt.Errorf("wmi query timeout")
	}
	return
}
<|endoftext|>


<commit_before>// Package log connects to a local or remote syslog server with fallback to
// stderr output.
package log

import (
	"fmt"
	"log"
	"log/syslog"
	"os"
	"runtime"
	"strings"
)

const (
	// LevelEmergency system is unusable.
	LevelEmergency Level = 0

	// LevelAlert should be corrected immediately.
	LevelAlert Level = 1

	// LevelCritical critical conditions.
	LevelCritical Level = 2

	// LevelError error conditions.
	LevelError Level = 3

	// LevelWarning may indicate that an error will occur if action is not taken.
	LevelWarning Level = 4

	// LevelNotice events that are unusual, but not error conditions.
	LevelNotice Level = 5

	// LevelInfo normal operational messages that require no action.
	LevelInfo Level = 6

	// LevelDebug information useful to developers for debugging the application.
	LevelDebug Level = 7
)

// Level defines the severity of an error. For example, if a custom error is
// created as bellow:
//
//    import "github.com/registrobr/gostk/log"
//
//    type ErrDatabaseFailure struct {
//    }
//
//    func (e ErrDatabaseFailure) Error() string {
//      return "database failure!"
//    }
//
//    func (e ErrDatabaseFailure) Level() log.Level {
//      return log.LevelEmergency
//    }
//
//  When used with the Logger type will be written in the syslog in the
//  corresponding log level.
type Level int

type leveler interface {
	Level() Level
}

// syslogWriter is useful to mock a low level syslog writer for unit tests.
type syslogWriter interface {
	Close() error
	Emerg(m string) (err error)
	Alert(m string) (err error)
	Crit(m string) (err error)
	Err(m string) (err error)
	Warning(m string) (err error)
	Notice(m string) (err error)
	Info(m string) (err error)
	Debug(m string) (err error)
}

var (
	remoteLogger syslogWriter
	localLogger  *log.Logger
)

func init() {
	localLogger = log.New(os.Stderr, "", log.LstdFlags)
}

// Connect initializes a connection with a remote syslog server using TCP
// (minimize package loss). All messages sent to this syslog server will be
// tagged with the name parameter.
func Connect(name, hostAndPort string) (err error) {
	remoteLogger, err = syslog.Dial("tcp", hostAndPort, syslog.LOG_INFO|syslog.LOG_LOCAL0, name)
	return
}

// ConnectLocal initializes a connection with a local syslog server.
func ConnectLocal(name string) (err error) {
	remoteLogger, err = syslog.New(syslog.LOG_INFO|syslog.LOG_LOCAL0, name)
	return
}

// Close disconnects the connection from the syslog server.
func Close() error {
	if remoteLogger == nil {
		return nil
	}

	err := remoteLogger.Close()
	if err == nil {
		remoteLogger = nil
	}
	return err
}

// Logger allows logging messages in all different level types. As it is an
// interface it can be replaced by mocks for test purposes.
type Logger interface {
	Emerg(m string)
	Emergf(m string, a ...interface{})
	Alert(m string)
	Alertf(m string, a ...interface{})
	Crit(m string)
	Critf(m string, a ...interface{})
	Error(e error)
	Errorf(m string, a ...interface{})
	Warning(m string)
	Warningf(m string, a ...interface{})
	Notice(m string)
	Noticef(m string, a ...interface{})
	Info(m string)
	Infof(m string, a ...interface{})
	Debug(m string)
	Debugf(m string, a ...interface{})
}

type logger struct {
	identifier string
}

// NewLogger returns a internal instance of the Logger type tagging an
// identifier to every message logged. This identifier is useful to group many
// messages to one related transaction id.
var NewLogger = func(id string) Logger {
	return logger{"[" + id + "] "}
}

func (l logger) Emerg(m string) {
	if remoteLogger == nil {
		localLogWithSourceInfo(l.identifier, m)
	} else {
		logWithSourceInfo(remoteLogger.Emerg, l.identifier, m)
	}
}

func (l logger) Emergf(m string, a ...interface{}) {
	if remoteLogger == nil {
		localLogWithSourceInfof(l.identifier, m, a...)
	} else {
		logWithSourceInfof(remoteLogger.Emerg, l.identifier, m, a...)
	}
}

func (l logger) Alert(m string) {
	if remoteLogger == nil {
		localLogWithSourceInfo(l.identifier, m)
	} else {
		logWithSourceInfo(remoteLogger.Alert, l.identifier, m)
	}
}

func (l logger) Alertf(m string, a ...interface{}) {
	if remoteLogger == nil {
		localLogWithSourceInfof(l.identifier, m, a...)
	} else {
		logWithSourceInfof(remoteLogger.Alert, l.identifier, m, a...)
	}
}

func (l logger) Crit(m string) {
	if remoteLogger == nil {
		localLogWithSourceInfo(l.identifier, m)
	} else {
		logWithSourceInfo(remoteLogger.Crit, l.identifier, m)
	}
}

func (l logger) Critf(m string, a ...interface{}) {
	if remoteLogger == nil {
		localLogWithSourceInfof(l.identifier, m, a...)
	} else {
		logWithSourceInfof(remoteLogger.Crit, l.identifier, m, a...)
	}
}

// Error converts an Go error into an error message. The responsibility of
// knowing the file and line where the error occurred is from the Error()
// function of the specific error.
func (l logger) Error(e error) {
	if e == nil {
		return
	}

	msg := l.identifier + e.Error()
	if remoteLogger == nil {
		localLogger.Println(msg)
		return
	}

	var err error

	if levelError, ok := e.(leveler); ok {
		switch levelError.Level() {
		case LevelEmergency:
			err = remoteLogger.Emerg(msg)
		case LevelAlert:
			err = remoteLogger.Alert(msg)
		case LevelCritical:
			err = remoteLogger.Crit(msg)
		case LevelError:
			err = remoteLogger.Err(msg)
		case LevelWarning:
			err = remoteLogger.Warning(msg)
		case LevelNotice:
			err = remoteLogger.Notice(msg)
		case LevelInfo:
			err = remoteLogger.Info(msg)
		case LevelDebug:
			err = remoteLogger.Debug(msg)
		default:
			l.Warningf("Wrong error level: %d", levelError.Level())
			err = remoteLogger.Err(msg)
		}
	} else {
		err = remoteLogger.Err(msg)
	}

	if err != nil {
		localLogger.Println("Error writing to syslog. Details:", err)
		localLogger.Println(msg)
	}
}

func (l logger) Errorf(m string, a ...interface{}) {
	if remoteLogger == nil {
		localLogWithSourceInfof(l.identifier, m, a...)
	} else {
		logWithSourceInfof(remoteLogger.Err, l.identifier, m, a...)
	}
}

func (l logger) Warning(m string) {
	if remoteLogger == nil {
		localLogWithSourceInfo(l.identifier, m)
	} else {
		logWithSourceInfo(remoteLogger.Warning, l.identifier, m)
	}
}

func (l logger) Warningf(m string, a ...interface{}) {
	if remoteLogger == nil {
		localLogWithSourceInfof(l.identifier, m, a...)
	} else {
		logWithSourceInfof(remoteLogger.Warning, l.identifier, m, a...)
	}
}

func (l logger) Notice(m string) {
	if remoteLogger == nil {
		localLogWithSourceInfo(l.identifier, m)
	} else {
		logWithSourceInfo(remoteLogger.Notice, l.identifier, m)
	}
}

func (l logger) Noticef(m string, a ...interface{}) {
	if remoteLogger == nil {
		localLogWithSourceInfof(l.identifier, m, a...)
	} else {
		logWithSourceInfof(remoteLogger.Notice, l.identifier, m, a...)
	}
}

func (l logger) Info(m string) {
	if remoteLogger == nil {
		localLogWithSourceInfo(l.identifier, m)
	} else {
		logWithSourceInfo(remoteLogger.Info, l.identifier, m)
	}
}

func (l logger) Infof(m string, a ...interface{}) {
	if remoteLogger == nil {
		localLogWithSourceInfof(l.identifier, m, a...)
	} else {
		logWithSourceInfof(remoteLogger.Info, l.identifier, m, a...)
	}
}

func (l logger) Debug(m string) {
	if remoteLogger == nil {
		localLogWithSourceInfo(l.identifier, m)
	} else {
		logWithSourceInfo(remoteLogger.Debug, l.identifier, m)
	}
}

func (l logger) Debugf(m string, a ...interface{}) {
	if remoteLogger == nil {
		localLogWithSourceInfof(l.identifier, m, a...)
	} else {
		logWithSourceInfof(remoteLogger.Debug, l.identifier, m, a...)
	}
}

// Emerg log an emergency message
func Emerg(m string) {
	l := NewLogger("")
	l.Emerg(m)
}

// Emergf log an emergency message with arguments
func Emergf(m string, a ...interface{}) {
	l := NewLogger("")
	l.Emergf(m, a...)
}

// Alert log an emergency message
func Alert(m string) {
	l := NewLogger("")
	l.Alert(m)
}

// Alertf log an emergency message with arguments
func Alertf(m string, a ...interface{}) {
	l := NewLogger("")
	l.Alertf(m, a...)
}

// Crit log an emergency message
func Crit(m string) {
	l := NewLogger("")
	l.Crit(m)
}

// Critf log an emergency message with arguments
func Critf(m string, a ...interface{}) {
	l := NewLogger("")
	l.Critf(m, a...)
}

// Error log an emergency message
func Error(err error) {
	l := NewLogger("")
	l.Error(err)
}

// Errorf log an emergency message with arguments
func Errorf(m string, a ...interface{}) {
	l := NewLogger("")
	l.Errorf(m, a...)
}

// Warning log an emergency message
func Warning(m string) {
	l := NewLogger("")
	l.Warning(m)
}

// Warningf log an emergency message with arguments
func Warningf(m string, a ...interface{}) {
	l := NewLogger("")
	l.Warningf(m, a...)
}

// Notice log an emergency message
func Notice(m string) {
	l := NewLogger("")
	l.Notice(m)
}

// Noticef log an emergency message with arguments
func Noticef(m string, a ...interface{}) {
	l := NewLogger("")
	l.Noticef(m, a...)
}

// Info log an emergency message
func Info(m string) {
	l := NewLogger("")
	l.Info(m)
}

// Infof log an emergency message with arguments
func Infof(m string, a ...interface{}) {
	l := NewLogger("")
	l.Infof(m, a...)
}

// Debug log an emergency message
func Debug(m string) {
	l := NewLogger("")
	l.Debug(m)
}

// Debugf log an emergency message with arguments
func Debugf(m string, a ...interface{}) {
	l := NewLogger("")
	l.Debugf(m, a...)
}

func localLogWithSourceInfo(prefix, message string) {
	_, file, line, _ := runtime.Caller(2)
	file = relevantPath(file, 3)
	lines := strings.Split(message, "\n")

	for _, item := range lines {
		if item == "" {
			continue
		}

		msg := fmt.Sprintf("%s%s:%d: %s", prefix, file, line, item)
		localLogger.Println(msg)
	}
}

func localLogWithSourceInfof(prefix, message string, a ...interface{}) {
	_, file, line, _ := runtime.Caller(2)
	file = relevantPath(file, 3)
	message = fmt.Sprintf(message, a...)
	lines := strings.Split(message, "\n")

	for _, item := range lines {
		if item == "" {
			continue
		}

		msg := fmt.Sprintf("%s%s:%d: %s", prefix, file, line, item)
		localLogger.Println(msg)
	}
}

func logWithSourceInfo(f func(string) error, prefix, message string) {
	_, file, line, _ := runtime.Caller(2)
	file = relevantPath(file, 3)
	lines := strings.Split(message, "\n")

	for _, item := range lines {
		if item == "" {
			continue
		}

		msg := fmt.Sprintf("%s%s:%d: %s", prefix, file, line, item)

		if err := f(msg); err != nil {
			localLogger.Println("Error writing to syslog. Details:", err)
			localLogger.Println(msg)
		}
	}
}

func logWithSourceInfof(f func(string) error, prefix, message string, a ...interface{}) {
	_, file, line, _ := runtime.Caller(2)
	file = relevantPath(file, 3)
	message = fmt.Sprintf(message, a...)
	lines := strings.Split(message, "\n")

	for _, item := range lines {
		if item == "" {
			continue
		}

		msg := fmt.Sprintf("%s%s:%d: %s", prefix, file, line, item)

		if err := f(msg); err != nil {
			localLogger.Println("Error writing to syslog. Details:", err)
			localLogger.Println(msg)
		}
	}
}

func relevantPath(path string, n int) string {
	tokens := strings.Split(path, "/")
	total := len(tokens)

	if n >= total {
		return path
	}

	var result string
	for i := total - n; i < total; i++ {
		result += tokens[i] + "/"
	}
	return strings.TrimSuffix(result, "/")
}
<commit_msg>Refactory code removing local log helper functions<commit_after>// Package log connects to a local or remote syslog server with fallback to
// stderr output.
package log

import (
	"fmt"
	"log"
	"log/syslog"
	"os"
	"runtime"
	"strings"
)

// pathDeep defines the number of folders that are visible when logging a
// message with the logging location.
const pathDeep = 3

const (
	// LevelEmergency system is unusable.
	LevelEmergency Level = 0

	// LevelAlert should be corrected immediately.
	LevelAlert Level = 1

	// LevelCritical critical conditions.
	LevelCritical Level = 2

	// LevelError error conditions.
	LevelError Level = 3

	// LevelWarning may indicate that an error will occur if action is not taken.
	LevelWarning Level = 4

	// LevelNotice events that are unusual, but not error conditions.
	LevelNotice Level = 5

	// LevelInfo normal operational messages that require no action.
	LevelInfo Level = 6

	// LevelDebug information useful to developers for debugging the application.
	LevelDebug Level = 7
)

// Level defines the severity of an error. For example, if a custom error is
// created as bellow:
//
//    import "github.com/registrobr/gostk/log"
//
//    type ErrDatabaseFailure struct {
//    }
//
//    func (e ErrDatabaseFailure) Error() string {
//      return "database failure!"
//    }
//
//    func (e ErrDatabaseFailure) Level() log.Level {
//      return log.LevelEmergency
//    }
//
//  When used with the Logger type will be written in the syslog in the
//  corresponding log level.
type Level int

type leveler interface {
	Level() Level
}

// syslogWriter is useful to mock a low level syslog writer for unit tests.
type syslogWriter interface {
	Close() error
	Emerg(m string) (err error)
	Alert(m string) (err error)
	Crit(m string) (err error)
	Err(m string) (err error)
	Warning(m string) (err error)
	Notice(m string) (err error)
	Info(m string) (err error)
	Debug(m string) (err error)
}

var (
	remoteLogger syslogWriter
	localLogger  *log.Logger
)

func init() {
	localLogger = log.New(os.Stderr, "", log.LstdFlags)
}

// Connect initializes a connection with a remote syslog server using TCP
// (minimize package loss). All messages sent to this syslog server will be
// tagged with the name parameter.
func Connect(name, hostAndPort string) (err error) {
	remoteLogger, err = syslog.Dial("tcp", hostAndPort, syslog.LOG_INFO|syslog.LOG_LOCAL0, name)
	return
}

// ConnectLocal initializes a connection with a local syslog server.
func ConnectLocal(name string) (err error) {
	remoteLogger, err = syslog.New(syslog.LOG_INFO|syslog.LOG_LOCAL0, name)
	return
}

// Close disconnects the connection from the syslog server.
func Close() error {
	if remoteLogger == nil {
		return nil
	}

	err := remoteLogger.Close()
	if err == nil {
		remoteLogger = nil
	}
	return err
}

// Logger allows logging messages in all different level types. As it is an
// interface it can be replaced by mocks for test purposes.
type Logger interface {
	Emerg(m string)
	Emergf(m string, a ...interface{})
	Alert(m string)
	Alertf(m string, a ...interface{})
	Crit(m string)
	Critf(m string, a ...interface{})
	Error(e error)
	Errorf(m string, a ...interface{})
	Warning(m string)
	Warningf(m string, a ...interface{})
	Notice(m string)
	Noticef(m string, a ...interface{})
	Info(m string)
	Infof(m string, a ...interface{})
	Debug(m string)
	Debugf(m string, a ...interface{})
}

type logger struct {
	identifier string
}

// NewLogger returns a internal instance of the Logger type tagging an
// identifier to every message logged. This identifier is useful to group many
// messages to one related transaction id.
var NewLogger = func(id string) Logger {
	return logger{"[" + id + "] "}
}

func (l logger) Emerg(m string) {
	var f logFunc
	if remoteLogger != nil {
		f = remoteLogger.Emerg
	}
	logWithSourceInfo(f, l.identifier, m)
}

func (l logger) Emergf(m string, a ...interface{}) {
	var f logFunc
	if remoteLogger != nil {
		f = remoteLogger.Emerg
	}
	logWithSourceInfof(f, l.identifier, m, a...)
}

func (l logger) Alert(m string) {
	var f logFunc
	if remoteLogger != nil {
		f = remoteLogger.Alert
	}
	logWithSourceInfo(f, l.identifier, m)
}

func (l logger) Alertf(m string, a ...interface{}) {
	var f logFunc
	if remoteLogger != nil {
		f = remoteLogger.Alert
	}
	logWithSourceInfof(f, l.identifier, m, a...)
}

func (l logger) Crit(m string) {
	var f logFunc
	if remoteLogger != nil {
		f = remoteLogger.Crit
	}
	logWithSourceInfo(f, l.identifier, m)
}

func (l logger) Critf(m string, a ...interface{}) {
	var f logFunc
	if remoteLogger != nil {
		f = remoteLogger.Crit
	}
	logWithSourceInfof(f, l.identifier, m, a...)
}

// Error converts an Go error into an error message. The responsibility of
// knowing the file and line where the error occurred is from the Error()
// function of the specific error.
func (l logger) Error(e error) {
	if e == nil {
		return
	}

	msg := l.identifier + e.Error()
	if remoteLogger == nil {
		localLogger.Println(msg)
		return
	}

	var err error

	if levelError, ok := e.(leveler); ok {
		switch levelError.Level() {
		case LevelEmergency:
			err = remoteLogger.Emerg(msg)
		case LevelAlert:
			err = remoteLogger.Alert(msg)
		case LevelCritical:
			err = remoteLogger.Crit(msg)
		case LevelError:
			err = remoteLogger.Err(msg)
		case LevelWarning:
			err = remoteLogger.Warning(msg)
		case LevelNotice:
			err = remoteLogger.Notice(msg)
		case LevelInfo:
			err = remoteLogger.Info(msg)
		case LevelDebug:
			err = remoteLogger.Debug(msg)
		default:
			l.Warningf("Wrong error level: %d", levelError.Level())
			err = remoteLogger.Err(msg)
		}
	} else {
		err = remoteLogger.Err(msg)
	}

	if err != nil {
		localLogger.Println("Error writing to syslog. Details:", err)
		localLogger.Println(msg)
	}
}

func (l logger) Errorf(m string, a ...interface{}) {
	var f logFunc
	if remoteLogger != nil {
		f = remoteLogger.Err
	}
	logWithSourceInfof(f, l.identifier, m, a...)
}

func (l logger) Warning(m string) {
	var f logFunc
	if remoteLogger != nil {
		f = remoteLogger.Warning
	}
	logWithSourceInfo(f, l.identifier, m)
}

func (l logger) Warningf(m string, a ...interface{}) {
	var f logFunc
	if remoteLogger != nil {
		f = remoteLogger.Warning
	}
	logWithSourceInfof(f, l.identifier, m, a...)
}

func (l logger) Notice(m string) {
	var f logFunc
	if remoteLogger != nil {
		f = remoteLogger.Notice
	}
	logWithSourceInfo(f, l.identifier, m)
}

func (l logger) Noticef(m string, a ...interface{}) {
	var f logFunc
	if remoteLogger != nil {
		f = remoteLogger.Notice
	}
	logWithSourceInfof(f, l.identifier, m, a...)
}

func (l logger) Info(m string) {
	var f logFunc
	if remoteLogger != nil {
		f = remoteLogger.Info
	}
	logWithSourceInfo(f, l.identifier, m)
}

func (l logger) Infof(m string, a ...interface{}) {
	var f logFunc
	if remoteLogger != nil {
		f = remoteLogger.Info
	}
	logWithSourceInfof(f, l.identifier, m, a...)
}

func (l logger) Debug(m string) {
	var f logFunc
	if remoteLogger != nil {
		f = remoteLogger.Debug
	}
	logWithSourceInfo(f, l.identifier, m)
}

func (l logger) Debugf(m string, a ...interface{}) {
	var f logFunc
	if remoteLogger != nil {
		f = remoteLogger.Debug
	}
	logWithSourceInfof(f, l.identifier, m, a...)
}

// Emerg log an emergency message
func Emerg(m string) {
	l := NewLogger("")
	l.Emerg(m)
}

// Emergf log an emergency message with arguments
func Emergf(m string, a ...interface{}) {
	l := NewLogger("")
	l.Emergf(m, a...)
}

// Alert log an emergency message
func Alert(m string) {
	l := NewLogger("")
	l.Alert(m)
}

// Alertf log an emergency message with arguments
func Alertf(m string, a ...interface{}) {
	l := NewLogger("")
	l.Alertf(m, a...)
}

// Crit log an emergency message
func Crit(m string) {
	l := NewLogger("")
	l.Crit(m)
}

// Critf log an emergency message with arguments
func Critf(m string, a ...interface{}) {
	l := NewLogger("")
	l.Critf(m, a...)
}

// Error log an emergency message
func Error(err error) {
	l := NewLogger("")
	l.Error(err)
}

// Errorf log an emergency message with arguments
func Errorf(m string, a ...interface{}) {
	l := NewLogger("")
	l.Errorf(m, a...)
}

// Warning log an emergency message
func Warning(m string) {
	l := NewLogger("")
	l.Warning(m)
}

// Warningf log an emergency message with arguments
func Warningf(m string, a ...interface{}) {
	l := NewLogger("")
	l.Warningf(m, a...)
}

// Notice log an emergency message
func Notice(m string) {
	l := NewLogger("")
	l.Notice(m)
}

// Noticef log an emergency message with arguments
func Noticef(m string, a ...interface{}) {
	l := NewLogger("")
	l.Noticef(m, a...)
}

// Info log an emergency message
func Info(m string) {
	l := NewLogger("")
	l.Info(m)
}

// Infof log an emergency message with arguments
func Infof(m string, a ...interface{}) {
	l := NewLogger("")
	l.Infof(m, a...)
}

// Debug log an emergency message
func Debug(m string) {
	l := NewLogger("")
	l.Debug(m)
}

// Debugf log an emergency message with arguments
func Debugf(m string, a ...interface{}) {
	l := NewLogger("")
	l.Debugf(m, a...)
}

type logFunc func(string) error

func logWithSourceInfo(f logFunc, prefix, message string) {
	_, file, line, _ := runtime.Caller(2)
	file = relevantPath(file, pathDeep)
	lines := strings.Split(message, "\n")

	for _, item := range lines {
		if item == "" {
			continue
		}

		msg := fmt.Sprintf("%s%s:%d: %s", prefix, file, line, item)

		if f == nil {
			localLogger.Println(msg)

		} else if err := f(msg); err != nil {
			localLogger.Println("Error writing to syslog. Details:", err)
			localLogger.Println(msg)
		}
	}
}

func logWithSourceInfof(f logFunc, prefix, message string, a ...interface{}) {
	_, file, line, _ := runtime.Caller(2)
	file = relevantPath(file, pathDeep)
	message = fmt.Sprintf(message, a...)
	lines := strings.Split(message, "\n")

	for _, item := range lines {
		if item == "" {
			continue
		}

		msg := fmt.Sprintf("%s%s:%d: %s", prefix, file, line, item)

		if f == nil {
			localLogger.Println(msg)

		} else if err := f(msg); err != nil {
			localLogger.Println("Error writing to syslog. Details:", err)
			localLogger.Println(msg)
		}
	}
}

func relevantPath(path string, n int) string {
	tokens := strings.Split(path, "/")
	total := len(tokens)

	if n >= total {
		return path
	}

	var result string
	for i := total - n; i < total; i++ {
		result += tokens[i] + "/"
	}
	return strings.TrimSuffix(result, "/")
}
<|endoftext|>


<commit_before>package log

import (
	"bitbucket.org/mundipagg/boletoapi/config"
	"github.com/mundipagg/goseq"
)

var logger *goseq.Logger

//Install instala o "servico" de log do SEQ
func Install() error {
	_logger, err := goseq.GetLogger(config.Get().SEQUrl, config.Get().SEQAPIKey)
	if err != nil {
		return err
	}
	logger = _logger
	return nil
}

//Info loga mensagem do level INFO
func Info(msg string) {
	logger.Information(msg, goseq.NewProperties())
}

//Warn loga mensagem do leve Warning
func Warn(msg string) {
	logger.Warning(msg, goseq.NewProperties())
}

//Fatal loga mensagem do leve fatal
func Fatal(msg string) {
	logger.Fatal(msg, goseq.NewProperties())
}

//Close fecha a conexao com o SEQ
func Close() {
	logger.Close()
}
<commit_msg>:speaker: Adiciona propriedade padrão no log<commit_after>package log

import (
	"bitbucket.org/mundipagg/boletoapi/config"
	"github.com/mundipagg/goseq"
)

var logger *goseq.Logger

//Install instala o "servico" de log do SEQ
func Install() error {
	_logger, err := goseq.GetLogger(config.Get().SEQUrl, config.Get().SEQAPIKey)
	if err != nil {
		return err
	}
	_logger.SetDefaultProperties(map[string]string{
		"Application": "BoletoOnline",
	})
	logger = _logger
	return nil
}

//Info loga mensagem do level INFO
func Info(msg string) {
	logger.Information(msg, goseq.NewProperties())
}

//Warn loga mensagem do leve Warning
func Warn(msg string) {
	logger.Warning(msg, goseq.NewProperties())
}

//Fatal loga mensagem do leve fatal
func Fatal(msg string) {
	logger.Fatal(msg, goseq.NewProperties())
}

//Close fecha a conexao com o SEQ
func Close() {
	logger.Close()
}
<|endoftext|>


<commit_before>package main

import (
	"bufio"
	"errors"
	"flag"
	"fmt"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"
)

const (
	GO_1_0 = iota
	GO_1_1
)
const ()

var (
	regexes = map[int]*regexp.Regexp{
		GO_1_0: regexp.MustCompile(`gc(\d+)\((\d+)\):\s(\d+)\+(\d+)\+(\d+)\s\w+\s(\d+)\s->\s(\d+)\s\w+\s(\d+)\s->\s(\d+)\s\((\d+)-(\d+)\)\sobjects\s(\d+)\shandoff`),
		GO_1_1: regexp.MustCompile(`gc(\d+)\((\d+)\):\s(\d+)\+(\d+)\+(\d+)\s\w+,\s(\d+)\s->\s(\d+)\s\w+\s(\d+)\s->\s(\d+)\s\((\d+)-(\d+)\)\sobjects,\s(\d+)\((\d+)\)\shandoff,\s(\d+)\((\d+)\)\ssteal,\s(\d+)\/(\d+)\/(\d+)\syields`),
	}
	header = map[int]string{
		GO_1_0: "numgc,nproc,mark,sweep,cleanup,heap0,heap1,obj0,obj1,nmalloc,nfree,nhandoff",
		GO_1_1: "numgc,nproc,mark,sweep,cleanup,heap0,heap1,obj0,obj1,nmalloc,nfree,nhandoff,nhandoffcnt,nsteal,nstealcnt,nprocyield,nosyield,nsleep",
	}

	inputFile  = flag.String("i", "", "The input file (default: Stdin)")
	outputFile = flag.String("o", "", "The output file (default: Stdout)")
	timestamp  = flag.Bool("t", false, "Add timestamp at line head(Stdin input only)")
	help       = flag.Bool("h", false, "Show Usage")
	isStdin    = false
	isStdout   = false
)

func detectLogVersion(line string) int {
	for version, regexp := range regexes {
		if regexp.MatchString(line) {
			return version
		}
	}

	return -1
}

func convert(input string, version int) (output string, err error) {
	defer func() {
		if e := recover(); e != nil {
			err = errors.New(fmt.Sprintf("unmatched uint string: %s => %s", input, e))
		}
	}()

	if matched := regexes[version].FindStringSubmatch(input); matched == nil {
		err = errors.New(fmt.Sprintf("unmatched string: %s", input))
	} else {
		output = strings.Join(matched[1:], ",")
	}
	return
}

func run(in, out *os.File) {
	reader := bufio.NewReader(in)
	writer := bufio.NewWriter(out)

	currentLogVersion := -1
	for {

		if line, err := reader.ReadString('\n'); err != nil {
			break
		} else {
			if currentLogVersion == -1 {
				if version := detectLogVersion(line); version != -1 {
					currentLogVersion = version
					writeHeader(writer, currentLogVersion)
				} else {
					continue
				}
			}

			if output, err := convert(line, currentLogVersion); err == nil {
				writeBody(writer, output)
			}
		}

	}
	writer.Flush()
}

func writeHeader(writer *bufio.Writer, version int) {
	prefix := ""
	if *timestamp && isStdin {
		prefix = "unixtime,"
	}
	writer.WriteString(prefix + header[version] + "\n")
}

func writeBody(writer *bufio.Writer, output string) {
	prefix := ""
	if *timestamp && isStdin {
		prefix = fmtFrac(time.Now(), 6) + ","
	}

	writer.WriteString(prefix + output + "\n")
	if isStdout {
		writer.Flush()
	}
}

func fmtFrac(t time.Time, prec int) string {
	unixNano := t.UnixNano()
	fmtStr := "%." + strconv.Itoa(prec) + "f"
	return fmt.Sprintf(fmtStr, float64(unixNano)/10e8)
}

func main() {
	flag.Parse()

	flag.Usage = func() {
		fmt.Println("Usage1: log2csv -i gc.log -o gc.csv")
		fmt.Println("Usage2: GOGCTRACE=1 your-go-program 2>&1 | log2csv -o gc.csv")
		flag.PrintDefaults()
	}

	if *help {
		flag.Usage()
		os.Exit(0)
	}

	var in, out *os.File

	if *inputFile != "" {
		var err error
		in, err = os.Open(*inputFile)
		if err != nil {
			fmt.Fprintf(os.Stderr, "cannot open input file: %s", err)
			os.Exit(1)
		}
		defer in.Close()
	} else {
		in = os.Stdin
		isStdin = true
	}

	if *outputFile != "" {
		var err error
		out, err = os.OpenFile(*outputFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
		if err != nil {
			fmt.Fprintf(os.Stderr, "cannot create output file: %s", err)
			os.Exit(1)
		}
		defer out.Close()
	} else {
		out = os.Stdout
		isStdout = true
	}

	run(in, out)
}
<commit_msg>print out unfiltered content from stdin and force to use output file<commit_after>package main

import (
	"bufio"
	"errors"
	"flag"
	"fmt"
	"os"
	"regexp"
	"strconv"
	"strings"
	"time"
)

const (
	GO_1_0 = iota
	GO_1_1
)
const ()

var (
	regexes = map[int]*regexp.Regexp{
		GO_1_0: regexp.MustCompile(`gc(\d+)\((\d+)\):\s(\d+)\+(\d+)\+(\d+)\s\w+\s(\d+)\s->\s(\d+)\s\w+\s(\d+)\s->\s(\d+)\s\((\d+)-(\d+)\)\sobjects\s(\d+)\shandoff`),
		GO_1_1: regexp.MustCompile(`gc(\d+)\((\d+)\):\s(\d+)\+(\d+)\+(\d+)\s\w+,\s(\d+)\s->\s(\d+)\s\w+\s(\d+)\s->\s(\d+)\s\((\d+)-(\d+)\)\sobjects,\s(\d+)\((\d+)\)\shandoff,\s(\d+)\((\d+)\)\ssteal,\s(\d+)\/(\d+)\/(\d+)\syields`),
	}
	header = map[int]string{
		GO_1_0: "numgc,nproc,mark,sweep,cleanup,heap0,heap1,obj0,obj1,nmalloc,nfree,nhandoff",
		GO_1_1: "numgc,nproc,mark,sweep,cleanup,heap0,heap1,obj0,obj1,nmalloc,nfree,nhandoff,nhandoffcnt,nsteal,nstealcnt,nprocyield,nosyield,nsleep",
	}

	inputFile  = flag.String("i", "", "The input file (default: Stdin)")
	outputFile = flag.String("o", "", "The output file")
	timestamp  = flag.Bool("t", false, "Add timestamp at line head(Stdin input only)")
	help       = flag.Bool("h", false, "Show Usage")
	isStdin    = false
)

func detectLogVersion(line string) int {
	for version, regexp := range regexes {
		if regexp.MatchString(line) {
			return version
		}
	}

	return -1
}

func convert(input string, version int) (output string, err error) {
	defer func() {
		if e := recover(); e != nil {
			err = errors.New(fmt.Sprintf("unmatched uint string: %s => %s", input, e))
		}
	}()

	if matched := regexes[version].FindStringSubmatch(input); matched == nil {
		err = errors.New(fmt.Sprintf("unmatched string: %s", input))
	} else {
		output = strings.Join(matched[1:], ",")
	}
	return
}

func run(in, out *os.File) {
	reader := bufio.NewReader(in)
	writer := bufio.NewWriter(out)

	currentLogVersion := -1
	for {

		filtered := false
		if line, err := reader.ReadString('\n'); err != nil {
			break
		} else {
			if currentLogVersion == -1 {
				if version := detectLogVersion(line); version != -1 {
					currentLogVersion = version
					writeHeader(writer, currentLogVersion)
				}
			}

			if currentLogVersion != -1 {
				if output, err := convert(line, currentLogVersion); err == nil {
					writeBody(writer, output)
					filtered = true
				}
			}

			if isStdin && filtered == false {
				fmt.Print(line)
			}
		}

	}
	writer.Flush()
}

func writeHeader(writer *bufio.Writer, version int) {
	prefix := ""
	if isStdin && *timestamp {
		prefix = "unixtime,"
	}
	writer.WriteString(prefix + header[version] + "\n")
}

func writeBody(writer *bufio.Writer, output string) {
	prefix := ""
	if isStdin && *timestamp {
		prefix = fmtFrac(time.Now(), 6) + ","
	}

	writer.WriteString(prefix + output + "\n")
}

func fmtFrac(t time.Time, prec int) string {
	unixNano := t.UnixNano()
	fmtStr := "%." + strconv.Itoa(prec) + "f"
	return fmt.Sprintf(fmtStr, float64(unixNano)/10e8)
}

func main() {
	flag.Parse()

	flag.Usage = func() {
		fmt.Println("Usage1: log2csv -i gc.log -o gc.csv")
		fmt.Println("Usage2: GOGCTRACE=1 your-go-program 2>&1 | log2csv -o gc.csv")
		flag.PrintDefaults()
	}

	if *help {
		flag.Usage()
		os.Exit(0)
	}

	var in, out *os.File

	if *inputFile != "" {
		var err error
		in, err = os.Open(*inputFile)
		if err != nil {
			fmt.Fprintf(os.Stderr, "cannot open input file: %s", err)
			os.Exit(1)
		}
		defer in.Close()
	} else {
		in = os.Stdin
		isStdin = true
	}

	if *outputFile != "" {
		var err error
		out, err = os.OpenFile(*outputFile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
		if err != nil {
			fmt.Fprintf(os.Stderr, "cannot create output file: %s", err)
			os.Exit(1)
		}
		defer out.Close()
	} else {
		fmt.Fprint(os.Stderr, "require output file\n")
		flag.Usage()
		os.Exit(-1)
	}

	run(in, out)
}
<|endoftext|>


<commit_before>package registry

import (
	"github.com/skynetservices/skydns/msg"
	"testing"
)

/* TODO:
   Benchmarks
*/

var services = []msg.Service{
	msg.Service{
		UUID:        "123",
		Name:        "TestService",
		Version:     "1.0.0",
		Region:      "Test",
		Host:        "localhost",
		Environment: "Production",
		Port:        9000,
		TTL:         4,
	},
	msg.Service{
		UUID:        "321",
		Name:        "TestService",
		Version:     "1.0.1",
		Region:      "Test",
		Environment: "Production",
		Host:        "localhost",
		Port:        9001,
		TTL:         4,
	},
}

func TestAdd(t *testing.T) {
	reg := New()

	for _, s := range services {
		if err := reg.Add(s); err != nil {
			t.Fatal(err)
		}
	}

	if reg.Len() != 2 {
		t.Fatal("Registry length incorrect")
	}
}

func TestAddDuplicate(t *testing.T) {
	reg := New()

	s := msg.Service{
		UUID:        "123",
		Name:        "TestService",
		Version:     "1.0.0",
		Region:      "Test",
		Host:        "localhost",
		Environment: "Production",
		Port:        9000,
		TTL:         4,
	}

	reg.Add(s)
	err := reg.Add(s)

	if err != ErrExists {
		t.Fatal("Registry should error on duplicate")
	}
}

func TestGetRegistryKey(t *testing.T) {
	s := msg.Service{
		UUID:        "123",
		Name:        "TestService",
		Version:     "1.0.0",
		Region:      "Test",
		Host:        "localhost",
		Environment: "Production",
		Port:        9000,
		TTL:         4,
	}

	key := getRegistryKey(s)

	if key != "123.localhost.test.1-0-0.testservice.production" {
		t.Fatal("Key incorrect. Received: ", key)
	}
}

func TestRemove(t *testing.T) {
	reg := New()

	for _, s := range services {
		if err := reg.Add(s); err != nil {
			t.Fatal(err)
		}
	}

	err := reg.Remove(services[0])

	if err != nil {
		t.Fatal(err)
	}

	if reg.Len() != 1 {
		t.Fatal("Service not removed")
	}
}

func TestRemoveUUID(t *testing.T) {
	reg := New()

	for _, s := range services {
		if err := reg.Add(s); err != nil {
			t.Fatal(err)
		}
	}

	err := reg.RemoveUUID(services[0].UUID)

	if err != nil {
		t.Fatal(err)
	}

	if reg.Len() != 1 {
		t.Fatal("Service not removed")
	}
}

func TestGet(t *testing.T) {
	reg := New()

	for _, s := range services {
		if err := reg.Add(s); err != nil {
			t.Fatal(err)
		}
	}

	// Test explicit path
	results, err := reg.Get("123.localhost.test.1-0-0.testservice.production")

	if err != nil {
		t.Fatal(err)
	}

	if len(results) != 1 {
		t.Fatal("Failed to return correct services")
	}

	// Test Wildcard
	results, err = reg.Get("any.localhost.test.all.testservice.production")

	if err != nil {
		t.Fatal(err)
	}

	if len(results) != 2 {
		t.Fatal("Failed to return correct services")
	}

	// Test implicit wildcards
	results, err = reg.Get("testservice.production")

	if err != nil {
		t.Fatal(err)
	}

	if len(results) != 2 {
		t.Fatal("Failed to return correct services")
	}

	// Test trailing .
	results, err = reg.Get("testservice.production.")

	if err != nil {
		t.Fatal(err)
	}

	if len(results) != 2 {
		t.Fatal("Failed to return correct services")
	}
}

func TestGetUUID(t *testing.T) {
	reg := New()

	for _, s := range services {
		if err := reg.Add(s); err != nil {
			t.Fatal(err)
		}
	}

	s, err := reg.GetUUID(services[0].UUID)

	if err != nil {
		t.Fatal(err)
	}

	if s != services[0] {
		t.Fatal("Failed to retrieve proper service")
	}
}

func TestUpdateTTL(t *testing.T) {
	reg := New()
	r := reg.(*DefaultRegistry)

	for _, s := range services {
		if err := reg.Add(s); err != nil {
			t.Fatal(err)
		}
	}

	origExpire := r.nodes[services[0].UUID].expires

	if err := reg.UpdateTTL(services[0].UUID, 10); err != nil {
		t.Fatal("Failed to update TTL", err)
	}

	results, err := reg.Get("123.localhost.test.1-0-0.testservice.production")

	if err != nil {
		t.Fatal(err)
	}

	if len(results) != 1 {
		t.Fatal("Failed to return correct services")
	}

	// Validate TTL and Expiration
	if results[0].TTL != 10 {
		t.Fatal("TTL was not updated", results[0].TTL)
	}

	if r.nodes[services[0].UUID].expires.Unix() <= origExpire.Unix() {
		t.Fatal("Service expiration not updated")
	}
}

func TestGetExpired(t *testing.T) {
	reg := New()

	s := msg.Service{
		UUID:        "123",
		Name:        "TestService",
		Version:     "1.0.0",
		Region:      "Test",
		Host:        "localhost",
		Environment: "Production",
		Port:        9000,
		TTL:         500,
	}

	sExpired := msg.Service{
		UUID:        "124",
		Name:        "TestService",
		Version:     "1.0.0",
		Region:      "Test",
		Host:        "localhost",
		Environment: "Production",
		Port:        9000,
		TTL:         0,
	}

	reg.Add(s)
	reg.Add(sExpired)

	expired := reg.GetExpired()

	if len(expired) != 1 {
		t.Fatalf("Expected %d expired services, received %d", 1, len(expired))
	}

	if expired[0] != "124" {
		t.Fatal("Incorrect UUID returned for expired entry")
	}
}
<commit_msg>adding additional test case for registry.Get<commit_after>package registry

import (
	"github.com/skynetservices/skydns/msg"
	"testing"
)

/* TODO:
   Benchmarks
*/

var services = []msg.Service{
	msg.Service{
		UUID:        "123",
		Name:        "TestService",
		Version:     "1.0.0",
		Region:      "Test",
		Host:        "localhost",
		Environment: "Production",
		Port:        9000,
		TTL:         4,
	},
	msg.Service{
		UUID:        "321",
		Name:        "TestService",
		Version:     "1.0.1",
		Region:      "Test",
		Environment: "Production",
		Host:        "localhost",
		Port:        9001,
		TTL:         4,
	},
}

func TestAdd(t *testing.T) {
	reg := New()

	for _, s := range services {
		if err := reg.Add(s); err != nil {
			t.Fatal(err)
		}
	}

	if reg.Len() != 2 {
		t.Fatal("Registry length incorrect")
	}
}

func TestAddDuplicate(t *testing.T) {
	reg := New()

	s := msg.Service{
		UUID:        "123",
		Name:        "TestService",
		Version:     "1.0.0",
		Region:      "Test",
		Host:        "localhost",
		Environment: "Production",
		Port:        9000,
		TTL:         4,
	}

	reg.Add(s)
	err := reg.Add(s)

	if err != ErrExists {
		t.Fatal("Registry should error on duplicate")
	}
}

func TestGetRegistryKey(t *testing.T) {
	s := msg.Service{
		UUID:        "123",
		Name:        "TestService",
		Version:     "1.0.0",
		Region:      "Test",
		Host:        "localhost",
		Environment: "Production",
		Port:        9000,
		TTL:         4,
	}

	key := getRegistryKey(s)

	if key != "123.localhost.test.1-0-0.testservice.production" {
		t.Fatal("Key incorrect. Received: ", key)
	}
}

func TestRemove(t *testing.T) {
	reg := New()

	for _, s := range services {
		if err := reg.Add(s); err != nil {
			t.Fatal(err)
		}
	}

	err := reg.Remove(services[0])

	if err != nil {
		t.Fatal(err)
	}

	if reg.Len() != 1 {
		t.Fatal("Service not removed")
	}
}

func TestRemoveUUID(t *testing.T) {
	reg := New()

	for _, s := range services {
		if err := reg.Add(s); err != nil {
			t.Fatal(err)
		}
	}

	err := reg.RemoveUUID(services[0].UUID)

	if err != nil {
		t.Fatal(err)
	}

	if reg.Len() != 1 {
		t.Fatal("Service not removed")
	}
}

func TestGet(t *testing.T) {
	reg := New()

	for _, s := range services {
		if err := reg.Add(s); err != nil {
			t.Fatal(err)
		}
	}

	// Test explicit path
	results, err := reg.Get("123.localhost.test.1-0-0.testservice.production")

	if err != nil {
		t.Fatal(err)
	}

	if len(results) != 1 {
		t.Fatal("Failed to return correct services")
	}

	// Test Wildcard
	results, err = reg.Get("any.localhost.test.all.testservice.production")

	if err != nil {
		t.Fatal(err)
	}

	if len(results) != 2 {
		t.Fatal("Failed to return correct services")
	}

	// Test implicit wildcards
	results, err = reg.Get("testservice.production")

	if err != nil {
		t.Fatal(err)
	}

	if len(results) != 2 {
		t.Fatal("Failed to return correct services")
	}

	// Test only supplying any for environment
	results, err = reg.Get("any")

	if err != nil {
		t.Fatal(err)
	}

	if len(results) != 2 {
		t.Fatal("Failed to return correct services")
	}

	// Test trailing .
	results, err = reg.Get("testservice.production.")

	if err != nil {
		t.Fatal(err)
	}

	if len(results) != 2 {
		t.Fatal("Failed to return correct services")
	}
}

func TestGetUUID(t *testing.T) {
	reg := New()

	for _, s := range services {
		if err := reg.Add(s); err != nil {
			t.Fatal(err)
		}
	}

	s, err := reg.GetUUID(services[0].UUID)

	if err != nil {
		t.Fatal(err)
	}

	if s != services[0] {
		t.Fatal("Failed to retrieve proper service")
	}
}

func TestUpdateTTL(t *testing.T) {
	reg := New()
	r := reg.(*DefaultRegistry)

	for _, s := range services {
		if err := reg.Add(s); err != nil {
			t.Fatal(err)
		}
	}

	origExpire := r.nodes[services[0].UUID].expires

	if err := reg.UpdateTTL(services[0].UUID, 10); err != nil {
		t.Fatal("Failed to update TTL", err)
	}

	results, err := reg.Get("123.localhost.test.1-0-0.testservice.production")

	if err != nil {
		t.Fatal(err)
	}

	if len(results) != 1 {
		t.Fatal("Failed to return correct services")
	}

	// Validate TTL and Expiration
	if results[0].TTL != 10 {
		t.Fatal("TTL was not updated", results[0].TTL)
	}

	if r.nodes[services[0].UUID].expires.Unix() <= origExpire.Unix() {
		t.Fatal("Service expiration not updated")
	}
}

func TestGetExpired(t *testing.T) {
	reg := New()

	s := msg.Service{
		UUID:        "123",
		Name:        "TestService",
		Version:     "1.0.0",
		Region:      "Test",
		Host:        "localhost",
		Environment: "Production",
		Port:        9000,
		TTL:         500,
	}

	sExpired := msg.Service{
		UUID:        "124",
		Name:        "TestService",
		Version:     "1.0.0",
		Region:      "Test",
		Host:        "localhost",
		Environment: "Production",
		Port:        9000,
		TTL:         0,
	}

	reg.Add(s)
	reg.Add(sExpired)

	expired := reg.GetExpired()

	if len(expired) != 1 {
		t.Fatalf("Expected %d expired services, received %d", 1, len(expired))
	}

	if expired[0] != "124" {
		t.Fatal("Incorrect UUID returned for expired entry")
	}
}
<|endoftext|>


<commit_before>package datasource

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"strings"

	"github.com/coreos/coreos-cloudinit/pkg"
)

// metadataService retrieves metadata from either an OpenStack[1] (2012-08-10)
// or EC2[2] (2009-04-04) compatible endpoint. It will first attempt to
// directly retrieve a JSON blob from the OpenStack endpoint. If that fails
// with a 404, it then attempts to retrieve metadata bit-by-bit from the EC2
// endpoint, and populates that into an equivalent JSON blob. metadataService
// also checks for userdata from EC2 and, if that fails with a 404, OpenStack.
//
// [1] http://docs.openstack.org/grizzly/openstack-compute/admin/content/metadata-service.html
// [2] http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AESDG-chapter-instancedata.html#instancedata-data-categories

const (
	BaseUrl              = "http://169.254.169.254/"
	Ec2ApiVersion        = "2009-04-04"
	Ec2UserdataUrl       = BaseUrl + Ec2ApiVersion + "/user-data"
	Ec2MetadataUrl       = BaseUrl + Ec2ApiVersion + "/meta-data"
	OpenstackApiVersion  = "openstack/2012-08-10"
	OpenstackUserdataUrl = BaseUrl + OpenstackApiVersion + "/user_data"
	OpenstackMetadataUrl = BaseUrl + OpenstackApiVersion + "/meta_data.json"
)

type metadataService struct{}

type getter interface {
	GetRetry(string) ([]byte, error)
}

func NewMetadataService() *metadataService {
	return &metadataService{}
}

func (ms *metadataService) IsAvailable() bool {
	client := pkg.NewHttpClient()
	_, err := client.Get(BaseUrl)
	return (err == nil)
}

func (ms *metadataService) AvailabilityChanges() bool {
	return true
}

func (ms *metadataService) ConfigRoot() string {
	return ""
}

func (ms *metadataService) FetchMetadata() ([]byte, error) {
	return fetchMetadata(pkg.NewHttpClient())
}

func (ms *metadataService) FetchUserdata() ([]byte, error) {
	client := pkg.NewHttpClient()
	if data, err := client.GetRetry(Ec2UserdataUrl); err == nil {
		return data, err
	} else if _, ok := err.(pkg.ErrTimeout); ok {
		return data, err
	}
	return client.GetRetry(OpenstackUserdataUrl)
}

func (ms *metadataService) Type() string {
	return "metadata-service"
}

func fetchMetadata(client getter) ([]byte, error) {
	if metadata, err := client.GetRetry(OpenstackMetadataUrl); err == nil {
		return metadata, nil
	} else if _, ok := err.(pkg.ErrTimeout); ok {
		return nil, err
	}

	attrs := make(map[string]interface{})
	if keynames, err := fetchAttributes(client, fmt.Sprintf("%s/public-keys", Ec2MetadataUrl)); err == nil {
		keyIDs := make(map[string]string)
		for _, keyname := range keynames {
			tokens := strings.SplitN(keyname, "=", 2)
			if len(tokens) != 2 {
				return nil, fmt.Errorf("malformed public key: %q\n", keyname)
			}
			keyIDs[tokens[1]] = tokens[0]
		}

		keys := make(map[string]string)
		for name, id := range keyIDs {
			sshkey, err := fetchAttribute(client, fmt.Sprintf("%s/public-keys/%s/openssh-key", Ec2MetadataUrl, id))
			if err != nil {
				return nil, err
			}
			keys[name] = sshkey
			fmt.Printf("Found SSH key for %q\n", name)
		}
		attrs["public_keys"] = keys
	} else if _, ok := err.(pkg.ErrNotFound); !ok {
		return nil, err
	}

	if hostname, err := fetchAttribute(client, fmt.Sprintf("%s/hostname", Ec2MetadataUrl)); err == nil {
		attrs["hostname"] = hostname
	} else if _, ok := err.(pkg.ErrNotFound); !ok {
		return nil, err
	}

	if localAddr, err := fetchAttribute(client, fmt.Sprintf("%s/local-ipv4", Ec2MetadataUrl)); err == nil {
		attrs["local-ipv4"] = localAddr
	} else if _, ok := err.(pkg.ErrNotFound); !ok {
		return nil, err
	}

	if publicAddr, err := fetchAttribute(client, fmt.Sprintf("%s/public-ipv4", Ec2MetadataUrl)); err == nil {
		attrs["public-ipv4"] = publicAddr
	} else if _, ok := err.(pkg.ErrNotFound); !ok {
		return nil, err
	}

	if content_path, err := fetchAttribute(client, fmt.Sprintf("%s/network_config/content_path", Ec2MetadataUrl)); err == nil {
		attrs["network_config"] = map[string]string{
			"content_path": content_path,
		}
	} else if _, ok := err.(pkg.ErrNotFound); !ok {
		return nil, err
	}

	return json.Marshal(attrs)
}

func fetchAttributes(client getter, url string) ([]string, error) {
	resp, err := client.GetRetry(url)
	if err != nil {
		return nil, err
	}
	scanner := bufio.NewScanner(bytes.NewBuffer(resp))
	data := make([]string, 0)
	for scanner.Scan() {
		data = append(data, scanner.Text())
	}
	return data, scanner.Err()
}

func fetchAttribute(client getter, url string) (string, error) {
	if attrs, err := fetchAttributes(client, url); err == nil && len(attrs) > 0 {
		return attrs[0], nil
	} else {
		return "", err
	}
}
<commit_msg>metadata-service: Handle no user-data<commit_after>package datasource

import (
	"bufio"
	"bytes"
	"encoding/json"
	"fmt"
	"strings"

	"github.com/coreos/coreos-cloudinit/pkg"
)

// metadataService retrieves metadata from either an OpenStack[1] (2012-08-10)
// or EC2[2] (2009-04-04) compatible endpoint. It will first attempt to
// directly retrieve a JSON blob from the OpenStack endpoint. If that fails
// with a 404, it then attempts to retrieve metadata bit-by-bit from the EC2
// endpoint, and populates that into an equivalent JSON blob. metadataService
// also checks for userdata from EC2 and, if that fails with a 404, OpenStack.
//
// [1] http://docs.openstack.org/grizzly/openstack-compute/admin/content/metadata-service.html
// [2] http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/AESDG-chapter-instancedata.html#instancedata-data-categories

const (
	BaseUrl              = "http://169.254.169.254/"
	Ec2ApiVersion        = "2009-04-04"
	Ec2UserdataUrl       = BaseUrl + Ec2ApiVersion + "/user-data"
	Ec2MetadataUrl       = BaseUrl + Ec2ApiVersion + "/meta-data"
	OpenstackApiVersion  = "openstack/2012-08-10"
	OpenstackUserdataUrl = BaseUrl + OpenstackApiVersion + "/user_data"
	OpenstackMetadataUrl = BaseUrl + OpenstackApiVersion + "/meta_data.json"
)

type metadataService struct{}

type getter interface {
	GetRetry(string) ([]byte, error)
}

func NewMetadataService() *metadataService {
	return &metadataService{}
}

func (ms *metadataService) IsAvailable() bool {
	client := pkg.NewHttpClient()
	_, err := client.Get(BaseUrl)
	return (err == nil)
}

func (ms *metadataService) AvailabilityChanges() bool {
	return true
}

func (ms *metadataService) ConfigRoot() string {
	return ""
}

func (ms *metadataService) FetchMetadata() ([]byte, error) {
	return fetchMetadata(pkg.NewHttpClient())
}

func (ms *metadataService) FetchUserdata() ([]byte, error) {
	client := pkg.NewHttpClient()
	if data, err := client.GetRetry(Ec2UserdataUrl); err == nil {
		return data, err
	} else if _, ok := err.(pkg.ErrTimeout); ok {
		return data, err
	}

	if data, err := client.GetRetry(OpenstackUserdataUrl); err == nil {
		return data, err
	} else if _, ok := err.(pkg.ErrNotFound); ok {
		return []byte{}, nil
	} else {
		return data, err
	}
}

func (ms *metadataService) Type() string {
	return "metadata-service"
}

func fetchMetadata(client getter) ([]byte, error) {
	if metadata, err := client.GetRetry(OpenstackMetadataUrl); err == nil {
		return metadata, nil
	} else if _, ok := err.(pkg.ErrTimeout); ok {
		return nil, err
	}

	attrs := make(map[string]interface{})
	if keynames, err := fetchAttributes(client, fmt.Sprintf("%s/public-keys", Ec2MetadataUrl)); err == nil {
		keyIDs := make(map[string]string)
		for _, keyname := range keynames {
			tokens := strings.SplitN(keyname, "=", 2)
			if len(tokens) != 2 {
				return nil, fmt.Errorf("malformed public key: %q\n", keyname)
			}
			keyIDs[tokens[1]] = tokens[0]
		}

		keys := make(map[string]string)
		for name, id := range keyIDs {
			sshkey, err := fetchAttribute(client, fmt.Sprintf("%s/public-keys/%s/openssh-key", Ec2MetadataUrl, id))
			if err != nil {
				return nil, err
			}
			keys[name] = sshkey
			fmt.Printf("Found SSH key for %q\n", name)
		}
		attrs["public_keys"] = keys
	} else if _, ok := err.(pkg.ErrNotFound); !ok {
		return nil, err
	}

	if hostname, err := fetchAttribute(client, fmt.Sprintf("%s/hostname", Ec2MetadataUrl)); err == nil {
		attrs["hostname"] = hostname
	} else if _, ok := err.(pkg.ErrNotFound); !ok {
		return nil, err
	}

	if localAddr, err := fetchAttribute(client, fmt.Sprintf("%s/local-ipv4", Ec2MetadataUrl)); err == nil {
		attrs["local-ipv4"] = localAddr
	} else if _, ok := err.(pkg.ErrNotFound); !ok {
		return nil, err
	}

	if publicAddr, err := fetchAttribute(client, fmt.Sprintf("%s/public-ipv4", Ec2MetadataUrl)); err == nil {
		attrs["public-ipv4"] = publicAddr
	} else if _, ok := err.(pkg.ErrNotFound); !ok {
		return nil, err
	}

	if content_path, err := fetchAttribute(client, fmt.Sprintf("%s/network_config/content_path", Ec2MetadataUrl)); err == nil {
		attrs["network_config"] = map[string]string{
			"content_path": content_path,
		}
	} else if _, ok := err.(pkg.ErrNotFound); !ok {
		return nil, err
	}

	return json.Marshal(attrs)
}

func fetchAttributes(client getter, url string) ([]string, error) {
	resp, err := client.GetRetry(url)
	if err != nil {
		return nil, err
	}
	scanner := bufio.NewScanner(bytes.NewBuffer(resp))
	data := make([]string, 0)
	for scanner.Scan() {
		data = append(data, scanner.Text())
	}
	return data, scanner.Err()
}

func fetchAttribute(client getter, url string) (string, error) {
	if attrs, err := fetchAttributes(client, url); err == nil && len(attrs) > 0 {
		return attrs[0], nil
	} else {
		return "", err
	}
}
<|endoftext|>


<commit_before>/*******************************************************************************
The MIT License (MIT)

Copyright (c) 2013-2014 Hajime Nakagami

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*******************************************************************************/

package firebirdsql

import (
	"database/sql"
	"fmt"
	"testing"
	"time"
)

func TestBasic(t *testing.T) {
	conn, err := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050/tmp/go_test_basic.fdb")
	defer conn.Close()

	if err != nil {
		t.Fatalf("Error connecting: %v", err)
	}
	var sql string
	var n int

	sql = "SELECT Count(*) FROM rdb$relations where rdb$relation_name='FOO'"
	err = conn.QueryRow(sql).Scan(&n)
	if err != nil {
		t.Fatalf("Error QueryRow: %v", err)
	}
	if n > 0 {
		conn.Exec("DROP TABLE foo")
	}

	sql = `
        CREATE TABLE foo (
            a INTEGER NOT NULL,
            b VARCHAR(30) NOT NULL UNIQUE,
            c VARCHAR(1024),
            d DECIMAL(16,3) DEFAULT -0.123,
            e DATE DEFAULT '1967-08-11',
            f TIMESTAMP DEFAULT '1967-08-11 23:45:01',
            g TIME DEFAULT '23:45:01',
            h BLOB SUB_TYPE 1,
            i DOUBLE PRECISION DEFAULT 0.0,
            j FLOAT DEFAULT 0.0,
            PRIMARY KEY (a),
            CONSTRAINT CHECK_A CHECK (a <> 0)
        )
    `
	conn.Exec(sql)
	_, err = conn.Exec("CREATE TABLE foo (a INTEGER)")
	if err == nil {
		t.Fatalf("Need metadata update error")
	}
	if err.Error() != "unsuccessful metadata update\nTable FOO already exists\n" {
		t.Fatalf("Bad message:%v", err.Error())
	}

	// 3 records insert
	conn.Exec("insert into foo(a, b, c,h) values (1, 'a', 'b','This is a memo')")
	conn.Exec("insert into foo(a, b, c, e, g, i, j) values (2, 'A', 'B', '1999-01-25', '00:00:01', 0.1, 0.1)")
	conn.Exec("insert into foo(a, b, c, e, g, i, j) values (3, 'X', 'Y', '2001-07-05', '00:01:02', 0.2, 0.2)")

	err = conn.QueryRow("select count(*) cnt from foo").Scan(&n)
	if err != nil {
		t.Fatalf("Error QueryRow: %v", err)
	}
	if n != 3 {
		t.Fatalf("Error bad record count: %v", n)
	}

	rows, err := conn.Query("select a, b, c, d, e, f, g, i, j from foo")
	var a int
	var b, c string
	var d float64
	var e time.Time
	var f time.Time
	var g time.Time
	var i float64
	var j float32

	for rows.Next() {
		rows.Scan(&a, &b, &c, &d, &e, &f, &g, &i, &j)
	}

	stmt, _ := conn.Prepare("select count(*) from foo where a=? and b=? and d=? and e=? and f=? and g=?")
	ep := time.Date(1967, 8, 11, 0, 0, 0, 0, time.UTC)
	fp := time.Date(1967, 8, 11, 23, 45, 1, 0, time.UTC)
	gp, err := time.Parse("15:04:05", "23:45:01")
	err = stmt.QueryRow(1, "a", -0.123, ep, fp, gp).Scan(&n)
	if err != nil {
		t.Fatalf("Error QueryRow: %v", err)
	}
	if n != 1 {
		t.Fatalf("Error bad record count: %v", n)
	}
}

func TestReturning(t *testing.T) {
	conn, _ := sql.Open("firebirdsql_createdb", "SYSDBA:masterkey@localhost:3050/tmp/go_test_returning.fdb")
	defer conn.Close()

	conn.Exec(`
        CREATE TABLE test_returning (
            f1 integer NOT NULL,
            f2 integer default 2,
            f3 varchar(20) default 'abc')`)
	conn.Close()

	conn, _ = sql.Open("firebirdsql", "SYSDBA:masterkey@localhost:3050/tmp/go_test_returning.fdb")

	for i := 0; i < 2; i++ {

		rows, err := conn.Query("INSERT INTO test_returning (f1) values (1) returning f2, f3")
		if err != nil {
			t.Fatalf("Error Insert returning : %v", err)
		}
		var f2 int
		var f3 string
		rows.Next()
		rows.Scan(&f2, &f3)
		if f2 != 2 || f3 != "abc" {
			t.Fatalf("Bad value insert returning: %v,%v", f2, f3)
		}
	}

}

func TestIssue2(t *testing.T) {
	conn, _ := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050/tmp/go_test_issue2.fdb")

	_, err := conn.Exec(`
        CREATE TABLE test_issue2
         (f1 integer NOT NULL,
          f2 integer,
          f3 integer NOT NULL,
          f4 integer NOT NULL,
          f5 integer NOT NULL,
          f6 integer NOT NULL,
          f7 varchar(255) NOT NULL,
          f8 varchar(255) NOT NULL,
          f9 varchar(255) NOT NULL,
          f10 varchar(255) NOT NULL,
          f11 varchar(255) NOT NULL,
          f12 varchar(255) NOT NULL,
          f13 varchar(255) NOT NULL,
          f14 varchar(255) NOT NULL,
          f15 integer,
          f16 integer,
          f17 integer,
          f18 integer,
          f19 integer,
          f20 integer,
          f21 integer,
          f22 varchar(1),
          f23 varchar(255),
          f24 integer,
          f25 varchar(64),
          f26 integer)`)
	defer conn.Close()
	if err != nil {
		t.Fatalf("Error Create Table: %v", err)
	}

	_, err = conn.Exec(`
        INSERT INTO test_issue2 VALUES
        (1, 2, 3, 4, 5, 6, '7', '8', '9', '10', '11', '12', '13', '14',
          15, 16, 17, 18, 19, 20, 21, 'A', '23', 24, '25', '26')`)
	if err != nil {
		t.Fatalf("Error Insert: %v", err)
	}

	rows, err := conn.Query("SELECT * FROM test_issue2")
	if err != nil {
		t.Fatalf("Error Query: %v", err)
	}
	for rows.Next() {
	}
}

func TestIssue3(t *testing.T) {
	conn, _ := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050/tmp/go_test_issue3.fdb")
	too_many := 401

	conn.Exec("CREATE TABLE test_issue3 (f1 integer NOT NULL)")
	defer conn.Close()
	stmt, _ := conn.Prepare("INSERT INTO test_issue3 values (?)")
	for i := 0; i < too_many; i++ {
		stmt.Exec(i + 1)
	}

	rows, _ := conn.Query("SELECT * FROM test_issue3 ORDER BY f1")
	i := 0
	var n int
	for rows.Next() {
		rows.Scan(&n)
		i++
		if i != n {
			t.Fatalf("Error %v != %v", n, i)
		}
	}
	if i != too_many {
		t.Fatalf("Can't get all %v records. only %v", too_many, i)
	}
}

func TestIssue7(t *testing.T) {
	conn, _ := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050/tmp/go_test_issue7.fdb")

	conn.Exec("CREATE TABLE test_issue7 (f1 varchar(2048))")
	defer conn.Close()
	stmt, _ := conn.Prepare("INSERT INTO test_issue7 values (?)")
	stmt.Exec(fmt.Sprintf("%2000d", 1))
}

func TestIssue9(t *testing.T) {
	conn, _ := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050/tmp/go_test_issue9.fdb")

	conn.Exec("CREATE TABLE test_issue9 (f1 smallint)")
	defer conn.Close()
	conn.Exec("INSERT INTO test_issue9 (f1) values (1)")
	var n int
	err := conn.QueryRow("SELECT f1 from test_issue9").Scan(&n)
	if err != nil || n != 1 {
		fmt.Println(err)
		t.Fatalf("Invalid short value:%v:%v", err, n)
	}
}

func TestIssue10(t *testing.T) {
	conn, _ := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050/tmp/go_test_issue10.fdb")

	conn.Exec("CREATE TABLE test_issue10 (f1 BLOB SUB_TYPE 1)")
	defer conn.Close()
	conn.Exec("INSERT INTO test_issue10 (f1) values ('ABC')")
    var blob sql.RawBytes
	err := conn.QueryRow("SELECT f1 from test_issue10").Scan(&blob)
	if err != nil || blob[0] != 65 {
		t.Fatalf("Invalid short value:%v:%v", err, blob)
	}
}

func TestError(t *testing.T) {
	conn, err := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050/tmp/go_test_error.fdb")
	if err != nil {
		t.Fatalf("Error connecting: %v", err)
	}
	_, err = conn.Exec("incorrect sql statement")
	if err == nil || err.Error() != "Dynamic SQL Error\nSQL error code = -104\nToken unknown - line 1, column 1\nincorrect\n" {
		t.Fatalf("Incorrect error")
	}
}

/*
func TestFB3(t *testing.T) {
	conn, err := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050/tmp/go_test_fb3.fdb")
	if err != nil {
		t.Fatalf("Error connecting: %v", err)
	}
	var sql string
	var n int

	sql = "SELECT Count(*) FROM rdb$relations where rdb$relation_name='TEST_FB3'"
	err = conn.QueryRow(sql).Scan(&n)
	if err != nil {
		t.Fatalf("Error QueryRow: %v", err)
	}
	if n > 0 {
		conn.Exec("DROP TABLE test_fb3")
	}

	sql = `
        CREATE TABLE test_fb3 (
            b BOOLEAN
        )
    `
	conn.Exec(sql)
	conn.Exec("insert into test_fb3(b) values (true)")
	conn.Exec("insert into test_fb3(b) values (false)")
    var b bool
	err = conn.QueryRow("select * from test_fb3 where b is true").Scan(&b)
	if err != nil {
		t.Fatalf("Error QueryRow: %v", err)
	}
	if b != true{
		conn.Exec("Invalid boolean value")
	}
	err = conn.QueryRow("select * from test_fb3 where b is false").Scan(&b)
	if err != nil {
		t.Fatalf("Error QueryRow: %v", err)
	}
	if b != false{
		conn.Exec("Invalid boolean value")
	}

	stmt, _ := conn.Prepare("select * from test_fb3 where b=?")
	err = stmt.QueryRow(true).Scan(&b)
	if err != nil {
		t.Fatalf("Error QueryRow: %v", err)
	}
	if b != false{
		conn.Exec("Invalid boolean value")
	}

	defer conn.Close()
}
*/
<commit_msg>fix test issue #10<commit_after>/*******************************************************************************
The MIT License (MIT)

Copyright (c) 2013-2014 Hajime Nakagami

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*******************************************************************************/

package firebirdsql

import (
	"database/sql"
	"fmt"
	"testing"
	"time"
)

func TestBasic(t *testing.T) {
	conn, err := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050/tmp/go_test_basic.fdb")
	defer conn.Close()

	if err != nil {
		t.Fatalf("Error connecting: %v", err)
	}
	var sql string
	var n int

	sql = "SELECT Count(*) FROM rdb$relations where rdb$relation_name='FOO'"
	err = conn.QueryRow(sql).Scan(&n)
	if err != nil {
		t.Fatalf("Error QueryRow: %v", err)
	}
	if n > 0 {
		conn.Exec("DROP TABLE foo")
	}

	sql = `
        CREATE TABLE foo (
            a INTEGER NOT NULL,
            b VARCHAR(30) NOT NULL UNIQUE,
            c VARCHAR(1024),
            d DECIMAL(16,3) DEFAULT -0.123,
            e DATE DEFAULT '1967-08-11',
            f TIMESTAMP DEFAULT '1967-08-11 23:45:01',
            g TIME DEFAULT '23:45:01',
            h BLOB SUB_TYPE 1,
            i DOUBLE PRECISION DEFAULT 0.0,
            j FLOAT DEFAULT 0.0,
            PRIMARY KEY (a),
            CONSTRAINT CHECK_A CHECK (a <> 0)
        )
    `
	conn.Exec(sql)
	_, err = conn.Exec("CREATE TABLE foo (a INTEGER)")
	if err == nil {
		t.Fatalf("Need metadata update error")
	}
	if err.Error() != "unsuccessful metadata update\nTable FOO already exists\n" {
		t.Fatalf("Bad message:%v", err.Error())
	}

	// 3 records insert
	conn.Exec("insert into foo(a, b, c,h) values (1, 'a', 'b','This is a memo')")
	conn.Exec("insert into foo(a, b, c, e, g, i, j) values (2, 'A', 'B', '1999-01-25', '00:00:01', 0.1, 0.1)")
	conn.Exec("insert into foo(a, b, c, e, g, i, j) values (3, 'X', 'Y', '2001-07-05', '00:01:02', 0.2, 0.2)")

	err = conn.QueryRow("select count(*) cnt from foo").Scan(&n)
	if err != nil {
		t.Fatalf("Error QueryRow: %v", err)
	}
	if n != 3 {
		t.Fatalf("Error bad record count: %v", n)
	}

	rows, err := conn.Query("select a, b, c, d, e, f, g, i, j from foo")
	var a int
	var b, c string
	var d float64
	var e time.Time
	var f time.Time
	var g time.Time
	var i float64
	var j float32

	for rows.Next() {
		rows.Scan(&a, &b, &c, &d, &e, &f, &g, &i, &j)
	}

	stmt, _ := conn.Prepare("select count(*) from foo where a=? and b=? and d=? and e=? and f=? and g=?")
	ep := time.Date(1967, 8, 11, 0, 0, 0, 0, time.UTC)
	fp := time.Date(1967, 8, 11, 23, 45, 1, 0, time.UTC)
	gp, err := time.Parse("15:04:05", "23:45:01")
	err = stmt.QueryRow(1, "a", -0.123, ep, fp, gp).Scan(&n)
	if err != nil {
		t.Fatalf("Error QueryRow: %v", err)
	}
	if n != 1 {
		t.Fatalf("Error bad record count: %v", n)
	}
}

func TestReturning(t *testing.T) {
	conn, _ := sql.Open("firebirdsql_createdb", "SYSDBA:masterkey@localhost:3050/tmp/go_test_returning.fdb")
	defer conn.Close()

	conn.Exec(`
        CREATE TABLE test_returning (
            f1 integer NOT NULL,
            f2 integer default 2,
            f3 varchar(20) default 'abc')`)
	conn.Close()

	conn, _ = sql.Open("firebirdsql", "SYSDBA:masterkey@localhost:3050/tmp/go_test_returning.fdb")

	for i := 0; i < 2; i++ {

		rows, err := conn.Query("INSERT INTO test_returning (f1) values (1) returning f2, f3")
		if err != nil {
			t.Fatalf("Error Insert returning : %v", err)
		}
		var f2 int
		var f3 string
		rows.Next()
		rows.Scan(&f2, &f3)
		if f2 != 2 || f3 != "abc" {
			t.Fatalf("Bad value insert returning: %v,%v", f2, f3)
		}
	}

}

func TestIssue2(t *testing.T) {
	conn, _ := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050/tmp/go_test_issue2.fdb")

	_, err := conn.Exec(`
        CREATE TABLE test_issue2
         (f1 integer NOT NULL,
          f2 integer,
          f3 integer NOT NULL,
          f4 integer NOT NULL,
          f5 integer NOT NULL,
          f6 integer NOT NULL,
          f7 varchar(255) NOT NULL,
          f8 varchar(255) NOT NULL,
          f9 varchar(255) NOT NULL,
          f10 varchar(255) NOT NULL,
          f11 varchar(255) NOT NULL,
          f12 varchar(255) NOT NULL,
          f13 varchar(255) NOT NULL,
          f14 varchar(255) NOT NULL,
          f15 integer,
          f16 integer,
          f17 integer,
          f18 integer,
          f19 integer,
          f20 integer,
          f21 integer,
          f22 varchar(1),
          f23 varchar(255),
          f24 integer,
          f25 varchar(64),
          f26 integer)`)
	defer conn.Close()
	if err != nil {
		t.Fatalf("Error Create Table: %v", err)
	}

	_, err = conn.Exec(`
        INSERT INTO test_issue2 VALUES
        (1, 2, 3, 4, 5, 6, '7', '8', '9', '10', '11', '12', '13', '14',
          15, 16, 17, 18, 19, 20, 21, 'A', '23', 24, '25', '26')`)
	if err != nil {
		t.Fatalf("Error Insert: %v", err)
	}

	rows, err := conn.Query("SELECT * FROM test_issue2")
	if err != nil {
		t.Fatalf("Error Query: %v", err)
	}
	for rows.Next() {
	}
}

func TestIssue3(t *testing.T) {
	conn, _ := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050/tmp/go_test_issue3.fdb")
	too_many := 401

	conn.Exec("CREATE TABLE test_issue3 (f1 integer NOT NULL)")
	defer conn.Close()
	stmt, _ := conn.Prepare("INSERT INTO test_issue3 values (?)")
	for i := 0; i < too_many; i++ {
		stmt.Exec(i + 1)
	}

	rows, _ := conn.Query("SELECT * FROM test_issue3 ORDER BY f1")
	i := 0
	var n int
	for rows.Next() {
		rows.Scan(&n)
		i++
		if i != n {
			t.Fatalf("Error %v != %v", n, i)
		}
	}
	if i != too_many {
		t.Fatalf("Can't get all %v records. only %v", too_many, i)
	}
}

func TestIssue7(t *testing.T) {
	conn, _ := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050/tmp/go_test_issue7.fdb")

	conn.Exec("CREATE TABLE test_issue7 (f1 varchar(2048))")
	defer conn.Close()
	stmt, _ := conn.Prepare("INSERT INTO test_issue7 values (?)")
	stmt.Exec(fmt.Sprintf("%2000d", 1))
}

func TestIssue9(t *testing.T) {
	conn, _ := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050/tmp/go_test_issue9.fdb")

	conn.Exec("CREATE TABLE test_issue9 (f1 smallint)")
	defer conn.Close()
	conn.Exec("INSERT INTO test_issue9 (f1) values (1)")
	var n int
	err := conn.QueryRow("SELECT f1 from test_issue9").Scan(&n)
	if err != nil || n != 1 {
		fmt.Println(err)
		t.Fatalf("Invalid short value:%v:%v", err, n)
	}
}

func TestIssue10(t *testing.T) {
	conn, _ := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050/tmp/go_test_issue10.fdb")

	conn.Exec("CREATE TABLE test_issue10 (f1 BLOB SUB_TYPE 1)")
	defer conn.Close()
	conn.Exec("INSERT INTO test_issue10 (f1) values ('ABC')")
    var blob []byte
	err := conn.QueryRow("SELECT f1 from test_issue10").Scan(&blob)
	if err != nil || blob == nil || blob[0] != 65 {
		t.Fatalf("Invalid blob value:%v:%v", err, blob)
	}
}

func TestError(t *testing.T) {
	conn, err := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050/tmp/go_test_error.fdb")
	if err != nil {
		t.Fatalf("Error connecting: %v", err)
	}
	_, err = conn.Exec("incorrect sql statement")
	if err == nil || err.Error() != "Dynamic SQL Error\nSQL error code = -104\nToken unknown - line 1, column 1\nincorrect\n" {
		t.Fatalf("Incorrect error")
	}
}

/*
func TestFB3(t *testing.T) {
	conn, err := sql.Open("firebirdsql_createdb", "sysdba:masterkey@localhost:3050/tmp/go_test_fb3.fdb")
	if err != nil {
		t.Fatalf("Error connecting: %v", err)
	}
	var sql string
	var n int

	sql = "SELECT Count(*) FROM rdb$relations where rdb$relation_name='TEST_FB3'"
	err = conn.QueryRow(sql).Scan(&n)
	if err != nil {
		t.Fatalf("Error QueryRow: %v", err)
	}
	if n > 0 {
		conn.Exec("DROP TABLE test_fb3")
	}

	sql = `
        CREATE TABLE test_fb3 (
            b BOOLEAN
        )
    `
	conn.Exec(sql)
	conn.Exec("insert into test_fb3(b) values (true)")
	conn.Exec("insert into test_fb3(b) values (false)")
    var b bool
	err = conn.QueryRow("select * from test_fb3 where b is true").Scan(&b)
	if err != nil {
		t.Fatalf("Error QueryRow: %v", err)
	}
	if b != true{
		conn.Exec("Invalid boolean value")
	}
	err = conn.QueryRow("select * from test_fb3 where b is false").Scan(&b)
	if err != nil {
		t.Fatalf("Error QueryRow: %v", err)
	}
	if b != false{
		conn.Exec("Invalid boolean value")
	}

	stmt, _ := conn.Prepare("select * from test_fb3 where b=?")
	err = stmt.QueryRow(true).Scan(&b)
	if err != nil {
		t.Fatalf("Error QueryRow: %v", err)
	}
	if b != false{
		conn.Exec("Invalid boolean value")
	}

	defer conn.Close()
}
*/
<|endoftext|>