1
#pragma once
2

            
3
#include <string>
4
#include <vector>
5

            
6
#include "absl/strings/numbers.h"
7
#include "absl/strings/str_cat.h"
8
#include "absl/strings/string_view.h"
9

            
10
namespace Envoy {
11
namespace Extensions {
12
namespace Tracers {
13
namespace OpenTelemetry {
14

            
15
class TraceCaptureReason {
16

            
17
  using Version = uint8_t;
18
  using PayloadBitMask = uint64_t;
19

            
20
  static const size_t MAX_PAYLOAD_SIZE = sizeof(Version) + sizeof(PayloadBitMask);
21
  static constexpr absl::string_view ATM = "atm";
22
  static constexpr absl::string_view FIXED = "fixed";
23
  static constexpr absl::string_view CUSTOM = "custom";
24
  static constexpr absl::string_view MAINFRAME = "mainframe";
25
  static constexpr absl::string_view SERVERLESS = "serverless";
26
  static constexpr absl::string_view RUM = "rum";
27
  static constexpr absl::string_view UNKNOWN = "unknown";
28

            
29
public:
30
  enum { InvalidVersion = 0u, Version1 = 1u };
31

            
32
  // Bit mask values
33
  enum Reason : PayloadBitMask {
34
    Undefined = 0ull,
35
    Atm = 1ull << 0,
36
    Fixed = 1ull << 1,
37
    Custom = 1ull << 2,
38
    Mainframe = 1ull << 3,
39
    Serverless = 1ull << 4,
40
    Rum = 1ull << 5,
41
  };
42

            
43
5
  static TraceCaptureReason createInvalid() { return {false, 0}; }
44

            
45
1395
  static TraceCaptureReason create(PayloadBitMask tcr_bitmask) { return {true, tcr_bitmask}; }
46

            
47
15
  static TraceCaptureReason create(const absl::string_view& payload_hex) {
48
15
    if (payload_hex.size() < 4 || payload_hex.size() % 2 != 0) {
49
      // At least 1 byte for version and 1 byte for bitmask (2 hex chars each)
50
3
      return createInvalid();
51
3
    }
52

            
53
    // validate the size of the payload
54
12
    size_t payload_bytes = payload_hex.size() / 2;
55
12
    if (payload_bytes <= sizeof(Version) || payload_bytes > MAX_PAYLOAD_SIZE) {
56
      return createInvalid();
57
    }
58

            
59
    // Parse version (first byte, 2 hex chars)
60
12
    uint32_t version = 0;
61
12
    if (!absl::SimpleHexAtoi(payload_hex.substr(0, 2), &version) ||
62
12
        version != TraceCaptureReason::Version1) {
63
1
      return createInvalid();
64
1
    }
65

            
66
11
    uint64_t bitmask = 0;
67
11
    if (!absl::SimpleHexAtoi(payload_hex.substr(2), &bitmask)) {
68
      return createInvalid();
69
    }
70

            
71
11
    constexpr PayloadBitMask kValidMask = Atm | Fixed | Custom | Mainframe | Serverless | Rum;
72
11
    if ((bitmask & ~kValidMask) != 0) {
73
1
      return createInvalid();
74
1
    }
75
10
    return create(bitmask);
76
11
  }
77

            
78
  // Returns true if parsing was successful.
79
2783
  bool isValid() const { return valid_; };
80

            
81
1392
  std::vector<absl::string_view> toSpanAttributeValue() const {
82
1392
    std::vector<absl::string_view> result;
83
1392
    if (tcr_bitmask_ & Atm) {
84
1389
      result.push_back(ATM);
85
1389
    }
86
1392
    if (tcr_bitmask_ & Fixed) {
87
5
      result.push_back(FIXED);
88
5
    }
89
1392
    if (tcr_bitmask_ & Custom) {
90
4
      result.push_back(CUSTOM);
91
4
    }
92
1392
    if (tcr_bitmask_ & Mainframe) {
93
      result.push_back(MAINFRAME);
94
    }
95
1392
    if (tcr_bitmask_ & Serverless) {
96
      result.push_back(SERVERLESS);
97
    }
98
1392
    if (tcr_bitmask_ & Rum) {
99
2
      result.push_back(RUM);
100
2
    }
101
1392
    if (result.empty()) {
102
      result.push_back(UNKNOWN);
103
    }
104
1392
    return result;
105
1392
  }
106

            
107
1392
  std::string bitmaskHex() const {
108
1392
    return absl::StrCat(absl::Hex(static_cast<uint8_t>(tcr_bitmask_), absl::kZeroPad2));
109
1392
  }
110

            
111
private:
112
  TraceCaptureReason(bool valid, PayloadBitMask tcr_bitmask)
113
1400
      : valid_(valid), tcr_bitmask_(tcr_bitmask) {}
114

            
115
  const bool valid_;
116
  const PayloadBitMask tcr_bitmask_;
117
};
118

            
119
} // namespace OpenTelemetry
120
} // namespace Tracers
121
} // namespace Extensions
122
} // namespace Envoy