file_cmds-321.40.3.tar.gz
[apple/file_cmds.git] / mtree / metrics.c
1 /*
2 * Copyright (c) 2020 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include <stdlib.h>
25 #include <string.h>
26
27 #include "metrics.h"
28
29 #define MAX_WARNINGS_LOGGED 5
30 #define MAX_ERRORS_LOGGED 5
31 #define WARN_FIRST -1
32
33 #ifndef ROUNDUP
34 #define ROUNDUP(COUNT, MULTIPLE) ((((COUNT) + (MULTIPLE) - 1) / (MULTIPLE)) * (MULTIPLE))
35 #endif
36
37 typedef struct failure_info {
38 int location;
39 int code;
40 } failure_info_t;
41
42 typedef struct metrics {
43 FILE *file;
44 time_t start_time;
45 int warning_count;
46 failure_info_t warnings[MAX_WARNINGS_LOGGED];
47 int error_count;
48 failure_info_t errors[MAX_ERRORS_LOGGED];
49 int last_error_location;
50 char *path;
51 int result;
52 } metrics_t;
53 metrics_t metrics = {};
54
55 void
56 set_metrics_file(FILE *file)
57 {
58 metrics.file = file;
59 }
60
61 void
62 set_metric_start_time(time_t time)
63 {
64 metrics.start_time = time;
65 }
66
67 void
68 set_metric_path(char *path)
69 {
70 metrics.path = strdup(path);
71 }
72
73 void
74 mtree_record_failure(int location, int code)
75 {
76 if (code <= WARN_FIRST) {
77 if (metrics.warning_count < MAX_WARNINGS_LOGGED) {
78 metrics.warning_count++;
79 } else {
80 // Shift up the warnings to make space for the latest one.
81 for (int index = 0; index < MAX_ERRORS_LOGGED - 1; index++) {
82 metrics.warnings[index] = metrics.warnings[index + 1];
83 }
84 }
85 metrics.warnings[metrics.warning_count - 1].location = location;
86 metrics.warnings[metrics.warning_count - 1].code = code;
87 } else {
88 int error_index = -1;
89 if (metrics.error_count <= MAX_ERRORS_LOGGED) {
90 if (metrics.error_count > 0) {
91 // Log all but the last error which occured in the location and
92 // code arrays. The last (location, error) is logged in
93 // (metrics.last_error_location, metrics.error)
94 error_index = metrics.error_count - 1;
95 }
96 metrics.error_count++;
97 } else {
98 // Shift up the errors to make space for the latest one.
99 for (int index = 0; index < MAX_ERRORS_LOGGED - 1; index++) {
100 metrics.errors[index] = metrics.errors[index + 1];
101 }
102 error_index = MAX_ERRORS_LOGGED - 1;
103 }
104 if (error_index >= 0) {
105 metrics.errors[error_index].location = metrics.last_error_location;
106 metrics.errors[error_index].code = metrics.result;
107 }
108 metrics.last_error_location = location;
109 metrics.result = code;
110 }
111 }
112 /*
113 * Note on format of metric string
114 * 1) dev points to the path
115 * 2) result is the overall result code from mtree
116 * 3) warnings and errors (upto 5 each) are printed in the format :
117 * w:(location1:code1),(location2:code2).... and
118 * e:(location1:code1),(location2:code2).... respectively.
119 * 4) fl is the last failure location of the run which is 0 if there is no failure
120 * 5) time is the total time taken for the run
121 */
122 void
123 print_metrics_to_file(void)
124 {
125 if (metrics.file == NULL) {
126 return;
127 }
128
129 fprintf(metrics.file, "dev=%s result=%d ",
130 metrics.path ? metrics.path : "", metrics.result);
131 if (metrics.warning_count) {
132 fprintf(metrics.file, "w:");
133 for (int index = 0; index < metrics.warning_count; index++) {
134 fprintf(metrics.file, "(%d:%d)",
135 metrics.warnings[index].location, metrics.warnings[index].code);
136 }
137 fprintf(metrics.file, " ");
138 }
139 if (metrics.error_count > 1) {
140 fprintf(metrics.file, "e:");
141 for (int index = 0; index < metrics.error_count - 1; index++) {
142 fprintf(metrics.file, "(%d:%d)",
143 metrics.errors[index].location, metrics.errors[index].code);
144 }
145 fprintf(metrics.file, " ");
146 }
147 fprintf(metrics.file, "fl=%d time=%ld\n",
148 metrics.last_error_location, ROUNDUP((time(NULL) - metrics.start_time), 60) / 60);
149
150 fclose(metrics.file);
151 if (metrics.path) {
152 free(metrics.path);
153 metrics.path = NULL;
154 }
155 }