1 
2 /**
3  *    Copyright (C) 2018-present MongoDB, Inc.
4  *
5  *    This program is free software: you can redistribute it and/or modify
6  *    it under the terms of the Server Side Public License, version 1,
7  *    as published by MongoDB, Inc.
8  *
9  *    This program is distributed in the hope that it will be useful,
10  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *    Server Side Public License for more details.
13  *
14  *    You should have received a copy of the Server Side Public License
15  *    along with this program. If not, see
16  *    <http://www.mongodb.com/licensing/server-side-public-license>.
17  *
18  *    As a special exception, the copyright holders give permission to link the
19  *    code of portions of this program with the OpenSSL library under certain
20  *    conditions as described in each individual source file and distribute
21  *    linked combinations including the program with the OpenSSL library. You
22  *    must comply with the Server Side Public License in all respects for
23  *    all of the code used other than as permitted herein. If you modify file(s)
24  *    with this exception, you may extend this exception to your version of the
25  *    file(s), but you are not obligated to do so. If you do not wish to do so,
26  *    delete this exception statement from your version. If you delete this
27  *    exception statement from all source files in the program, then also delete
28  *    it in the license file.
29  */
30 
31 #include "mongo/platform/basic.h"
32 
33 #include "mongo/db/ftdc/collector.h"
34 
35 #include "mongo/base/string_data.h"
36 #include "mongo/bson/bsonmisc.h"
37 #include "mongo/bson/bsonobjbuilder.h"
38 #include "mongo/db/client.h"
39 #include "mongo/db/ftdc/constants.h"
40 #include "mongo/db/ftdc/util.h"
41 #include "mongo/db/jsobj.h"
42 #include "mongo/db/operation_context.h"
43 #include "mongo/util/time_support.h"
44 
45 namespace mongo {
46 
add(std::unique_ptr<FTDCCollectorInterface> collector)47 void FTDCCollectorCollection::add(std::unique_ptr<FTDCCollectorInterface> collector) {
48     // TODO: ensure the collectors all have unique names.
49     _collectors.emplace_back(std::move(collector));
50 }
51 
collect(Client * client)52 std::tuple<BSONObj, Date_t> FTDCCollectorCollection::collect(Client* client) {
53     // If there are no collectors, just return an empty BSONObj so that that are caller knows we did
54     // not collect anything
55     if (_collectors.empty()) {
56         return std::tuple<BSONObj, Date_t>(BSONObj(), Date_t());
57     }
58 
59     BSONObjBuilder builder;
60 
61     Date_t start = client->getServiceContext()->getPreciseClockSource()->now();
62     Date_t end;
63     bool firstLoop = true;
64 
65     builder.appendDate(kFTDCCollectStartField, start);
66 
67     // All collectors should be ok seeing the inconsistent states in the middle of replication
68     // batches. This is desirable because we want to be able to collect data in the middle of
69     // batches that are taking a long time.
70     auto opCtx = client->makeOperationContext();
71     opCtx->lockState()->setShouldConflictWithSecondaryBatchApplication(false);
72     opCtx->lockState()->setShouldAcquireTicket(false);
73 
74     for (auto& collector : _collectors) {
75         BSONObjBuilder subObjBuilder(builder.subobjStart(collector->name()));
76 
77         // Add a Date_t before and after each BSON is collected so that we can track timing of the
78         // collector.
79         Date_t now = start;
80 
81         if (!firstLoop) {
82             now = client->getServiceContext()->getPreciseClockSource()->now();
83         }
84 
85         firstLoop = false;
86 
87         subObjBuilder.appendDate(kFTDCCollectStartField, now);
88 
89         collector->collect(opCtx.get(), subObjBuilder);
90 
91         end = client->getServiceContext()->getPreciseClockSource()->now();
92         subObjBuilder.appendDate(kFTDCCollectEndField, end);
93     }
94 
95     builder.appendDate(kFTDCCollectEndField, end);
96 
97     return std::tuple<BSONObj, Date_t>(builder.obj(), start);
98 }
99 
100 }  // namespace mongo
101