Sfoglia il codice sorgente

Add extra prometheus metrics
- buildsTriggered
- buildsFailed
- valid options:
metricsDockerfileSyntaxError,
metricsDockerfileEmptyError,
metricsCommandNotSupportedError,
metricsErrorProcessingCommandsError,
metricsBuildTargetNotReachableError,
metricsMissingOnbuildArgumentsError,
metricsUnknownInstructionError,
metricsBuildCanceled,
- engineInfo

Signed-off-by: Roberto Gandolfo Hashioka <roberto_hashioka@hotmail.com>

Roberto Gandolfo Hashioka 8 anni fa
parent
commit
a28b173a78

+ 5 - 0
builder/dockerfile/builder.go

@@ -49,6 +49,7 @@ func NewBuildManager(b builder.Backend) *BuildManager {
 
 
 // Build starts a new build from a BuildConfig
 // Build starts a new build from a BuildConfig
 func (bm *BuildManager) Build(ctx context.Context, config backend.BuildConfig) (*builder.Result, error) {
 func (bm *BuildManager) Build(ctx context.Context, config backend.BuildConfig) (*builder.Result, error) {
+	buildsTriggered.Inc()
 	if config.Options.Dockerfile == "" {
 	if config.Options.Dockerfile == "" {
 		config.Options.Dockerfile = builder.DefaultDockerfileName
 		config.Options.Dockerfile = builder.DefaultDockerfileName
 	}
 	}
@@ -141,6 +142,7 @@ func (b *Builder) build(source builder.Source, dockerfile *parser.Result) (*buil
 	addNodesForLabelOption(dockerfile.AST, b.options.Labels)
 	addNodesForLabelOption(dockerfile.AST, b.options.Labels)
 
 
 	if err := checkDispatchDockerfile(dockerfile.AST); err != nil {
 	if err := checkDispatchDockerfile(dockerfile.AST); err != nil {
+		buildsFailed.WithValues(metricsDockerfileSyntaxError).Inc()
 		return nil, err
 		return nil, err
 	}
 	}
 
 
@@ -150,12 +152,14 @@ func (b *Builder) build(source builder.Source, dockerfile *parser.Result) (*buil
 	}
 	}
 
 
 	if b.options.Target != "" && !dispatchState.isCurrentStage(b.options.Target) {
 	if b.options.Target != "" && !dispatchState.isCurrentStage(b.options.Target) {
+		buildsFailed.WithValues(metricsBuildTargetNotReachableError).Inc()
 		return nil, errors.Errorf("failed to reach build target %s in Dockerfile", b.options.Target)
 		return nil, errors.Errorf("failed to reach build target %s in Dockerfile", b.options.Target)
 	}
 	}
 
 
 	b.warnOnUnusedBuildArgs()
 	b.warnOnUnusedBuildArgs()
 
 
 	if dispatchState.imageID == "" {
 	if dispatchState.imageID == "" {
+		buildsFailed.WithValues(metricsDockerfileEmptyError).Inc()
 		return nil, errors.New("No image was generated. Is your Dockerfile empty?")
 		return nil, errors.New("No image was generated. Is your Dockerfile empty?")
 	}
 	}
 	return &builder.Result{ImageID: dispatchState.imageID, FromImage: dispatchState.baseImage}, nil
 	return &builder.Result{ImageID: dispatchState.imageID, FromImage: dispatchState.baseImage}, nil
@@ -171,6 +175,7 @@ func (b *Builder) dispatchDockerfileWithCancellation(dockerfile *parser.Result)
 		case <-b.clientCtx.Done():
 		case <-b.clientCtx.Done():
 			logrus.Debug("Builder: build cancelled!")
 			logrus.Debug("Builder: build cancelled!")
 			fmt.Fprint(b.Stdout, "Build cancelled")
 			fmt.Fprint(b.Stdout, "Build cancelled")
+			buildsFailed.WithValues(metricsBuildCanceled).Inc()
 			return nil, errors.New("Build cancelled")
 			return nil, errors.New("Build cancelled")
 		default:
 		default:
 			// Not cancelled yet, keep going...
 			// Not cancelled yet, keep going...

+ 5 - 1
builder/dockerfile/evaluator.go

@@ -134,6 +134,7 @@ func (b *Builder) dispatch(options dispatchOptions) (*dispatchState, error) {
 	// To ensure the user is given a decent error message if the platform
 	// To ensure the user is given a decent error message if the platform
 	// on which the daemon is running does not support a builder command.
 	// on which the daemon is running does not support a builder command.
 	if err := platformSupports(strings.ToLower(cmd)); err != nil {
 	if err := platformSupports(strings.ToLower(cmd)); err != nil {
+		buildsFailed.WithValues(metricsCommandNotSupportedError).Inc()
 		return nil, err
 		return nil, err
 	}
 	}
 
 
@@ -155,6 +156,7 @@ func (b *Builder) dispatch(options dispatchOptions) (*dispatchState, error) {
 	processFunc := createProcessWordFunc(options.shlex, cmd, envs)
 	processFunc := createProcessWordFunc(options.shlex, cmd, envs)
 	words, err := getDispatchArgsFromNode(ast, processFunc, msg)
 	words, err := getDispatchArgsFromNode(ast, processFunc, msg)
 	if err != nil {
 	if err != nil {
+		buildsFailed.WithValues(metricsErrorProcessingCommandsError).Inc()
 		return nil, err
 		return nil, err
 	}
 	}
 	args = append(args, words...)
 	args = append(args, words...)
@@ -163,6 +165,7 @@ func (b *Builder) dispatch(options dispatchOptions) (*dispatchState, error) {
 
 
 	f, ok := evaluateTable[cmd]
 	f, ok := evaluateTable[cmd]
 	if !ok {
 	if !ok {
+		buildsFailed.WithValues(metricsUnknownInstructionError).Inc()
 		return nil, fmt.Errorf("unknown instruction: %s", upperCasedCmd)
 		return nil, fmt.Errorf("unknown instruction: %s", upperCasedCmd)
 	}
 	}
 	if err := f(newDispatchRequestFromOptions(options, b, args)); err != nil {
 	if err := f(newDispatchRequestFromOptions(options, b, args)); err != nil {
@@ -283,6 +286,7 @@ func checkDispatch(ast *parser.Node) error {
 	// least one argument
 	// least one argument
 	if upperCasedCmd == "ONBUILD" {
 	if upperCasedCmd == "ONBUILD" {
 		if ast.Next == nil {
 		if ast.Next == nil {
+			buildsFailed.WithValues(metricsMissingOnbuildArgumentsError).Inc()
 			return errors.New("ONBUILD requires at least one argument")
 			return errors.New("ONBUILD requires at least one argument")
 		}
 		}
 	}
 	}
@@ -290,6 +294,6 @@ func checkDispatch(ast *parser.Node) error {
 	if _, ok := evaluateTable[cmd]; ok {
 	if _, ok := evaluateTable[cmd]; ok {
 		return nil
 		return nil
 	}
 	}
-
+	buildsFailed.WithValues(metricsUnknownInstructionError).Inc()
 	return errors.Errorf("unknown instruction: %s", upperCasedCmd)
 	return errors.Errorf("unknown instruction: %s", upperCasedCmd)
 }
 }

+ 44 - 0
builder/dockerfile/metrics.go

@@ -0,0 +1,44 @@
+package dockerfile
+
+import (
+	"github.com/docker/go-metrics"
+)
+
+var (
+	buildsTriggered metrics.Counter
+	buildsFailed    metrics.LabeledCounter
+)
+
+// Build metrics prometheus messages, these values must be initialized before
+// using them. See the example below in the "builds_failed" metric definition.
+const (
+	metricsDockerfileSyntaxError        = "dockerfile_syntax_error"
+	metricsDockerfileEmptyError         = "dockerfile_empty_error"
+	metricsCommandNotSupportedError     = "command_not_supported_error"
+	metricsErrorProcessingCommandsError = "error_processing_commands_error"
+	metricsBuildTargetNotReachableError = "build_target_not_reachable_error"
+	metricsMissingOnbuildArgumentsError = "missing_onbuild_arguments_error"
+	metricsUnknownInstructionError      = "unknown_instruction_error"
+	metricsBuildCanceled                = "build_canceled"
+)
+
+func init() {
+	buildMetrics := metrics.NewNamespace("builder", "", nil)
+
+	buildsTriggered = buildMetrics.NewCounter("builds_triggered", "Number of triggered image builds")
+	buildsFailed = buildMetrics.NewLabeledCounter("builds_failed", "Number of failed image builds", "reason")
+	for _, r := range []string{
+		metricsDockerfileSyntaxError,
+		metricsDockerfileEmptyError,
+		metricsCommandNotSupportedError,
+		metricsErrorProcessingCommandsError,
+		metricsBuildTargetNotReachableError,
+		metricsMissingOnbuildArgumentsError,
+		metricsUnknownInstructionError,
+		metricsBuildCanceled,
+	} {
+		buildsFailed.WithValues(r)
+	}
+
+	metrics.Register(buildMetrics)
+}

+ 3 - 1
daemon/daemon.go

@@ -731,13 +731,15 @@ func NewDaemon(config *config.Config, registryService registry.Service, containe
 	// FIXME: this method never returns an error
 	// FIXME: this method never returns an error
 	info, _ := d.SystemInfo()
 	info, _ := d.SystemInfo()
 
 
-	engineVersion.WithValues(
+	engineInfo.WithValues(
 		dockerversion.Version,
 		dockerversion.Version,
 		dockerversion.GitCommit,
 		dockerversion.GitCommit,
 		info.Architecture,
 		info.Architecture,
 		info.Driver,
 		info.Driver,
 		info.KernelVersion,
 		info.KernelVersion,
 		info.OperatingSystem,
 		info.OperatingSystem,
+		info.OSType,
+		info.ID,
 	).Set(1)
 	).Set(1)
 	engineCpus.Set(float64(info.NCPU))
 	engineCpus.Set(float64(info.NCPU))
 	engineMemory.Set(float64(info.MemTotal))
 	engineMemory.Set(float64(info.MemTotal))

+ 6 - 4
daemon/metrics.go

@@ -6,7 +6,7 @@ var (
 	containerActions          metrics.LabeledTimer
 	containerActions          metrics.LabeledTimer
 	imageActions              metrics.LabeledTimer
 	imageActions              metrics.LabeledTimer
 	networkActions            metrics.LabeledTimer
 	networkActions            metrics.LabeledTimer
-	engineVersion             metrics.LabeledGauge
+	engineInfo                metrics.LabeledGauge
 	engineCpus                metrics.Gauge
 	engineCpus                metrics.Gauge
 	engineMemory              metrics.Gauge
 	engineMemory              metrics.Gauge
 	healthChecksCounter       metrics.Counter
 	healthChecksCounter       metrics.Counter
@@ -26,12 +26,14 @@ func init() {
 		containerActions.WithValues(a).Update(0)
 		containerActions.WithValues(a).Update(0)
 	}
 	}
 	networkActions = ns.NewLabeledTimer("network_actions", "The number of seconds it takes to process each network action", "action")
 	networkActions = ns.NewLabeledTimer("network_actions", "The number of seconds it takes to process each network action", "action")
-	engineVersion = ns.NewLabeledGauge("engine", "The version and commit information for the engine process", metrics.Unit("info"),
+	engineInfo = ns.NewLabeledGauge("engine", "The information related to the engine and the OS it is running on", metrics.Unit("info"),
 		"version",
 		"version",
 		"commit",
 		"commit",
 		"architecture",
 		"architecture",
-		"graph_driver", "kernel",
-		"os",
+		"graphdriver",
+		"kernel", "os",
+		"os_type",
+		"daemon_id", // ID is a randomly generated unique identifier (e.g. UUID4)
 	)
 	)
 	engineCpus = ns.NewGauge("engine_cpus", "The number of cpus that the host system of the engine has", metrics.Unit("cpus"))
 	engineCpus = ns.NewGauge("engine_cpus", "The number of cpus that the host system of the engine has", metrics.Unit("cpus"))
 	engineMemory = ns.NewGauge("engine_memory", "The number of bytes of memory that the host system of the engine has", metrics.Bytes)
 	engineMemory = ns.NewGauge("engine_memory", "The number of bytes of memory that the host system of the engine has", metrics.Bytes)