aboutsummaryrefslogtreecommitdiffstats
path: root/file_cmds/mtree/metrics.c
diff options
context:
space:
mode:
Diffstat (limited to 'file_cmds/mtree/metrics.c')
-rw-r--r--file_cmds/mtree/metrics.c155
1 files changed, 155 insertions, 0 deletions
diff --git a/file_cmds/mtree/metrics.c b/file_cmds/mtree/metrics.c
new file mode 100644
index 0000000..01a9fe2
--- /dev/null
+++ b/file_cmds/mtree/metrics.c
@@ -0,0 +1,155 @@
+/*
+* Copyright (c) 2020 Apple Inc. All rights reserved.
+*
+* @APPLE_LICENSE_HEADER_START@
+*
+* This file contains Original Code and/or Modifications of Original Code
+* as defined in and that are subject to the Apple Public Source License
+* Version 2.0 (the 'License'). You may not use this file except in
+* compliance with the License. Please obtain a copy of the License at
+* http://www.opensource.apple.com/apsl/ and read it before using this
+* file.
+*
+* The Original Code and all software distributed under the License are
+* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+* Please see the License for the specific language governing rights and
+* limitations under the License.
+*
+* @APPLE_LICENSE_HEADER_END@
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "metrics.h"
+
+#define MAX_WARNINGS_LOGGED 5
+#define MAX_ERRORS_LOGGED 5
+#define WARN_FIRST -1
+
+#ifndef ROUNDUP
+#define ROUNDUP(COUNT, MULTIPLE) ((((COUNT) + (MULTIPLE) - 1) / (MULTIPLE)) * (MULTIPLE))
+#endif
+
+typedef struct failure_info {
+ int location;
+ int code;
+} failure_info_t;
+
+typedef struct metrics {
+ FILE *file;
+ time_t start_time;
+ int warning_count;
+ failure_info_t warnings[MAX_WARNINGS_LOGGED];
+ int error_count;
+ failure_info_t errors[MAX_ERRORS_LOGGED];
+ int last_error_location;
+ char *path;
+ int result;
+} metrics_t;
+metrics_t metrics = {};
+
+void
+set_metrics_file(FILE *file)
+{
+ metrics.file = file;
+}
+
+void
+set_metric_start_time(time_t time)
+{
+ metrics.start_time = time;
+}
+
+void
+set_metric_path(char *path)
+{
+ metrics.path = strdup(path);
+}
+
+void
+mtree_record_failure(int location, int code)
+{
+ if (code <= WARN_FIRST) {
+ if (metrics.warning_count < MAX_WARNINGS_LOGGED) {
+ metrics.warning_count++;
+ } else {
+ // Shift up the warnings to make space for the latest one.
+ for (int index = 0; index < MAX_ERRORS_LOGGED - 1; index++) {
+ metrics.warnings[index] = metrics.warnings[index + 1];
+ }
+ }
+ metrics.warnings[metrics.warning_count - 1].location = location;
+ metrics.warnings[metrics.warning_count - 1].code = code;
+ } else {
+ int error_index = -1;
+ if (metrics.error_count <= MAX_ERRORS_LOGGED) {
+ if (metrics.error_count > 0) {
+ // Log all but the last error which occured in the location and
+ // code arrays. The last (location, error) is logged in
+ // (metrics.last_error_location, metrics.error)
+ error_index = metrics.error_count - 1;
+ }
+ metrics.error_count++;
+ } else {
+ // Shift up the errors to make space for the latest one.
+ for (int index = 0; index < MAX_ERRORS_LOGGED - 1; index++) {
+ metrics.errors[index] = metrics.errors[index + 1];
+ }
+ error_index = MAX_ERRORS_LOGGED - 1;
+ }
+ if (error_index >= 0) {
+ metrics.errors[error_index].location = metrics.last_error_location;
+ metrics.errors[error_index].code = metrics.result;
+ }
+ metrics.last_error_location = location;
+ metrics.result = code;
+ }
+}
+/*
+ * Note on format of metric string
+ * 1) dev points to the path
+ * 2) result is the overall result code from mtree
+ * 3) warnings and errors (upto 5 each) are printed in the format :
+ * w:(location1:code1),(location2:code2).... and
+ * e:(location1:code1),(location2:code2).... respectively.
+ * 4) fl is the last failure location of the run which is 0 if there is no failure
+ * 5) time is the total time taken for the run
+ */
+void
+print_metrics_to_file(void)
+{
+ if (metrics.file == NULL) {
+ return;
+ }
+
+ fprintf(metrics.file, "dev=%s result=%d ",
+ metrics.path ? metrics.path : "", metrics.result);
+ if (metrics.warning_count) {
+ fprintf(metrics.file, "w:");
+ for (int index = 0; index < metrics.warning_count; index++) {
+ fprintf(metrics.file, "(%d:%d)",
+ metrics.warnings[index].location, metrics.warnings[index].code);
+ }
+ fprintf(metrics.file, " ");
+ }
+ if (metrics.error_count > 1) {
+ fprintf(metrics.file, "e:");
+ for (int index = 0; index < metrics.error_count - 1; index++) {
+ fprintf(metrics.file, "(%d:%d)",
+ metrics.errors[index].location, metrics.errors[index].code);
+ }
+ fprintf(metrics.file, " ");
+ }
+ fprintf(metrics.file, "fl=%d time=%ld\n",
+ metrics.last_error_location, ROUNDUP((time(NULL) - metrics.start_time), 60) / 60);
+
+ fclose(metrics.file);
+ if (metrics.path) {
+ free(metrics.path);
+ metrics.path = NULL;
+ }
+}