1 /*
2  * Copyright (c) Facebook, Inc. and its affiliates.
3  *
4  * This source code is licensed under the MIT license found in the
5  * LICENSE file in the root directory of this source tree.
6  *
7  */
8 
9 #pragma once
10 #include <fstream>
11 #include <sstream>
12 
13 #include <folly/compression/Compression.h>
14 #include <folly/dynamic.h>
15 #include <folly/logging/AsyncFileWriter.h>
16 #include <quic/codec/Types.h>
17 #include <quic/logging/BaseQLogger.h>
18 #include <quic/logging/QLoggerConstants.h>
19 #include <quic/logging/QLoggerTypes.h>
20 
21 namespace quic {
22 
23 class FileQLogger : public BaseQLogger {
24   const static uint64_t kCompressionBufferSize = 1024; // 1 KB
25 
26  public:
27   inline const static std::string kQlogExtension = ".qlog";
28   inline const static std::string kCompressedQlogExtension = ".qlog.gz";
29 
30   using QLogger::TransportSummaryArgs;
31   std::vector<std::unique_ptr<QLogEvent>> logs;
32   FileQLogger(
33       VantagePoint vantagePointIn,
34       std::string protocolTypeIn = kHTTP3ProtocolType,
35       std::string path = "",
36       bool prettyJson = true,
37       bool streaming = false,
38       bool compress = false)
BaseQLogger(vantagePointIn,std::move (protocolTypeIn))39       : BaseQLogger(vantagePointIn, std::move(protocolTypeIn)),
40         path_(std::move(path)),
41         prettyJson_(prettyJson),
42         streaming_(streaming),
43         compress_{compress} {}
44 
~FileQLogger()45   ~FileQLogger() override {
46     if (streaming_ && dcid.hasValue()) {
47       finishStream();
48     }
49   }
50   void addPacket(const RegularQuicPacket& regularPacket, uint64_t packetSize)
51       override;
52   void addPacket(
53       const VersionNegotiationPacket& versionPacket,
54       uint64_t packetSize,
55       bool isPacketRecvd) override;
56   void addPacket(const RegularQuicWritePacket& writePacket, uint64_t packetSize)
57       override;
58   void addPacket(
59       const RetryPacket& retryPacket,
60       uint64_t packetSize,
61       bool isPacketRecvd) override;
62   void addConnectionClose(
63       std::string error,
64       std::string reason,
65       bool drainConnection,
66       bool sendCloseImmediately) override;
67   void addTransportSummary(const TransportSummaryArgs& args) override;
68   void addCongestionMetricUpdate(
69       uint64_t bytesInFlight,
70       uint64_t currentCwnd,
71       std::string congestionEvent,
72       std::string state = "",
73       std::string recoveryState = "") override;
74   void addPacingMetricUpdate(
75       uint64_t pacingBurstSizeIn,
76       std::chrono::microseconds pacingIntervalIn) override;
77   void addPacingObservation(
78       std::string actual,
79       std::string expected,
80       std::string conclusion) override;
81   void addBandwidthEstUpdate(uint64_t bytes, std::chrono::microseconds interval)
82       override;
83   void addAppLimitedUpdate() override;
84   void addAppUnlimitedUpdate() override;
85   void addAppIdleUpdate(std::string idleEvent, bool idle) override;
86   void addPacketDrop(size_t packetSize, std::string dropReasonIn) override;
87   void addDatagramReceived(uint64_t dataLen) override;
88   void addLossAlarm(
89       PacketNum largestSent,
90       uint64_t alarmCount,
91       uint64_t outstandingPackets,
92       std::string type) override;
93   void addPacketsLost(
94       PacketNum largestLostPacketNum,
95       uint64_t lostBytes,
96       uint64_t lostPackets) override;
97   void addTransportStateUpdate(std::string update) override;
98   void addPacketBuffered(ProtectionType protectionType, uint64_t packetSize)
99       override;
100   void addMetricUpdate(
101       std::chrono::microseconds latestRtt,
102       std::chrono::microseconds mrtt,
103       std::chrono::microseconds srtt,
104       std::chrono::microseconds ackDelay) override;
105   void addStreamStateUpdate(
106       StreamId id,
107       std::string update,
108       folly::Optional<std::chrono::milliseconds> timeSinceStreamCreation)
109       override;
110   virtual void addConnectionMigrationUpdate(bool intentionalMigration) override;
111   virtual void addPathValidationEvent(bool success) override;
112   void addPriorityUpdate(
113       quic::StreamId streamId,
114       uint8_t urgency,
115       bool incremental) override;
116 
117   void outputLogsToFile(const std::string& path, bool prettyJson);
118   folly::dynamic toDynamic() const;
119   folly::dynamic toDynamicBase() const;
120   folly::dynamic generateSummary(
121       size_t numEvents,
122       std::chrono::microseconds startTime,
123       std::chrono::microseconds endTime) const;
124 
125   void setDcid(folly::Optional<ConnectionId> connID) override;
126   void setScid(folly::Optional<ConnectionId> connID) override;
127 
128  private:
129   void setupStream();
130   void writeToStream(folly::StringPiece message);
131   void finishStream();
132   void handleEvent(std::unique_ptr<QLogEvent> event);
133 
134   std::unique_ptr<folly::AsyncFileWriter> writer_;
135   std::unique_ptr<folly::io::StreamCodec> compressionCodec_;
136   std::unique_ptr<folly::IOBuf> compressionBuffer_;
137 
138   std::string path_;
139   std::string basePadding_ = "  ";
140   std::string eventsPadding_ = "";
141   std::string eventLine_;
142   std::string token_;
143   std::string endLine_;
144   std::stringstream baseJson_;
145 
146   bool prettyJson_;
147   bool streaming_;
148   bool compress_;
149   int numEvents_ = 0;
150   std::chrono::microseconds startTime_ = std::chrono::microseconds::zero();
151   std::chrono::microseconds endTime_;
152 
153   size_t pos_;
154 };
155 } // namespace quic
156