diff --git a/deploy/openshift/templates/che-monitoring.yaml b/deploy/openshift/templates/che-monitoring.yaml
index 3ea3d166e7b..5a84960f93e 100644
--- a/deploy/openshift/templates/che-monitoring.yaml
+++ b/deploy/openshift/templates/che-monitoring.yaml
@@ -3964,6 +3964,7 @@ objects:
"linewidth": 1,
"links": [],
"nullPointMode": "null",
+ "paceLength": 10,
"percentage": false,
"pointradius": 5,
"points": false,
@@ -4049,6 +4050,7 @@ objects:
"linewidth": 1,
"links": [],
"nullPointMode": "null",
+ "paceLength": 10,
"percentage": false,
"pointradius": 5,
"points": false,
@@ -4134,6 +4136,7 @@ objects:
"linewidth": 1,
"links": [],
"nullPointMode": "null",
+ "paceLength": 10,
"percentage": false,
"pointradius": 5,
"points": false,
@@ -4193,13 +4196,107 @@ objects:
"alignLevel": null
}
},
+ {
+ "aliasColors": {},
+ "bars": false,
+ "dashLength": 10,
+ "dashes": false,
+ "datasource": "Che",
+ "description": "",
+ "fill": 1,
+ "gridPos": {
+ "h": 5,
+ "w": 11,
+ "x": 0,
+ "y": 6
+ },
+ "id": 36,
+ "interval": "",
+ "legend": {
+ "avg": true,
+ "current": true,
+ "max": true,
+ "min": true,
+ "show": true,
+ "total": false,
+ "values": true
+ },
+ "lines": true,
+ "linewidth": 1,
+ "links": [],
+ "nullPointMode": "null as zero",
+ "paceLength": 10,
+ "percentage": false,
+ "pointradius": 2,
+ "points": false,
+ "renderer": "flot",
+ "seriesOverrides": [],
+ "stack": true,
+ "steppedLine": false,
+ "targets": [
+ {
+ "expr": "sum(increase(che_workspace_failure_total{while=\"STARTING\"} [1h])) /(sum(increase(che_workspace_failure_total{while=\"STARTING\"} [1h])) + sum(increase(che_workspace_started_total [1h])))",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "fail",
+ "refId": "A"
+ },
+ {
+ "expr": "sum(increase(che_workspace_started_total [1h]))/(sum(increase(che_workspace_failure_total{while=\"STARTING\"} [1h])) + sum(increase(che_workspace_started_total [1h])))",
+ "format": "time_series",
+ "intervalFactor": 1,
+ "legendFormat": "success",
+ "refId": "B"
+ }
+ ],
+ "thresholds": [],
+ "timeFrom": null,
+ "timeRegions": [],
+ "timeShift": null,
+ "title": "Workspace start rate",
+ "tooltip": {
+ "shared": true,
+ "sort": 0,
+ "value_type": "individual"
+ },
+ "type": "graph",
+ "xaxis": {
+ "buckets": null,
+ "mode": "time",
+ "name": null,
+ "show": true,
+ "values": []
+ },
+ "yaxes": [
+ {
+ "format": "percentunit",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": true
+ },
+ {
+ "format": "short",
+ "label": null,
+ "logBase": 1,
+ "max": null,
+ "min": null,
+ "show": false
+ }
+ ],
+ "yaxis": {
+ "align": false,
+ "alignLevel": null
+ }
+ },
{
"collapsed": false,
"gridPos": {
"h": 1,
"w": 24,
"x": 0,
- "y": 6
+ "y": 11
},
"id": 24,
"panels": [],
@@ -4217,7 +4314,7 @@ objects:
"h": 7,
"w": 11,
"x": 0,
- "y": 7
+ "y": 12
},
"id": 16,
"legend": {
@@ -4233,6 +4330,7 @@ objects:
"linewidth": 1,
"links": [],
"nullPointMode": "null",
+ "paceLength": 10,
"percentage": false,
"pointradius": 5,
"points": false,
@@ -4298,7 +4396,7 @@ objects:
"h": 1,
"w": 24,
"x": 0,
- "y": 14
+ "y": 19
},
"id": 22,
"panels": [],
@@ -4316,7 +4414,7 @@ objects:
"h": 7,
"w": 9,
"x": 0,
- "y": 15
+ "y": 20
},
"id": 18,
"legend": {
@@ -4333,6 +4431,7 @@ objects:
"linewidth": 1,
"links": [],
"nullPointMode": "null as zero",
+ "paceLength": 10,
"percentage": false,
"pointradius": 5,
"points": false,
@@ -4427,7 +4526,7 @@ objects:
"h": 7,
"w": 7,
"x": 9,
- "y": 15
+ "y": 20
},
"id": 26,
"legend": {
@@ -4444,6 +4543,7 @@ objects:
"linewidth": 1,
"links": [],
"nullPointMode": "null as zero",
+ "paceLength": 10,
"percentage": false,
"pointradius": 5,
"points": false,
@@ -4523,7 +4623,7 @@ objects:
"h": 7,
"w": 7,
"x": 16,
- "y": 15
+ "y": 20
},
"id": 32,
"legend": {
@@ -4542,6 +4642,7 @@ objects:
"linewidth": 1,
"links": [],
"nullPointMode": "null",
+ "paceLength": 10,
"percentage": false,
"pointradius": 5,
"points": false,
@@ -4621,7 +4722,7 @@ objects:
"h": 8,
"w": 9,
"x": 0,
- "y": 22
+ "y": 27
},
"id": 30,
"legend": {
@@ -4637,6 +4738,7 @@ objects:
"linewidth": 1,
"links": [],
"nullPointMode": "null as zero",
+ "paceLength": 10,
"percentage": false,
"pointradius": 5,
"points": false,
@@ -4713,7 +4815,7 @@ objects:
"h": 8,
"w": 7,
"x": 9,
- "y": 22
+ "y": 27
},
"id": 34,
"legend": {
@@ -4729,6 +4831,7 @@ objects:
"linewidth": 1,
"links": [],
"nullPointMode": "null as zero",
+ "paceLength": 10,
"percentage": false,
"pointradius": 5,
"points": false,
@@ -4807,7 +4910,7 @@ objects:
"h": 8,
"w": 7,
"x": 16,
- "y": 22
+ "y": 27
},
"id": 28,
"legend": {
@@ -4823,6 +4926,7 @@ objects:
"linewidth": 1,
"links": [],
"nullPointMode": "null as zero",
+ "paceLength": 10,
"percentage": false,
"pointradius": 5,
"points": false,
@@ -4892,14 +4996,14 @@ objects:
}
],
"refresh": "5s",
- "schemaVersion": 16,
+ "schemaVersion": 18,
"style": "dark",
"tags": [],
"templating": {
"list": []
},
"time": {
- "from": "now-5m",
+ "from": "now-1h",
"to": "now"
},
"timepicker": {
diff --git a/wsmaster/che-core-api-metrics/pom.xml b/wsmaster/che-core-api-metrics/pom.xml
index 716e4c65445..b9960e18753 100644
--- a/wsmaster/che-core-api-metrics/pom.xml
+++ b/wsmaster/che-core-api-metrics/pom.xml
@@ -51,6 +51,11 @@
org.eclipse.che.core
che-core-api-workspace-shared
+
+ ch.qos.logback
+ logback-classic
+ test
+
org.eclipse.che.core
che-core-api-dto
diff --git a/wsmaster/che-core-api-metrics/src/main/java/org/eclipse/che/api/metrics/WorkspaceStartAttemptsMeterBinder.java b/wsmaster/che-core-api-metrics/src/main/java/org/eclipse/che/api/metrics/WorkspaceStartAttemptsMeterBinder.java
new file mode 100644
index 00000000000..20995e91c10
--- /dev/null
+++ b/wsmaster/che-core-api-metrics/src/main/java/org/eclipse/che/api/metrics/WorkspaceStartAttemptsMeterBinder.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2012-2018 Red Hat, Inc.
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ */
+package org.eclipse.che.api.metrics;
+
+import static org.eclipse.che.api.metrics.WorkspaceBinders.workspaceMetric;
+
+import com.google.inject.Inject;
+import io.micrometer.core.instrument.Counter;
+import io.micrometer.core.instrument.MeterRegistry;
+import io.micrometer.core.instrument.binder.MeterBinder;
+import javax.inject.Singleton;
+import org.eclipse.che.api.core.model.workspace.WorkspaceStatus;
+import org.eclipse.che.api.core.notification.EventService;
+import org.eclipse.che.api.workspace.shared.dto.event.WorkspaceStatusEvent;
+
+/** Counts number of attempts to start workspace. */
+@Singleton
+public class WorkspaceStartAttemptsMeterBinder implements MeterBinder {
+ private final EventService eventService;
+
+ private Counter startingCounter;
+
+ @Inject
+ public WorkspaceStartAttemptsMeterBinder(EventService eventService) {
+ this.eventService = eventService;
+ }
+
+ @Override
+ public void bindTo(MeterRegistry registry) {
+ startingCounter =
+ Counter.builder(workspaceMetric("starting_attempts.total"))
+ .description("The count of workspaces start attempts")
+ .register(registry);
+
+ // only subscribe to the event once we have the counters ready
+ eventService.subscribe(
+ event -> {
+ if (event.getPrevStatus() == WorkspaceStatus.STOPPED
+ && event.getStatus() == WorkspaceStatus.STARTING) {
+ startingCounter.increment();
+ }
+ },
+ WorkspaceStatusEvent.class);
+ }
+}
diff --git a/wsmaster/che-core-api-metrics/src/main/java/org/eclipse/che/api/metrics/WorkspaceSuccessfulStartAttemptsMeterBinder.java b/wsmaster/che-core-api-metrics/src/main/java/org/eclipse/che/api/metrics/WorkspaceSuccessfulStartAttemptsMeterBinder.java
new file mode 100644
index 00000000000..6ca70db5ee2
--- /dev/null
+++ b/wsmaster/che-core-api-metrics/src/main/java/org/eclipse/che/api/metrics/WorkspaceSuccessfulStartAttemptsMeterBinder.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2012-2018 Red Hat, Inc.
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ */
+package org.eclipse.che.api.metrics;
+
+import static org.eclipse.che.api.metrics.WorkspaceBinders.workspaceMetric;
+
+import com.google.inject.Inject;
+import io.micrometer.core.instrument.Counter;
+import io.micrometer.core.instrument.MeterRegistry;
+import io.micrometer.core.instrument.binder.MeterBinder;
+import javax.inject.Singleton;
+import org.eclipse.che.api.core.model.workspace.WorkspaceStatus;
+import org.eclipse.che.api.core.notification.EventService;
+import org.eclipse.che.api.workspace.shared.dto.event.WorkspaceStatusEvent;
+
+/** Counts number of successfully started workspaces. */
+@Singleton
+public class WorkspaceSuccessfulStartAttemptsMeterBinder implements MeterBinder {
+ private final EventService eventService;
+
+ private Counter startedCounter;
+
+ @Inject
+ public WorkspaceSuccessfulStartAttemptsMeterBinder(EventService eventService) {
+ this.eventService = eventService;
+ }
+
+ @Override
+ public void bindTo(MeterRegistry registry) {
+ startedCounter =
+ Counter.builder(workspaceMetric("started.total"))
+ .description("The count of started workspaces")
+ .register(registry);
+
+ // only subscribe to the event once we have the counters ready
+ eventService.subscribe(
+ event -> {
+ if (event.getPrevStatus() == WorkspaceStatus.STARTING
+ && event.getStatus() == WorkspaceStatus.RUNNING) {
+ startedCounter.increment();
+ }
+ },
+ WorkspaceStatusEvent.class);
+ }
+}
diff --git a/wsmaster/che-core-api-metrics/src/main/java/org/eclipse/che/api/metrics/WsMasterMetricsModule.java b/wsmaster/che-core-api-metrics/src/main/java/org/eclipse/che/api/metrics/WsMasterMetricsModule.java
index 502fea2baea..3c5d2c7f832 100644
--- a/wsmaster/che-core-api-metrics/src/main/java/org/eclipse/che/api/metrics/WsMasterMetricsModule.java
+++ b/wsmaster/che-core-api-metrics/src/main/java/org/eclipse/che/api/metrics/WsMasterMetricsModule.java
@@ -28,5 +28,7 @@ protected void configure() {
meterMultibinder.addBinding().to(WorkspaceActivityMeterBinder.class);
meterMultibinder.addBinding().to(WorkspaceFailureMeterBinder.class);
+ meterMultibinder.addBinding().to(WorkspaceSuccessfulStartAttemptsMeterBinder.class);
+ meterMultibinder.addBinding().to(WorkspaceStartAttemptsMeterBinder.class);
}
}
diff --git a/wsmaster/che-core-api-metrics/src/test/java/org/eclipse/che/api/metrics/WorkspaceStartAttemptsMeterBinderTest.java b/wsmaster/che-core-api-metrics/src/test/java/org/eclipse/che/api/metrics/WorkspaceStartAttemptsMeterBinderTest.java
new file mode 100644
index 00000000000..5696aab4f97
--- /dev/null
+++ b/wsmaster/che-core-api-metrics/src/test/java/org/eclipse/che/api/metrics/WorkspaceStartAttemptsMeterBinderTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2012-2018 Red Hat, Inc.
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ */
+package org.eclipse.che.api.metrics;
+
+import static java.util.Arrays.asList;
+
+import io.micrometer.core.instrument.Counter;
+import io.micrometer.core.instrument.MeterRegistry;
+import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
+import java.util.ArrayList;
+import java.util.List;
+import org.eclipse.che.api.core.model.workspace.WorkspaceStatus;
+import org.eclipse.che.api.core.notification.EventService;
+import org.eclipse.che.api.workspace.shared.dto.event.WorkspaceStatusEvent;
+import org.eclipse.che.dto.server.DtoFactory;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+public class WorkspaceStartAttemptsMeterBinderTest {
+
+ private EventService eventService;
+ private MeterRegistry registry;
+
+ @BeforeMethod
+ public void setUp() {
+ eventService = new EventService();
+ registry = new SimpleMeterRegistry();
+ }
+
+ @Test(dataProvider = "allStatusTransitionsWithoutStarting")
+ public void shouldNotCollectEvents(WorkspaceStatus from, WorkspaceStatus to) {
+ // given
+ WorkspaceStartAttemptsMeterBinder meterBinder =
+ new WorkspaceStartAttemptsMeterBinder(eventService);
+ meterBinder.bindTo(registry);
+
+ // when
+
+ eventService.publish(
+ DtoFactory.newDto(WorkspaceStatusEvent.class)
+ .withPrevStatus(from)
+ .withStatus(to)
+ .withWorkspaceId("id1"));
+
+ // then
+ Counter successful = registry.find("che.workspace.starting_attempts.total").counter();
+ Assert.assertEquals(successful.count(), 0.0);
+ }
+
+ @Test
+ public void shouldCollectOnlyStart() {
+ // given
+ WorkspaceStartAttemptsMeterBinder meterBinder =
+ new WorkspaceStartAttemptsMeterBinder(eventService);
+ meterBinder.bindTo(registry);
+
+ // when
+ eventService.publish(
+ DtoFactory.newDto(WorkspaceStatusEvent.class)
+ .withPrevStatus(WorkspaceStatus.STOPPED)
+ .withStatus(WorkspaceStatus.STARTING)
+ .withWorkspaceId("id1"));
+ // then
+ Counter successful = registry.find("che.workspace.starting_attempts.total").counter();
+ Assert.assertEquals(successful.count(), 1.0);
+ }
+
+ @DataProvider
+ public Object[][] allStatusTransitionsWithoutStarting() {
+ List> transitions = new ArrayList<>(9);
+
+ for (WorkspaceStatus from : WorkspaceStatus.values()) {
+ for (WorkspaceStatus to : WorkspaceStatus.values()) {
+ if (from == WorkspaceStatus.STOPPED && to == WorkspaceStatus.STARTING) {
+ continue;
+ }
+
+ transitions.add(asList(from, to));
+ }
+ }
+
+ return transitions.stream().map(List::toArray).toArray(Object[][]::new);
+ }
+}
diff --git a/wsmaster/che-core-api-metrics/src/test/java/org/eclipse/che/api/metrics/WorkspaceSuccessfulStartAttemptsMeterBinderTest.java b/wsmaster/che-core-api-metrics/src/test/java/org/eclipse/che/api/metrics/WorkspaceSuccessfulStartAttemptsMeterBinderTest.java
new file mode 100644
index 00000000000..8c55c045b6e
--- /dev/null
+++ b/wsmaster/che-core-api-metrics/src/test/java/org/eclipse/che/api/metrics/WorkspaceSuccessfulStartAttemptsMeterBinderTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2012-2018 Red Hat, Inc.
+ * This program and the accompanying materials are made
+ * available under the terms of the Eclipse Public License 2.0
+ * which is available at https://www.eclipse.org/legal/epl-2.0/
+ *
+ * SPDX-License-Identifier: EPL-2.0
+ *
+ * Contributors:
+ * Red Hat, Inc. - initial API and implementation
+ */
+package org.eclipse.che.api.metrics;
+
+import static java.util.Arrays.asList;
+
+import io.micrometer.core.instrument.Counter;
+import io.micrometer.core.instrument.MeterRegistry;
+import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
+import java.util.ArrayList;
+import java.util.List;
+import org.eclipse.che.api.core.model.workspace.WorkspaceStatus;
+import org.eclipse.che.api.core.notification.EventService;
+import org.eclipse.che.api.workspace.shared.dto.event.WorkspaceStatusEvent;
+import org.eclipse.che.dto.server.DtoFactory;
+import org.testng.Assert;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+public class WorkspaceSuccessfulStartAttemptsMeterBinderTest {
+
+ private EventService eventService;
+ private MeterRegistry registry;
+
+ @BeforeMethod
+ public void setUp() {
+ eventService = new EventService();
+ registry = new SimpleMeterRegistry();
+ }
+
+ @Test(dataProvider = "allStatusTransitionsWithoutRunning")
+ public void shouldNotCollectEvents(WorkspaceStatus from, WorkspaceStatus to) {
+ // given
+ WorkspaceSuccessfulStartAttemptsMeterBinder meterBinder =
+ new WorkspaceSuccessfulStartAttemptsMeterBinder(eventService);
+ meterBinder.bindTo(registry);
+
+ // when
+
+ eventService.publish(
+ DtoFactory.newDto(WorkspaceStatusEvent.class)
+ .withPrevStatus(from)
+ .withStatus(to)
+ .withWorkspaceId("id1"));
+
+ // then
+ Counter successful = registry.find("che.workspace.started.total").counter();
+ Assert.assertEquals(successful.count(), 0.0);
+ }
+
+ @Test
+ public void shouldCollectOnlyStarted() {
+ // given
+ WorkspaceSuccessfulStartAttemptsMeterBinder meterBinder =
+ new WorkspaceSuccessfulStartAttemptsMeterBinder(eventService);
+ meterBinder.bindTo(registry);
+
+ // when
+ eventService.publish(
+ DtoFactory.newDto(WorkspaceStatusEvent.class)
+ .withPrevStatus(WorkspaceStatus.STARTING)
+ .withStatus(WorkspaceStatus.RUNNING)
+ .withWorkspaceId("id1"));
+ // then
+ Counter successful = registry.find("che.workspace.started.total").counter();
+ Assert.assertEquals(successful.count(), 1.0);
+ }
+
+ @DataProvider
+ public Object[][] allStatusTransitionsWithoutRunning() {
+ List> transitions = new ArrayList<>(9);
+
+ for (WorkspaceStatus from : WorkspaceStatus.values()) {
+ for (WorkspaceStatus to : WorkspaceStatus.values()) {
+ if (from == WorkspaceStatus.STARTING && to == WorkspaceStatus.RUNNING) {
+ continue;
+ }
+
+ transitions.add(asList(from, to));
+ }
+ }
+
+ return transitions.stream().map(List::toArray).toArray(Object[][]::new);
+ }
+}
diff --git a/wsmaster/che-core-api-metrics/src/test/resources/logback-test.xml b/wsmaster/che-core-api-metrics/src/test/resources/logback-test.xml
new file mode 100644
index 00000000000..e6abf05f024
--- /dev/null
+++ b/wsmaster/che-core-api-metrics/src/test/resources/logback-test.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+ %-41(%date[%.15thread]) %-45([%-5level] [%.30logger{30} %L]) - %msg%n
+
+
+
+
+
+
+
+