Skip to content

Commit

Permalink
lwc-events: support duration for default value (#1670)
Browse files Browse the repository at this point in the history
When wrapping timer events it can be useful for the default
value to be a duration for mapping to percentile timer type.
  • Loading branch information
brharrington authored Jun 23, 2024
1 parent d013537 commit bf81f55
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -85,16 +85,16 @@ private[events] object DatapointConverter {
case _ => event => toDouble(event.extractValue(k), event.value)
}
case None =>
event => event.value
event => toDouble(event.value, 1.0)
}
}

private def squared(value: Any, dflt: Double): Double = {
private def squared(value: Any, dflt: Any): Double = {
val v = toDouble(value, dflt)
v * v
}

private[events] def toDouble(value: Any, dflt: Double): Double = {
private[events] def toDouble(value: Any, dflt: Any): Double = {
value match {
case v: Boolean => if (v) 1.0 else 0.0
case v: Byte => v.toDouble
Expand All @@ -106,7 +106,7 @@ private[events] object DatapointConverter {
case v: Number => v.doubleValue()
case v: String => parseDouble(v)
case v: Duration => v.toNanos / 1e9
case _ => dflt
case _ => toDouble(dflt, 1.0)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ trait LwcEvent {
* Value to use for the event when mapping to a time series. By default it will be
* 1.0 same as incrementing a counter by 1.
*/
def value: Double = 1.0
def value: Any = 1.0

/**
* Extract a tag value for a given key. Returns `null` if there is no value for
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class DatapointConverterSuite extends FunSuite {
assertEquals(DatapointConverter.toDouble(Duration.ofMillis(42131), -1.0), 42.131)
assertEquals(DatapointConverter.toDouble(Duration.ofSeconds(42131), -1.0), 42131.0)
assertEquals(DatapointConverter.toDouble(Duration.ofMinutes(2), -1.0), 120.0)
assertEquals(DatapointConverter.toDouble(null, Duration.ofMillis(42)), 0.042)
assert(DatapointConverter.toDouble("foo", -1.0).isNaN)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/*
* Copyright 2014-2024 Netflix, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.netflix.atlas.lwc.events

import com.netflix.atlas.core.util.SortedTagMap
import munit.FunSuite

import java.lang.System.Logger
import java.time.Duration

class LwcEventDurationSuite extends FunSuite {

import LwcEventDurationSuite.*

private val sampleSpan: TestEvent = {
TestEvent(SortedTagMap("app" -> "www", "node" -> "i-123"), Duration.ofMillis(42))
}

private val sampleLwcEvent: LwcEvent = new TestSpan(sampleSpan)

test("tagValue: exists") {
assertEquals(sampleLwcEvent.tagValue("app"), "www")
assertEquals(sampleLwcEvent.tagValue("node"), "i-123")
}

test("tagValue: enum") {
assertEquals(sampleLwcEvent.tagValue("level"), "TRACE")
}

test("tagValue: missing") {
assertEquals(sampleLwcEvent.tagValue("foo"), null)
}

test("tagValue: wrong type") {
assertEquals(sampleLwcEvent.tagValue("duration"), null)
}

test("extractValue: exists") {
assertEquals(sampleLwcEvent.extractValue("app"), "www")
assertEquals(sampleLwcEvent.extractValue("node"), "i-123")
assertEquals(sampleLwcEvent.extractValue("duration"), Duration.ofMillis(42))
}

test("extractValue: missing") {
assertEquals(sampleLwcEvent.extractValue("foo"), null)
}

test("defautl value") {
assertEquals(sampleLwcEvent.value, Duration.ofMillis(42))
}

test("toJson: raw event") {
val expected = """{"tags":{"app":"www","node":"i-123"},"duration":42}"""
assertEquals(sampleLwcEvent.toJson, expected)
}

test("toJson: row no columns") {
val expected = """[]"""
assertEquals(sampleLwcEvent.toJson(List.empty), expected)
}

test("toJson: row nested object") {
val expected = """[42,{"app":"www","node":"i-123"}]"""
assertEquals(sampleLwcEvent.toJson(List("duration", "tags")), expected)
}

test("toJson: row simple") {
val expected = """[42,"www"]"""
assertEquals(sampleLwcEvent.toJson(List("duration", "app")), expected)
}
}

object LwcEventDurationSuite {

case class TestEvent(tags: Map[String, String], duration: Duration)

def extractSpanValue(span: TestEvent)(key: String): Any = {
key match {
case "tags" => span.tags
case "duration" => span.duration
case "level" => Logger.Level.TRACE
case k => span.tags.getOrElse(k, null)
}
}

class TestSpan(event: TestEvent) extends LwcEvent.Span {

override def spanId: String = "test"

override def parentId: String = "parent"

override def rawEvent: Any = event

override def timestamp: Long = 0L

override def value: Any = event.duration

override def extractValue(key: String): Any = {
extractSpanValue(event)(key)
}
}
}

0 comments on commit bf81f55

Please sign in to comment.