1 // Copyright 2018 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #pragma once
6 
7 #include <limits.h>
8 #include <stdint.h>
9 
10 #include <cobalt-client/cpp/counter-internal.h>
11 #include <cobalt-client/cpp/histogram-internal.h>
12 #include <cobalt-client/cpp/types-internal.h>
13 #include <fbl/string_buffer.h>
14 #include <lib/zx/channel.h>
15 #include <lib/zx/time.h>
16 #include <lib/zx/vmo.h>
17 #include <zircon/types.h>
18 
19 namespace cobalt_client {
20 namespace internal {
21 
22 struct CobaltOptions {
23     // Service path to LoggerFactory interface.
24     fbl::StringBuffer<PATH_MAX> service_path;
25 
26     // Maximum time to wait for Cobalt Service to respond for the CreateLogger request.
27     // Unless the channel is closed, we will keep checking if the channel is readable.
28     zx::duration logger_deadline;
29 
30     // The maximum time to wait, after the request has been written to the channel.
31     // This allows amortizing the wait time in future calls.
32     zx::duration logger_deadline_first_attempt;
33 
34     // Sets the input VMO to point to the serialized config for this logger and the size
35     // of the serialized data.
36     fbl::Function<bool(zx::vmo*, size_t*)> config_reader;
37 
38     // Performs a connection to a service at a given path.
39     fbl::Function<zx_status_t(const char* service_path, zx::channel service)> service_connect;
40 
41     // Which release stage to use for persisting metrics.
42     ReleaseStage release_stage;
43 };
44 
45 class CobaltLogger : public Logger {
46 public:
47     CobaltLogger() = delete;
48     explicit CobaltLogger(CobaltOptions options);
49     CobaltLogger(const CobaltLogger&) = delete;
50     CobaltLogger(CobaltLogger&&) = delete;
51     CobaltLogger& operator=(const CobaltLogger&) = delete;
52     CobaltLogger& operator=(CobaltLogger&&) = delete;
~CobaltLogger()53     ~CobaltLogger() override{};
54 
55     // Returns true if the histogram was persisted.
56     bool Log(const RemoteMetricInfo& metric_info, const HistogramBucket* buckets,
57              size_t bucket_count) override;
58 
59     // Returns true if the counter was persisted.
60     bool Log(const RemoteMetricInfo& metric_info, int64_t count) override;
61 
IsListeningForReply()62     bool IsListeningForReply() const { return logger_factory_.is_valid(); }
63 
64     // Blocks until the reply from LoggerFactory arrives into |logger_factory_|
65     // channel or the peer is closed. |observed| will be set to the observed signals
66     // if provided. Useful for testing to enforce a deterministic order of operations.
67     zx_status_t WaitForReply(zx_signals_t* observed = nullptr) const {
68         return zx_object_wait_one(logger_factory_.get(),
69                                   ZX_CHANNEL_READABLE | ZX_CHANNEL_PEER_CLOSED,
70                                   zx::time::infinite().get(), observed);
71     }
72 
73 protected:
74     // If returns true, a channel has been established with the endpoint,
75     // and the handshake to set up a logger started.
76     bool TrySendLoggerRequest();
77 
78     // The service replied and the status is ok.
79     bool HasCobaltReplied(zx::duration deadline);
80 
81     // Returns true if the logger request has been sent, and Cobalt Service
82     // replied successfully already. If any error happens that prevents
83     // writing to the current channel(ZX_ERR_PEER_CLOSED), we guarantee
84     // the next time this method is called will return false.
85     bool IsLoggerReady();
86 
87     // Set of options for this logger.
88     CobaltOptions options_;
89 
90     zx::channel logger_;
91     zx::channel logger_factory_;
92 
93     bool is_first_attempt_;
94 };
95 
96 } // namespace internal
97 } // namespace cobalt_client
98