예제 #1
0
// Log sends data to the agent's global log. It works like log.Log
func (j *Job) Log(v ...interface{}) {
	for _, val := range v {
		if j.errorChannel != nil {
			if v, ok := val.(string); ok {
				j.errorChannel <- gotelemetry.NewLogError("%s -> %s", j.ID, v)
			} else {
				j.errorChannel <- gotelemetry.NewLogError("%s -> %#v", j.ID, val)
			}
		}
	}
}
예제 #2
0
func setupUDPListener(listen string, errorChannel chan error) {
	addr, err := net.ResolveUDPAddr("udp", listen)

	if err != nil {
		errorChannel <- err
		return
	}

	conn, err := net.ListenUDP("udp", addr)

	if err != nil {
		errorChannel <- err
		return
	}

	errorChannel <- gotelemetry.NewLogError("Graphite => Listening for UDP plaintext messages on %s", conn.LocalAddr())

	buf := make([]byte, 2048)

	for {
		if n, addr, err := conn.ReadFromUDP(buf); err == nil {
			remoteAddress := addr.String() + ", UDP"

			if err := parseRequest(remoteAddress, string(buf[0:n]), errorChannel); err != nil {
				errorChannel <- gotelemetry.NewErrorWithFormat(400, "Graphite => [%s, UDP] Error %s while receving data", nil, addr, err)
			}
		} else {
			errorChannel <- gotelemetry.NewErrorWithFormat(400, "Graphite => [%s, UDP] Error %s while receving data", nil, addr, err)
		}
	}
}
예제 #3
0
func ProcessNotificationRequest(configFile *config.ConfigFile, errorChannel chan error, completionChannel chan bool, notificationChannel string, notificationFlow string, notification gotelemetry.Notification) {
	errorChannel <- gotelemetry.NewLogError("Notification mode is on.")

	apiToken, err := configFile.APIToken()

	if err != nil {
		errorChannel <- err
		completionChannel <- true

		return
	}

	credentials, err := gotelemetry.NewCredentials(apiToken)

	if err != nil {
		errorChannel <- err
		completionChannel <- true

		return
	}

	credentials.SetDebugChannel(errorChannel)

	if len(notificationChannel) > 0 {
		channel := gotelemetry.NewChannel(notificationChannel)
		err = channel.SendNotification(credentials, notification)
	} else if len(notificationFlow) > 0 {
		err = gotelemetry.SendFlowChannelNotification(credentials, notificationFlow, notification)
	} else {
		err = gotelemetry.NewError(http.StatusBadRequest, "Either channel or flow is required")
	}

	if err != nil {
		errorChannel <- err
	} else {
		errorChannel <- gotelemetry.NewLogError("Notification sent successfully.")
	}

	completionChannel <- true
}
예제 #4
0
func RunCommand(cfg config.CLIConfigType, errorChannel chan error, completionChannel chan bool) {
	client, err := clientForEntryWithName(cfg.OAuthName)

	if err != nil {
		errorChannel <- err
		return
	}

	switch cfg.OAuthCommand {
	case config.OAuthCommands.None:
		// Do nothing
		break

	case config.OAuthCommands.Request:
		url, err := client.GetAuthorizationURL()

		if err != nil {
			errorChannel <- err
			break
		}

		errorChannel <- gotelemetry.NewLogError("Please visit this URL and authorize the Agent:\n\n---\n%s\n---\n\n", url)
		errorChannel <- gotelemetry.NewLogError("When you are done, please run the agent with the oauth-exchange command to set the new token.\n\n")

	case config.OAuthCommands.Exchange:
		err := client.ExchangeToken(cfg.OAuthCode, cfg.OAuthVerifier, cfg.OAuthRealmID)

		if err != nil {
			errorChannel <- err
			break
		}

		errorChannel <- gotelemetry.NewLogError("Token exchanged successfully. The entry %s can now be used to make authenticated calls.", cfg.OAuthName)

	default:
		errorChannel <- fmt.Errorf("Unknown oauth command %s", cfg.OAuthCommand)
	}

	completionChannel <- true
}
예제 #5
0
func parseCounterRequest(remoteAddress string, line []string, errorChannel chan error) error {
	counterName := line[0]
	valueString := line[1]

	isSetOperation := valueString[0] == '='

	if isSetOperation {
		valueString = strings.TrimPrefix(valueString, "=")
	}

	value, err := strconv.ParseInt(valueString, 10, 64)

	if err != nil {
		return gotelemetry.NewErrorWithFormat(
			400, "Graphite => [%s] Invalid value %s: %s",
			nil,
			remoteAddress,
			line[1],
			err.Error(),
		)
	}

	counter, isCreated, err := aggregations.GetCounter(counterName)

	if isCreated {
		errorChannel <- gotelemetry.NewLogError("Graphite => Started receiving graphite data for '%s'", counterName)
	}

	if err != nil {
		return gotelemetry.NewErrorWithFormat(
			500, "Graphite => [%s] Unable to get counter %s: %s",
			nil,
			remoteAddress,
			counterName,
			err.Error(),
		)
	}

	if isSetOperation {
		counter.SetValue(value)
	} else {
		counter.Increment(value)
	}

	return nil
}
예제 #6
0
func setupTCPListener(listen string, errorChannel chan error) {
	l, err := net.Listen("tcp", listen)

	if err != nil {
		errorChannel <- err
		return
	}

	defer l.Close()

	errorChannel <- gotelemetry.NewLogError("Graphite => Listening for TCP plaintext connections on %s", l.Addr())

	for {
		conn, err := l.Accept()

		if err != nil {
			errorChannel <- err
			return
		}

		go handleTCPRequest(conn, errorChannel, true)
	}
}
예제 #7
0
// Logf sends a formatted string to the agent's global log. It works like log.Logf
func (m *Manager) Logf(format string, v ...interface{}) {
	if m.errorChannel != nil {
		m.errorChannel <- gotelemetry.NewLogError("Data Manager -> %#s", fmt.Sprintf(format, v...))
	}
}
예제 #8
0
func (c *Counter) debug(format string, data ...interface{}) {
	manager.errorChannel <- gotelemetry.NewLogError("Counter %s -> %s", c.Name, fmt.Sprintf(format, data...))
}
예제 #9
0
func ProcessPipeRequest(configFile *config.ConfigFile, errorChannel chan error, completionChannel chan bool, data []byte) {
	errorChannel <- gotelemetry.NewLogError("Piped mode is on.")
	errorChannel <- gotelemetry.NewDebugError("Input data is %s", strings.Replace(string(data), "\n", "\\n", -1))

	submissionType := gotelemetry.BatchTypePATCH

	if config.CLIConfig.UseJSONPatch {
		errorChannel <- gotelemetry.NewDebugError("Will perform a JSON-Patch operation")
		submissionType = gotelemetry.BatchTypeJSONPATCH
	} else if config.CLIConfig.UsePOST {
		errorChannel <- gotelemetry.NewDebugError("Will perform a POST operation")
		submissionType = gotelemetry.BatchTypePOST
	} else {
		errorChannel <- gotelemetry.NewDebugError("Will perform a Rails-style HTTP PATCH operation")
	}

	apiToken, err := configFile.APIToken()

	if err != nil {
		errorChannel <- err
		completionChannel <- true

		return
	}

	credentials, err := gotelemetry.NewCredentials(apiToken, configFile.APIURL())

	if err != nil {
		errorChannel <- err
		completionChannel <- true

		return
	}

	credentials.SetDebugChannel(errorChannel)

	updates := map[string]interface{}{}

	err = json.Unmarshal(data, &updates)

	if err != nil {
		errorChannel <- err
		completionChannel <- true

		return
	}

	b := gotelemetry.Batch{}

	for tag, update := range updates {
		b.SetData(tag, update)
	}

	err = b.Publish(credentials, configFile.ChannelTag(), submissionType)

	if err != nil {
		errorChannel <- err
	}

	errorChannel <- gotelemetry.NewLogError("Processing complete. Exiting.")

	completionChannel <- true
}
예제 #10
0
func parseTraditionalRequest(remoteAddress string, line []string, errorChannel chan error) error {
	seriesName := line[0]

	value, err := strconv.ParseFloat(line[1], 64)

	if err != nil {
		return gotelemetry.NewErrorWithFormat(
			400, "Graphite => [%s] Invalid value %s: %s",
			nil,
			remoteAddress,
			line[1],
			err.Error(),
		)
	}

	timestamp, err := strconv.ParseInt(line[2], 10, 64)

	if err != nil {
		return gotelemetry.NewErrorWithFormat(
			400, "Graphite => [%s] Invalid timestamp %s: %s",
			nil,
			remoteAddress,
			line[2],
			err.Error(),
		)
	}

	series, isCreated, err := aggregations.GetSeries(seriesName)

	if err != nil {
		return gotelemetry.NewErrorWithFormat(
			500, "Graphite => [%s] Unable to get series %s: %s",
			nil,
			remoteAddress,
			seriesName,
			err.Error(),
		)
	}

	if isCreated {
		errorChannel <- gotelemetry.NewLogError("Graphite => Started receiving graphite data for '%s'", seriesName)
	}

	ts := time.Unix(timestamp, 0)

	if err := series.Push(&ts, value); err != nil {
		return gotelemetry.NewErrorWithFormat(
			500, "Graphite => [%s] Unable to push value %f with timestamp %s to series %s: %s",
			nil,
			remoteAddress,
			value,
			ts,
			seriesName,
			err.Error(),
		)
	}

	errorChannel <- gotelemetry.NewDebugError(
		"Graphite => [%s] Pushed value %f to series %s at time %s",
		remoteAddress,
		value,
		seriesName,
		ts,
	)

	return nil
}
예제 #11
0
// Logf sends a formatted string to the agent's global log. It works like log.Logf
func (j *Job) Logf(format string, v ...interface{}) {
	if j.errorChannel != nil {
		j.errorChannel <- gotelemetry.NewLogError("%s -> %#s", j.ID, fmt.Sprintf(format, v...))
	}
}
예제 #12
0
func NewJobManager(jobConfig config.ConfigInterface, errorChannel chan error, completionChannel chan bool) (*JobManager, error) {
	result := &JobManager{
		jobs:                 map[string]*Job{},
		completionChannel:    completionChannel,
		jobCompletionChannel: make(chan string),
	}

	apiToken, err := jobConfig.APIToken()

	if err != nil {
		return nil, err
	}

	credentials, err := gotelemetry.NewCredentials(apiToken, jobConfig.APIURL())

	if err != nil {
		return nil, err
	}

	credentials.SetDebugChannel(errorChannel)

	result.credentials = credentials

	submissionInterval := jobConfig.SubmissionInterval()

	if submissionInterval < time.Second {
		errorChannel <- gotelemetry.NewLogError("Submission interval automatically set to 1s. You can change this value by adding a `submission_interval` property to your configuration file.")
		submissionInterval = time.Second
	} else {
		errorChannel <- gotelemetry.NewLogError("Submission interval set to %ds", submissionInterval/time.Second)
	}

	result.accountStreams = map[string]*gotelemetry.BatchStream{}

	for _, jobDescription := range jobConfig.Jobs() {
		jobId := jobDescription.ID()

		if jobId == "" {
			return nil, gotelemetry.NewError(500, "Job ID missing and no `flow_tag` provided.")
		}

		if !config.CLIConfig.Filter.MatchString(jobId) {
			continue
		}

		if config.CLIConfig.ForceRunOnce {
			delete(jobDescription, "refresh")
		}

		channelTag := jobDescription.ChannelTag()

		accountStream, ok := result.accountStreams[channelTag]

		if !ok {
			var err error

			accountStream, err = gotelemetry.NewBatchStream(credentials, channelTag, submissionInterval, errorChannel)

			if err != nil {
				return nil, err
			}

			result.accountStreams[channelTag] = accountStream
		}

		job, err := createJob(result, credentials, accountStream, errorChannel, jobDescription, result.jobCompletionChannel, false)

		if err != nil {
			return nil, err
		}

		if err := result.addJob(job); err != nil {
			return nil, err
		}
	}

	if len(result.jobs) == 0 {
		errorChannel <- gotelemetry.NewLogError("No jobs are being scheduled.")
		return nil, nil
	}

	go result.monitorDoneChannel()

	return result, nil
}