@@ -50,12 +50,14 @@ data Metric
50
50
| Metric
51
51
{ mName :: ! Text
52
52
, mType :: ! Text
53
- , mValue :: ! Number
53
+ , mLabel :: ! (Maybe Text )
54
+ , mNumber :: ! Number
54
55
}
55
56
56
57
instance A. ToJSON Metric where
57
58
toJSON NoMetric = A. Null
58
- toJSON (Metric n t v) = A. object [" name" .= n, " type" .= t, " value" .= v]
59
+ toJSON (Metric n t Nothing v) = A. object [" name" .= n, " type" .= t, " value" .= v]
60
+ toJSON (Metric n t (Just l) v) = A. object [" name" .= n, " type" .= t, " label" .= l, " value" .= v]
59
61
60
62
data Number
61
63
= NumberInt Integer
@@ -94,17 +96,29 @@ spawnPrometheus ekg host port prometheusOutput = Async.async $
94
96
[ case sv of
95
97
Counter c -> renderNamedValue sk (int64Dec c)
96
98
Gauge g -> renderNamedValue sk (int64Dec g)
97
- Label l -> if isFloat l
98
- then renderNamedValue sk (byteString $ encodeUtf8 l)
99
- else mempty
99
+ Label l -> if " {" `T.isPrefixOf` l
100
+ then renderLabel sk l
101
+ else if (isFloat l)
102
+ then renderNamedValue sk (byteString $ encodeUtf8 l)
103
+ else mempty
100
104
_ -> mempty
101
105
| (sk,sv) <- samples ]
106
+
102
107
renderNamedValue :: Text -> Builder -> Builder
103
108
renderNamedValue nm bld =
104
109
(byteString $ prepareName nm)
105
110
<> charUtf8 ' '
106
111
<> bld
107
112
<> charUtf8 ' \n '
113
+
114
+ renderLabel :: Text -> Text -> Builder
115
+ renderLabel nm l =
116
+ (byteString $ prepareName nm)
117
+ <> charUtf8 ' '
118
+ <> byteString (textToUtf8ByteString l)
119
+ <> charUtf8 ' '
120
+ <> charUtf8 ' 1'
121
+ <> charUtf8 ' \n '
108
122
prepareName nm = encodeUtf8 $ T. filter (flip elem ([' a' .. ' z' ]++ [' A' .. ' Z' ]++ [' _' ])) $ T. replace " " " _" $ T. replace " -" " _" $ T. replace " ." " _" nm
109
123
isFloat v = case double v of
110
124
Right (_n, " " ) -> True -- only floating point number parsed, no leftover
@@ -136,7 +150,8 @@ spawnPrometheus ekg host port prometheusOutput = Async.async $
136
150
intMetric sk v =
137
151
Metric { mName = maybe " " id $ T. stripPrefix (ns <> " ." ) sk
138
152
, mType = " int" -- All values are Int64.
139
- , mValue = NumberInt (fromIntegral v)
153
+ , mLabel = Nothing
154
+ , mNumber = NumberInt (fromIntegral v)
140
155
}
141
156
142
157
-- We cannot make any assumptions about the format of 'sk' in other samples,
@@ -146,26 +161,34 @@ spawnPrometheus ekg host port prometheusOutput = Async.async $
146
161
{ namespace = " common"
147
162
, metrics =
148
163
[ case sv of
149
- Counter c -> mkMetric sk $ NumberInt (fromIntegral c)
150
- Gauge g -> mkMetric sk $ NumberInt (fromIntegral g)
164
+ Counter c -> mkMetric sk Nothing $ NumberInt (fromIntegral c)
165
+ Gauge g -> mkMetric sk Nothing $ NumberInt (fromIntegral g)
151
166
Label l -> case double l of
152
- Left _ -> NoMetric
153
- Right (r, _) -> mkMetric sk $ NumberReal r
167
+ Right (r, _) ->
168
+ mkMetric sk Nothing $ NumberReal r
169
+ Left _ ->
170
+ case T. uncons l of
171
+ Just (' {' , _) -> mkMetric sk (Just l) (NumberInt 1 )
172
+ _ -> NoMetric
154
173
_ -> NoMetric
155
174
| (sk, sv) <- samples
156
175
]
157
176
}
158
177
where
159
- mkMetric sk number =
178
+ mkMetric sk condTxt number =
160
179
let (withoutType, typeSuffix) = stripTypeSuffix sk number
161
- in Metric { mName = withoutType, mType = typeSuffix, mValue = number }
180
+ in Metric { mName = withoutType, mType = typeSuffix, mLabel = condTxt, mNumber = number }
162
181
stripTypeSuffix sk number =
163
182
let types = [" us" , " ns" , " s" , " B" , " int" , " real" ]
164
183
parts = T. splitOn " ." sk
165
184
typeSuffix = if not . null $ parts then last parts else " "
166
185
in if typeSuffix `elem` types
167
186
then (fromJust $ T. stripSuffix (" ." <> typeSuffix) sk, typeSuffix)
168
187
else case number of
169
- NumberInt _ -> (sk, " int" )
170
- NumberReal _ -> (sk, " real" )
188
+ NumberInt _ -> (sk, " int" )
189
+ NumberReal _ -> (sk, " real" )
190
+
191
+ textToUtf8ByteString :: Text -> ByteString
192
+ textToUtf8ByteString txt = encodeUtf8 txt
193
+
171
194
\end {code}
0 commit comments