Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(484)

Side by Side Diff: components/metrics/stability_metrics_helper.cc

Issue 1366643002: Extract guts of ChromeStabilityMetricsProvider into helper class (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase Created 5 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/metrics/chrome_stability_metrics_provider.h" 5 #include "components/metrics/stability_metrics_helper.h"
6 6
7 #include <vector> 7 #include <vector>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/metrics/histogram.h" 10 #include "base/metrics/histogram.h"
11 #include "base/metrics/sparse_histogram.h" 11 #include "base/metrics/sparse_histogram.h"
12 #include "base/prefs/pref_registry_simple.h" 12 #include "base/prefs/pref_registry_simple.h"
13 #include "base/prefs/pref_service.h" 13 #include "base/prefs/pref_service.h"
14 #include "chrome/browser/chrome_notification_types.h" 14 #include "components/metrics/metrics_pref_names.h"
15 #include "chrome/common/chrome_constants.h"
16 #include "chrome/common/pref_names.h"
17 #include "components/metrics/proto/system_profile.pb.h" 15 #include "components/metrics/proto/system_profile.pb.h"
18 #include "content/public/browser/child_process_data.h"
19 #include "content/public/browser/notification_service.h"
20 #include "content/public/browser/render_process_host.h"
21 #include "content/public/browser/user_metrics.h"
22 #include "content/public/browser/web_contents.h"
23
24 #if defined(ENABLE_EXTENSIONS)
25 #include "extensions/browser/process_map.h"
26 #endif
27
28 #if defined(ENABLE_PLUGINS)
29 #include "chrome/browser/metrics/plugin_metrics_provider.h"
30 #endif
31 16
32 #if defined(OS_WIN) 17 #if defined(OS_WIN)
33 #include <windows.h> // Needed for STATUS_* codes 18 #include <windows.h> // Needed for STATUS_* codes
34 #include "chrome/installer/util/install_util.h"
35 #include "components/browser_watcher/crash_reporting_metrics_win.h"
36 #endif 19 #endif
37 20
38 #if defined(OS_CHROMEOS) 21 #if defined(OS_CHROMEOS)
39 #include "chrome/browser/memory/system_memory_stats_recorder.h" 22 #include "components/metrics/system_memory_stats_recorder.h"
40 #endif 23 #endif
41 24
25 namespace metrics {
26
42 namespace { 27 namespace {
43 28
44 enum RendererType { 29 enum RendererType {
45 RENDERER_TYPE_RENDERER = 1, 30 RENDERER_TYPE_RENDERER = 1,
46 RENDERER_TYPE_EXTENSION, 31 RENDERER_TYPE_EXTENSION,
47 // NOTE: Add new action types only immediately above this line. Also, 32 // NOTE: Add new action types only immediately above this line. Also,
48 // make sure the enum list in tools/metrics/histograms/histograms.xml is 33 // make sure the enum list in tools/metrics/histograms/histograms.xml is
49 // updated with any change in here. 34 // updated with any change in here.
50 RENDERER_TYPE_COUNT 35 RENDERER_TYPE_COUNT
51 }; 36 };
52 37
53 // Converts an exit code into something that can be inserted into our 38 // Converts an exit code into something that can be inserted into our
54 // histograms (which expect non-negative numbers less than MAX_INT). 39 // histograms (which expect non-negative numbers less than MAX_INT).
55 int MapCrashExitCodeForHistogram(int exit_code) { 40 int MapCrashExitCodeForHistogram(int exit_code) {
56 #if defined(OS_WIN) 41 #if defined(OS_WIN)
57 // Since |abs(STATUS_GUARD_PAGE_VIOLATION) == MAX_INT| it causes problems in 42 // Since |abs(STATUS_GUARD_PAGE_VIOLATION) == MAX_INT| it causes problems in
58 // histograms.cc. Solve this by remapping it to a smaller value, which 43 // histograms.cc. Solve this by remapping it to a smaller value, which
59 // hopefully doesn't conflict with other codes. 44 // hopefully doesn't conflict with other codes.
60 if (exit_code == STATUS_GUARD_PAGE_VIOLATION) 45 if (exit_code == STATUS_GUARD_PAGE_VIOLATION)
61 return 0x1FCF7EC3; // Randomly picked number. 46 return 0x1FCF7EC3; // Randomly picked number.
62 #endif 47 #endif
63 48
64 return std::abs(exit_code); 49 return std::abs(exit_code);
65 } 50 }
66 51
67 #if defined(OS_WIN)
68 void CountBrowserCrashDumpAttempts() {
69 enum Outcome {
70 OUTCOME_SUCCESS,
71 OUTCOME_FAILURE,
72 OUTCOME_UNKNOWN,
73 OUTCOME_MAX_VALUE
74 };
75
76 browser_watcher::CrashReportingMetrics::Values metrics =
77 browser_watcher::CrashReportingMetrics(
78 InstallUtil::IsChromeSxSProcess()
79 ? chrome::kBrowserCrashDumpAttemptsRegistryPathSxS
80 : chrome::kBrowserCrashDumpAttemptsRegistryPath)
81 .RetrieveAndResetMetrics();
82
83 for (int i = 0; i < metrics.crash_dump_attempts; ++i) {
84 Outcome outcome = OUTCOME_UNKNOWN;
85 if (i < metrics.successful_crash_dumps)
86 outcome = OUTCOME_SUCCESS;
87 else if (i < metrics.successful_crash_dumps + metrics.failed_crash_dumps)
88 outcome = OUTCOME_FAILURE;
89
90 UMA_STABILITY_HISTOGRAM_ENUMERATION("CrashReport.BreakpadCrashDumpOutcome",
91 outcome, OUTCOME_MAX_VALUE);
92 }
93
94 for (int i = 0; i < metrics.dump_without_crash_attempts; ++i) {
95 Outcome outcome = OUTCOME_UNKNOWN;
96 if (i < metrics.successful_dumps_without_crash) {
97 outcome = OUTCOME_SUCCESS;
98 } else if (i < metrics.successful_dumps_without_crash +
99 metrics.failed_dumps_without_crash) {
100 outcome = OUTCOME_FAILURE;
101 }
102
103 UMA_STABILITY_HISTOGRAM_ENUMERATION(
104 "CrashReport.BreakpadDumpWithoutCrashOutcome", outcome,
105 OUTCOME_MAX_VALUE);
106 }
107 }
108 #endif // defined(OS_WIN)
109
110 void RecordChildKills(int histogram_type) { 52 void RecordChildKills(int histogram_type) {
111 UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.ChildKills", 53 UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.ChildKills",
112 histogram_type, RENDERER_TYPE_COUNT); 54 histogram_type, RENDERER_TYPE_COUNT);
113 } 55 }
114 56
115 } // namespace 57 } // namespace
116 58
117 ChromeStabilityMetricsProvider::ChromeStabilityMetricsProvider( 59 StabilityMetricsHelper::StabilityMetricsHelper(PrefService* local_state)
118 PrefService* local_state)
119 : local_state_(local_state) { 60 : local_state_(local_state) {
120 DCHECK(local_state_); 61 DCHECK(local_state_);
121 BrowserChildProcessObserver::Add(this);
122 } 62 }
123 63
124 ChromeStabilityMetricsProvider::~ChromeStabilityMetricsProvider() { 64 StabilityMetricsHelper::~StabilityMetricsHelper() {}
125 BrowserChildProcessObserver::Remove(this);
126 }
127 65
128 void ChromeStabilityMetricsProvider::OnRecordingEnabled() { 66 void StabilityMetricsHelper::ProvideStabilityMetrics(
129 registrar_.Add(this, 67 SystemProfileProto* system_profile_proto) {
130 content::NOTIFICATION_LOAD_START, 68 SystemProfileProto_Stability* stability_proto =
131 content::NotificationService::AllSources());
132 registrar_.Add(this,
133 content::NOTIFICATION_RENDERER_PROCESS_CLOSED,
134 content::NotificationService::AllSources());
135 registrar_.Add(this,
136 content::NOTIFICATION_RENDER_WIDGET_HOST_HANG,
137 content::NotificationService::AllSources());
138 }
139
140 void ChromeStabilityMetricsProvider::OnRecordingDisabled() {
141 registrar_.RemoveAll();
142 }
143
144 void ChromeStabilityMetricsProvider::ProvideStabilityMetrics(
145 metrics::SystemProfileProto* system_profile_proto) {
146 metrics::SystemProfileProto_Stability* stability_proto =
147 system_profile_proto->mutable_stability(); 69 system_profile_proto->mutable_stability();
148 70
149 int count = local_state_->GetInteger(prefs::kStabilityPageLoadCount); 71 int count = local_state_->GetInteger(prefs::kStabilityPageLoadCount);
150 if (count) { 72 if (count) {
151 stability_proto->set_page_load_count(count); 73 stability_proto->set_page_load_count(count);
152 local_state_->SetInteger(prefs::kStabilityPageLoadCount, 0); 74 local_state_->SetInteger(prefs::kStabilityPageLoadCount, 0);
153 } 75 }
154 76
155 count = local_state_->GetInteger(prefs::kStabilityChildProcessCrashCount); 77 count = local_state_->GetInteger(prefs::kStabilityChildProcessCrashCount);
156 if (count) { 78 if (count) {
(...skipping 26 matching lines...) Expand all
183 stability_proto->set_extension_renderer_failed_launch_count(count); 105 stability_proto->set_extension_renderer_failed_launch_count(count);
184 local_state_->SetInteger( 106 local_state_->SetInteger(
185 prefs::kStabilityExtensionRendererFailedLaunchCount, 0); 107 prefs::kStabilityExtensionRendererFailedLaunchCount, 0);
186 } 108 }
187 109
188 count = local_state_->GetInteger(prefs::kStabilityRendererHangCount); 110 count = local_state_->GetInteger(prefs::kStabilityRendererHangCount);
189 if (count) { 111 if (count) {
190 stability_proto->set_renderer_hang_count(count); 112 stability_proto->set_renderer_hang_count(count);
191 local_state_->SetInteger(prefs::kStabilityRendererHangCount, 0); 113 local_state_->SetInteger(prefs::kStabilityRendererHangCount, 0);
192 } 114 }
193
194 #if defined(OS_WIN)
195 CountBrowserCrashDumpAttempts();
196 #endif // defined(OS_WIN)
197 } 115 }
198 116
199 void ChromeStabilityMetricsProvider::ClearSavedStabilityMetrics() { 117 void StabilityMetricsHelper::ClearSavedStabilityMetrics() {
200 // Clear all the prefs used in this class in UMA reports (which doesn't 118 // Clear all the prefs used in this class in UMA reports (which doesn't
201 // include |kUninstallMetricsPageLoadCount| as it's not sent up by UMA). 119 // include |kUninstallMetricsPageLoadCount| as it's not sent up by UMA).
202 local_state_->SetInteger(prefs::kStabilityChildProcessCrashCount, 0); 120 local_state_->SetInteger(prefs::kStabilityChildProcessCrashCount, 0);
203 local_state_->SetInteger(prefs::kStabilityExtensionRendererCrashCount, 0); 121 local_state_->SetInteger(prefs::kStabilityExtensionRendererCrashCount, 0);
204 local_state_->SetInteger(prefs::kStabilityExtensionRendererFailedLaunchCount, 122 local_state_->SetInteger(prefs::kStabilityExtensionRendererFailedLaunchCount,
205 0); 123 0);
206 local_state_->SetInteger(prefs::kStabilityPageLoadCount, 0); 124 local_state_->SetInteger(prefs::kStabilityPageLoadCount, 0);
207 local_state_->SetInteger(prefs::kStabilityRendererCrashCount, 0); 125 local_state_->SetInteger(prefs::kStabilityRendererCrashCount, 0);
208 local_state_->SetInteger(prefs::kStabilityRendererFailedLaunchCount, 0); 126 local_state_->SetInteger(prefs::kStabilityRendererFailedLaunchCount, 0);
209 local_state_->SetInteger(prefs::kStabilityRendererHangCount, 0); 127 local_state_->SetInteger(prefs::kStabilityRendererHangCount, 0);
210 } 128 }
211 129
212 // static 130 // static
213 void ChromeStabilityMetricsProvider::RegisterPrefs( 131 void StabilityMetricsHelper::RegisterPrefs(PrefRegistrySimple* registry) {
214 PrefRegistrySimple* registry) {
215 registry->RegisterIntegerPref(prefs::kStabilityChildProcessCrashCount, 0); 132 registry->RegisterIntegerPref(prefs::kStabilityChildProcessCrashCount, 0);
216 registry->RegisterIntegerPref(prefs::kStabilityExtensionRendererCrashCount, 133 registry->RegisterIntegerPref(prefs::kStabilityExtensionRendererCrashCount,
217 0); 134 0);
218 registry->RegisterIntegerPref( 135 registry->RegisterIntegerPref(
219 prefs::kStabilityExtensionRendererFailedLaunchCount, 0); 136 prefs::kStabilityExtensionRendererFailedLaunchCount, 0);
220 registry->RegisterIntegerPref(prefs::kStabilityPageLoadCount, 0); 137 registry->RegisterIntegerPref(prefs::kStabilityPageLoadCount, 0);
221 registry->RegisterIntegerPref(prefs::kStabilityRendererCrashCount, 0); 138 registry->RegisterIntegerPref(prefs::kStabilityRendererCrashCount, 0);
222 registry->RegisterIntegerPref(prefs::kStabilityRendererFailedLaunchCount, 0); 139 registry->RegisterIntegerPref(prefs::kStabilityRendererFailedLaunchCount, 0);
223 registry->RegisterIntegerPref(prefs::kStabilityRendererHangCount, 0); 140 registry->RegisterIntegerPref(prefs::kStabilityRendererHangCount, 0);
224 141
225 registry->RegisterInt64Pref(prefs::kUninstallMetricsPageLoadCount, 0); 142 registry->RegisterInt64Pref(prefs::kUninstallMetricsPageLoadCount, 0);
226 } 143 }
227 144
228 void ChromeStabilityMetricsProvider::Observe( 145 void StabilityMetricsHelper::BrowserChildProcessCrashed() {
229 int type,
230 const content::NotificationSource& source,
231 const content::NotificationDetails& details) {
232 switch (type) {
233 case content::NOTIFICATION_LOAD_START: {
234 content::NavigationController* controller =
235 content::Source<content::NavigationController>(source).ptr();
236 content::WebContents* web_contents = controller->GetWebContents();
237 LogLoadStarted(web_contents);
238 break;
239 }
240
241 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: {
242 content::RenderProcessHost::RendererClosedDetails* process_details =
243 content::Details<content::RenderProcessHost::RendererClosedDetails>(
244 details).ptr();
245 content::RenderProcessHost* host =
246 content::Source<content::RenderProcessHost>(source).ptr();
247 LogRendererCrash(
248 host, process_details->status, process_details->exit_code);
249 break;
250 }
251
252 case content::NOTIFICATION_RENDER_WIDGET_HOST_HANG:
253 LogRendererHang();
254 break;
255
256 default:
257 NOTREACHED();
258 break;
259 }
260 }
261
262 void ChromeStabilityMetricsProvider::BrowserChildProcessCrashed(
263 const content::ChildProcessData& data,
264 int exit_code) {
265 #if defined(ENABLE_PLUGINS)
266 // Exclude plugin crashes from the count below because we report them via
267 // a separate UMA metric.
268 if (PluginMetricsProvider::IsPluginProcess(data.process_type))
269 return;
270 #endif
271
272 IncrementPrefValue(prefs::kStabilityChildProcessCrashCount); 146 IncrementPrefValue(prefs::kStabilityChildProcessCrashCount);
273 } 147 }
274 148
275 void ChromeStabilityMetricsProvider::LogLoadStarted( 149 void StabilityMetricsHelper::LogLoadStarted() {
276 content::WebContents* web_contents) { 150 base::RecordAction(base::UserMetricsAction("PageLoad"));
277 content::RecordAction(base::UserMetricsAction("PageLoad"));
278 // TODO(asvitkine): Check if this is used for anything and if not, remove. 151 // TODO(asvitkine): Check if this is used for anything and if not, remove.
279 LOCAL_HISTOGRAM_BOOLEAN("Chrome.UmaPageloadCounter", true); 152 LOCAL_HISTOGRAM_BOOLEAN("Chrome.UmaPageloadCounter", true);
280 IncrementPrefValue(prefs::kStabilityPageLoadCount); 153 IncrementPrefValue(prefs::kStabilityPageLoadCount);
281 IncrementLongPrefsValue(prefs::kUninstallMetricsPageLoadCount); 154 IncrementLongPrefsValue(prefs::kUninstallMetricsPageLoadCount);
282 // We need to save the prefs, as page load count is a critical stat, and it 155 // We need to save the prefs, as page load count is a critical stat, and it
283 // might be lost due to a crash :-(. 156 // might be lost due to a crash :-(.
284 } 157 }
285 158
286 void ChromeStabilityMetricsProvider::LogRendererCrash( 159 void StabilityMetricsHelper::LogRendererCrash(bool was_extension_process,
287 content::RenderProcessHost* host, 160 base::TerminationStatus status,
288 base::TerminationStatus status, 161 int exit_code) {
289 int exit_code) { 162 int histogram_type =
290 int histogram_type = RENDERER_TYPE_RENDERER; 163 was_extension_process ? RENDERER_TYPE_EXTENSION : RENDERER_TYPE_RENDERER;
291 bool was_extension_process = false;
292 #if defined(ENABLE_EXTENSIONS)
293 if (extensions::ProcessMap::Get(host->GetBrowserContext())
294 ->Contains(host->GetID())) {
295 histogram_type = RENDERER_TYPE_EXTENSION;
296 was_extension_process = true;
297 }
298 #endif
299 if (status == base::TERMINATION_STATUS_PROCESS_CRASHED || 164 if (status == base::TERMINATION_STATUS_PROCESS_CRASHED ||
300 status == base::TERMINATION_STATUS_ABNORMAL_TERMINATION) { 165 status == base::TERMINATION_STATUS_ABNORMAL_TERMINATION) {
301 if (was_extension_process) { 166 if (was_extension_process) {
302 IncrementPrefValue(prefs::kStabilityExtensionRendererCrashCount); 167 IncrementPrefValue(prefs::kStabilityExtensionRendererCrashCount);
303 168
304 UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Extension", 169 UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Extension",
305 MapCrashExitCodeForHistogram(exit_code)); 170 MapCrashExitCodeForHistogram(exit_code));
306 } else { 171 } else {
307 IncrementPrefValue(prefs::kStabilityRendererCrashCount); 172 IncrementPrefValue(prefs::kStabilityRendererCrashCount);
308 173
309 UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Renderer", 174 UMA_HISTOGRAM_SPARSE_SLOWLY("CrashExitCodes.Renderer",
310 MapCrashExitCodeForHistogram(exit_code)); 175 MapCrashExitCodeForHistogram(exit_code));
311 } 176 }
312 177
313 UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.ChildCrashes", 178 UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.ChildCrashes",
314 histogram_type, RENDERER_TYPE_COUNT); 179 histogram_type, RENDERER_TYPE_COUNT);
315 } else if (status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED) { 180 } else if (status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED) {
316 RecordChildKills(histogram_type); 181 RecordChildKills(histogram_type);
317 #if defined(OS_CHROMEOS) 182 #if defined(OS_CHROMEOS)
318 } else if (status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM) { 183 } else if (status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM) {
319 RecordChildKills(histogram_type); 184 RecordChildKills(histogram_type);
320 UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.ChildKills.OOM", 185 UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.ChildKills.OOM",
321 was_extension_process ? 2 : 1, 186 was_extension_process ? 2 : 1, 3);
322 3); 187 RecordMemoryStats(was_extension_process
323 memory::RecordMemoryStats( 188 ? RECORD_MEMORY_STATS_EXTENSIONS_OOM_KILLED
324 was_extension_process 189 : RECORD_MEMORY_STATS_CONTENTS_OOM_KILLED);
325 ? memory::RECORD_MEMORY_STATS_EXTENSIONS_OOM_KILLED
326 : memory::RECORD_MEMORY_STATS_CONTENTS_OOM_KILLED);
327 #endif 190 #endif
328 } else if (status == base::TERMINATION_STATUS_STILL_RUNNING) { 191 } else if (status == base::TERMINATION_STATUS_STILL_RUNNING) {
329 UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.DisconnectedAlive", 192 UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.DisconnectedAlive",
330 histogram_type, RENDERER_TYPE_COUNT); 193 histogram_type, RENDERER_TYPE_COUNT);
331 } else if (status == base::TERMINATION_STATUS_LAUNCH_FAILED) { 194 } else if (status == base::TERMINATION_STATUS_LAUNCH_FAILED) {
332 UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.ChildLaunchFailures", 195 UMA_HISTOGRAM_ENUMERATION("BrowserRenderProcessHost.ChildLaunchFailures",
333 histogram_type, RENDERER_TYPE_COUNT); 196 histogram_type, RENDERER_TYPE_COUNT);
334 if (was_extension_process) 197 if (was_extension_process)
335 IncrementPrefValue(prefs::kStabilityExtensionRendererFailedLaunchCount); 198 IncrementPrefValue(prefs::kStabilityExtensionRendererFailedLaunchCount);
336 else 199 else
337 IncrementPrefValue(prefs::kStabilityRendererFailedLaunchCount); 200 IncrementPrefValue(prefs::kStabilityRendererFailedLaunchCount);
338 } 201 }
339 } 202 }
340 203
341 void ChromeStabilityMetricsProvider::IncrementPrefValue(const char* path) { 204 void StabilityMetricsHelper::IncrementPrefValue(const char* path) {
342 int value = local_state_->GetInteger(path); 205 int value = local_state_->GetInteger(path);
343 local_state_->SetInteger(path, value + 1); 206 local_state_->SetInteger(path, value + 1);
344 } 207 }
345 208
346 void ChromeStabilityMetricsProvider::IncrementLongPrefsValue(const char* path) { 209 void StabilityMetricsHelper::IncrementLongPrefsValue(const char* path) {
347 int64 value = local_state_->GetInt64(path); 210 int64 value = local_state_->GetInt64(path);
348 local_state_->SetInt64(path, value + 1); 211 local_state_->SetInt64(path, value + 1);
349 } 212 }
350 213
351 void ChromeStabilityMetricsProvider::LogRendererHang() { 214 void StabilityMetricsHelper::LogRendererHang() {
352 IncrementPrefValue(prefs::kStabilityRendererHangCount); 215 IncrementPrefValue(prefs::kStabilityRendererHangCount);
353 } 216 }
217
218 } // namespace metrics
OLDNEW
« no previous file with comments | « components/metrics/stability_metrics_helper.h ('k') | components/metrics/stability_metrics_helper_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698