diff --git a/cabal.project b/cabal.project index b441e019..f4082476 100644 --- a/cabal.project +++ b/cabal.project @@ -8,3 +8,4 @@ packages: nri-http/nri-http.cabal nri-postgresql/nri-postgresql.cabal nri-kafka/nri-kafka.cabal + nri-analytics/nri-analytics.cabal diff --git a/nri-analytics/CHANGELOG.md b/nri-analytics/CHANGELOG.md new file mode 100644 index 00000000..b8a470df --- /dev/null +++ b/nri-analytics/CHANGELOG.md @@ -0,0 +1,7 @@ +# 0.1.0.0 + +- Initial release. Provides `Analytics.handler`, `Analytics.silentHandler`, + `Analytics.Settings`, and `Analytics.decoder`. Sync HTTP POST delivery + to a configured events service URL with bearer auth, bounded timeout, + and log-and-drop on failure. Wire format is provisional pending the + events service contract. diff --git a/nri-analytics/LICENSE b/nri-analytics/LICENSE new file mode 100644 index 00000000..bd63ae7f --- /dev/null +++ b/nri-analytics/LICENSE @@ -0,0 +1,29 @@ +BSD 3-Clause License + +Copyright (c) 2024, NoRedInk +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/nri-analytics/README.md b/nri-analytics/README.md new file mode 100644 index 00000000..7a1ed537 --- /dev/null +++ b/nri-analytics/README.md @@ -0,0 +1,8 @@ +# nri-analytics + +Sync HTTP delivery of typed analytics events to the NoRedInk events service. + +This package is consumed by NoRedInk's monolith. It produces an +`AnalyticsHandler` whose `sendEvent` is wired into `nri-prelude`'s +`Platform.Analytics.Internal` callback at the application root. See the +companion design doc in `NoRedInk/event-platform/docs`. diff --git a/nri-analytics/nri-analytics.cabal b/nri-analytics/nri-analytics.cabal new file mode 100644 index 00000000..8e4ddc73 --- /dev/null +++ b/nri-analytics/nri-analytics.cabal @@ -0,0 +1,99 @@ +cabal-version: 1.18 + +-- This file has been generated from package.yaml by hpack version 0.37.0. +-- +-- see: https://github.com/sol/hpack + +name: nri-analytics +version: 0.1.0.0 +synopsis: Deliver typed analytics events to the NoRedInk events service. +description: Please see the README at . +category: Web +homepage: https://github.com/NoRedInk/haskell-libraries/tree/trunk/nri-analytics#readme +bug-reports: https://github.com/NoRedInk/haskell-libraries/issues +author: NoRedInk +maintainer: haskell-open-source@noredink.com +copyright: 2026 NoRedInk Corp. +license: BSD3 +license-file: LICENSE +build-type: Simple +extra-doc-files: + README.md + LICENSE + CHANGELOG.md + +source-repository head + type: git + location: https://github.com/NoRedInk/haskell-libraries + subdir: nri-analytics + +library + exposed-modules: + Analytics + other-modules: + Analytics.Internal + hs-source-dirs: + src + default-extensions: + DeriveGeneric + FlexibleInstances + GeneralizedNewtypeDeriving + NamedFieldPuns + NoImplicitPrelude + OverloadedStrings + PartialTypeSignatures + ScopedTypeVariables + Strict + ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wpartial-fields -Wredundant-constraints -Wincomplete-uni-patterns -fplugin=NriPrelude.Plugin + build-depends: + aeson >=2.0 && <2.3 + , base >=4.18 && <4.22 + , bytestring >=0.10.8.2 && <0.13 + , conduit >=1.3.0 && <1.4 + , http-client >=0.6.0 && <0.8 + , http-client-tls >=0.3.0 && <0.4 + , nri-env-parser >=0.1.0.0 && <0.5 + , nri-prelude >=0.7.0.0 && <0.8 + , safe-exceptions >=0.1.7.0 && <1.3 + , text >=1.2.3.1 && <2.2 + , time >=1.9.3 && <2 + , uuid ==1.3.* + default-language: Haskell2010 + +test-suite tests + type: exitcode-stdio-1.0 + main-is: Main.hs + other-modules: + Spec.Analytics + Analytics + Analytics.Internal + Paths_nri_analytics + hs-source-dirs: + tests + src + default-extensions: + DeriveGeneric + FlexibleInstances + GeneralizedNewtypeDeriving + NamedFieldPuns + NoImplicitPrelude + OverloadedStrings + PartialTypeSignatures + ScopedTypeVariables + Strict + ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wpartial-fields -Wredundant-constraints -Wincomplete-uni-patterns -fplugin=NriPrelude.Plugin -threaded + build-depends: + aeson >=2.0 && <2.3 + , base >=4.18 && <4.22 + , bytestring >=0.10.8.2 && <0.13 + , conduit >=1.3.0 && <1.4 + , http-client >=0.6.0 && <0.8 + , http-client-tls >=0.3.0 && <0.4 + , nri-analytics + , nri-env-parser >=0.1.0.0 && <0.5 + , nri-prelude >=0.7.0.0 && <0.8 + , safe-exceptions >=0.1.7.0 && <1.3 + , text >=1.2.3.1 && <2.2 + , time >=1.9.3 && <2 + , uuid ==1.3.* + default-language: Haskell2010 diff --git a/nri-analytics/package.yaml b/nri-analytics/package.yaml new file mode 100644 index 00000000..4705b70f --- /dev/null +++ b/nri-analytics/package.yaml @@ -0,0 +1,63 @@ +name: nri-analytics +synopsis: Deliver typed analytics events to the NoRedInk events service. +description: Please see the README at . +homepage: https://github.com/NoRedInk/haskell-libraries/tree/trunk/nri-analytics#readme +author: NoRedInk +version: 0.1.0.0 +maintainer: haskell-open-source@noredink.com +copyright: 2026 NoRedInk Corp. +github: NoRedInk/haskell-libraries/nri-analytics +license-file: LICENSE +category: Web +extra-doc-files: + - README.md + - LICENSE + - CHANGELOG.md +dependencies: + - aeson >= 2.0 && < 2.3 + - base >= 4.18 && < 4.22 + - bytestring >= 0.10.8.2 && < 0.13 + - conduit >= 1.3.0 && < 1.4 + - http-client >= 0.6.0 && < 0.8 + - http-client-tls >= 0.3.0 && < 0.4 + - nri-env-parser >= 0.1.0.0 && < 0.5 + - nri-prelude >= 0.7.0.0 && < 0.8 + - safe-exceptions >= 0.1.7.0 && < 1.3 + - text >= 1.2.3.1 && < 2.2 + - time >= 1.9.3 && < 2 + - uuid >= 1.3 && < 1.4 +library: + exposed-modules: + - Analytics + other-modules: + - Analytics.Internal + source-dirs: src +default-extensions: + - DeriveGeneric + - FlexibleInstances + - GeneralizedNewtypeDeriving + - NamedFieldPuns + - NoImplicitPrelude + - OverloadedStrings + - PartialTypeSignatures + - ScopedTypeVariables + - Strict +ghc-options: + - -Wall + - -Wcompat + - -Widentities + - -Wincomplete-record-updates + - -Wpartial-fields + - -Wredundant-constraints + - -Wincomplete-uni-patterns + - -fplugin=NriPrelude.Plugin +tests: + tests: + main: Main.hs + source-dirs: + - tests + - src + ghc-options: + - -threaded + dependencies: + - nri-analytics diff --git a/nri-analytics/src/Analytics.hs b/nri-analytics/src/Analytics.hs new file mode 100644 index 00000000..7b074730 --- /dev/null +++ b/nri-analytics/src/Analytics.hs @@ -0,0 +1,102 @@ +-- | Sync HTTP delivery of typed analytics events to NoRedInk's events +-- service. The `AnalyticsHandler` produced here is meant to be threaded +-- into `nri-prelude`'s `LogHandler` analytics callback at the +-- application root. +module Analytics + ( -- * Handle + Internal.AnalyticsHandler, + sendEvent, + handler, + silentHandler, + + -- * Settings + Internal.Settings + ( Settings, + eventsServiceUrl, + timeoutMicros, + authToken + ), + decoder, + ) +where + +import qualified Analytics.Internal as Internal +import qualified Conduit +import qualified Data.Aeson as Aeson +import qualified Environment +import qualified Log +import qualified Network.HTTP.Client.TLS as HTTP.TLS +import NriPrelude +import Prelude (IO, pure) + +-- | Send a single event payload. Called from +-- `Platform.Analytics.Internal.trackEvent` via the `LogHandler`'s +-- analytics callback. Synchronous; bounded by `Settings.timeoutMicros`; +-- never throws. +sendEvent :: Internal.AnalyticsHandler -> Aeson.Value -> IO () +sendEvent = Internal.sendEvent + +-- | A no-op handler. Use this in tests and on platforms that have not +-- opted in to analytics tracking yet. +silentHandler :: Internal.AnalyticsHandler +silentHandler = + Internal.AnalyticsHandler + { Internal.sendEvent = \_ -> pure (), + Internal.settings = + Internal.Settings + { Internal.eventsServiceUrl = "", + Internal.timeoutMicros = 0, + Internal.authToken = Log.mkSecret "" + }, + Internal.httpManager = Nothing + } + +-- | Acquire a live handler. Owns an HTTP manager that lives until the +-- `Acquire` is released. +handler :: Internal.Settings -> Conduit.Acquire Internal.AnalyticsHandler +handler s = do + manager <- Conduit.mkAcquire HTTP.TLS.newTlsManager (\_ -> pure ()) + pure + Internal.AnalyticsHandler + { Internal.sendEvent = Internal.sendEventIO manager s, + Internal.settings = s, + Internal.httpManager = Just manager + } + +-- | Read settings from environment variables. +decoder :: Environment.Decoder Internal.Settings +decoder = + pure Internal.Settings + |> andMap eventsServiceUrlDecoder + |> andMap timeoutMicrosDecoder + |> andMap authTokenDecoder + +eventsServiceUrlDecoder :: Environment.Decoder Text +eventsServiceUrlDecoder = + Environment.variable + Environment.Variable + { Environment.name = "ANALYTICS_EVENTS_SERVICE_URL", + Environment.description = "Base URL of the events service.", + Environment.defaultValue = "" + } + Environment.text + +timeoutMicrosDecoder :: Environment.Decoder Int +timeoutMicrosDecoder = + Environment.variable + Environment.Variable + { Environment.name = "ANALYTICS_EVENTS_TIMEOUT_MICROS", + Environment.description = "Per-request timeout in microseconds. Default 500000 (500ms).", + Environment.defaultValue = "500000" + } + Environment.int + +authTokenDecoder :: Environment.Decoder (Log.Secret Text) +authTokenDecoder = + Environment.variable + Environment.Variable + { Environment.name = "ANALYTICS_EVENTS_AUTH_TOKEN", + Environment.description = "Bearer token for the events service.", + Environment.defaultValue = "" + } + (Environment.secret Environment.text) diff --git a/nri-analytics/src/Analytics/Internal.hs b/nri-analytics/src/Analytics/Internal.hs new file mode 100644 index 00000000..2198c8a0 --- /dev/null +++ b/nri-analytics/src/Analytics/Internal.hs @@ -0,0 +1,97 @@ +module Analytics.Internal + ( AnalyticsHandler (..), + Settings (..), + buildRequest, + sendEventIO, + stampEnvelope, + ) +where + +import qualified Control.Exception.Safe as Exception +import qualified Data.Aeson as Aeson +import qualified Data.Aeson.KeyMap as KeyMap +import qualified Data.Text +import qualified Data.Text.Encoding +import qualified Data.Time.Clock as Clock +import qualified Data.Time.Format.ISO8601 as ISO8601 +import qualified Data.UUID +import qualified Data.UUID.V4 as UUID +import qualified Log +import qualified Network.HTTP.Client as HTTP +import NriPrelude +import qualified Prelude +import Prelude (IO, pure) + +-- | Configuration for the analytics handler. Loaded from environment +-- variables via `Analytics.decoder`. The events service contract is +-- provisional; revise these fields as the contract solidifies. +data Settings = Settings + { -- | Base URL of the events service, e.g. https://events.noredink.com. + eventsServiceUrl :: Text, + -- | Per-request HTTP timeout. The request thread blocks for at most + -- this long before the event is dropped. + timeoutMicros :: Int, + -- | Bearer token used in the Authorization header. Wrapped in + -- `Log.Secret` so accidental logging or `Show`-deriving doesn't + -- leak it. + authToken :: Log.Secret Text + } + +-- | Live handle for delivering events. The `sendEvent` callback is what +-- gets threaded into nri-prelude's `LogHandler`. The other fields are +-- internal but must be retained to keep the HTTP manager + counters +-- alive for the program's lifetime. +data AnalyticsHandler = AnalyticsHandler + { sendEvent :: Aeson.Value -> IO (), + settings :: Settings, + httpManager :: Maybe HTTP.Manager + } + +-- | Build the HTTP request for a single event. Pure-ish: doesn't fire the +-- request, just constructs it. Tested directly so we don't have to spin +-- up a server. +buildRequest :: Settings -> Aeson.Value -> IO HTTP.Request +buildRequest s value = do + initial <- HTTP.parseRequest (Data.Text.unpack (eventsServiceUrl s ++ "/events")) + pure + initial + { HTTP.method = "POST", + HTTP.requestHeaders = + [ ("Content-Type", "application/json"), + ("Authorization", "Bearer " ++ Data.Text.Encoding.encodeUtf8 (Log.unSecret (authToken s))) + ], + HTTP.requestBody = HTTP.RequestBodyLBS (Aeson.encode value), + HTTP.responseTimeout = HTTP.responseTimeoutMicro (Prelude.fromIntegral (timeoutMicros s)) + } + +-- | Synchronous HTTP delivery. Catches every exception and drops the +-- event so analytics failure can never bring down the surrounding +-- request. (Logging hook is a TODO until the prelude logger is wired +-- through here.) +sendEventIO :: HTTP.Manager -> Settings -> Aeson.Value -> IO () +sendEventIO manager s value = + Exception.handleAny logAndDrop <| do + enveloped <- stampEnvelope value + request <- buildRequest s enveloped + _response <- HTTP.httpLbs request manager + pure () + where + logAndDrop :: Exception.SomeException -> IO () + logAndDrop _e = pure () + +-- | Mint event_id (UUID v4) + event_timestamp (ISO 8601 UTC) and +-- shallow-merge them onto the event JSON. Envelope keys win on +-- collision. Non-object inbound values are wrapped under a `payload` +-- key so the envelope still produces a valid object. +stampEnvelope :: Aeson.Value -> IO Aeson.Value +stampEnvelope inbound = do + uuid <- UUID.nextRandom + now <- Clock.getCurrentTime + let envelope = + KeyMap.fromList + [ ("event_id", Aeson.String (Data.UUID.toText uuid)), + ("event_timestamp", Aeson.String (Data.Text.pack (ISO8601.iso8601Show now))) + ] + pure <| case inbound of + Aeson.Object body -> Aeson.Object (KeyMap.union envelope body) + other -> Aeson.Object (KeyMap.insert "payload" other envelope) diff --git a/nri-analytics/tests/Main.hs b/nri-analytics/tests/Main.hs new file mode 100644 index 00000000..8d26936d --- /dev/null +++ b/nri-analytics/tests/Main.hs @@ -0,0 +1,15 @@ +module Main (main) where + +import qualified Spec.Analytics +import qualified Test +import qualified Prelude + +main :: Prelude.IO () +main = Test.run tests + +tests :: Test.Test +tests = + Test.describe + "nri-analytics" + [ Spec.Analytics.tests + ] diff --git a/nri-analytics/tests/Spec/Analytics.hs b/nri-analytics/tests/Spec/Analytics.hs new file mode 100644 index 00000000..31b98cdd --- /dev/null +++ b/nri-analytics/tests/Spec/Analytics.hs @@ -0,0 +1,79 @@ +module Spec.Analytics (tests) where + +import qualified Analytics +import qualified Analytics.Internal as Internal +import qualified Data.Aeson as Aeson +import qualified Data.Aeson.KeyMap as KeyMap +import qualified Data.Text +import qualified Dict +import qualified Environment +import qualified Expect +import qualified Log +import qualified Network.HTTP.Client as HTTP +import qualified Network.HTTP.Client.TLS as HTTP.TLS +import NriPrelude +import Test (Test, describe, test) +import qualified Prelude + +tests :: Test +tests = + describe + "Analytics" + [ test "silentHandler.sendEvent does nothing and returns ()" <| \_ -> do + Expect.fromIO <| Analytics.sendEvent Analytics.silentHandler (Aeson.object []), + test "buildRequest sets URL, method, content-type, bearer auth" <| \_ -> do + let settings = + Internal.Settings + { Internal.eventsServiceUrl = "https://events.example.com", + Internal.timeoutMicros = 250000, + Internal.authToken = Log.mkSecret "secret-token" + } + req <- Expect.fromIO <| Internal.buildRequest settings (Aeson.object []) + let headers = HTTP.requestHeaders req + HTTP.method req + |> Expect.equal "POST" + Prelude.lookup "Content-Type" headers + |> Expect.equal (Just "application/json") + Prelude.lookup "Authorization" headers + |> Expect.equal (Just "Bearer secret-token"), + test "stampEnvelope adds event_id and event_timestamp keys" <| \_ -> do + result <- Expect.fromIO <| Internal.stampEnvelope (Aeson.object [("foo", Aeson.String "bar")]) + case result of + Aeson.Object km -> do + case KeyMap.lookup "event_id" km of + Just (Aeson.String _) -> Expect.pass + _ -> Expect.fail "event_id missing or wrong shape" + case KeyMap.lookup "event_timestamp" km of + Just (Aeson.String _) -> Expect.pass + _ -> Expect.fail "event_timestamp missing or wrong shape" + Expect.equal (KeyMap.lookup "foo" km) (Just (Aeson.String "bar")) + _ -> Expect.fail "expected Object", + test "decoder loads settings from env vars" <| \_ -> do + let env = + Dict.fromList + [ ("ANALYTICS_EVENTS_SERVICE_URL", "https://events.example.com"), + ("ANALYTICS_EVENTS_TIMEOUT_MICROS", "300000"), + ("ANALYTICS_EVENTS_AUTH_TOKEN", "the-token") + ] + case Environment.decodePairs Analytics.decoder env of + Ok s -> do + Internal.eventsServiceUrl s + |> Expect.equal "https://events.example.com" + Internal.timeoutMicros s + |> Expect.equal 300000 + Log.unSecret (Internal.authToken s) + |> Expect.equal "the-token" + Err err -> Expect.fail (Data.Text.pack (Prelude.show err)), + test "sendEventIO swallows exceptions when delivery fails" <| \_ -> do + -- Construct a settings pointing at an unreachable URL; verify that + -- sendEventIO catches the resulting exception and returns () so + -- analytics failure cannot propagate into the surrounding request. + manager <- Expect.fromIO HTTP.TLS.newTlsManager + let settings = + Internal.Settings + { Internal.eventsServiceUrl = "http://127.0.0.1:1", + Internal.timeoutMicros = 50000, + Internal.authToken = Log.mkSecret "" + } + Expect.fromIO <| Internal.sendEventIO manager settings (Aeson.object [("k", Aeson.String "v")]) + ] diff --git a/nri-env-parser/nri-env-parser.cabal b/nri-env-parser/nri-env-parser.cabal index c7b0be94..7f11f793 100644 --- a/nri-env-parser/nri-env-parser.cabal +++ b/nri-env-parser/nri-env-parser.cabal @@ -53,7 +53,7 @@ library base >=4.18 && <4.22 , modern-uri >=0.3.1.0 && <0.4 , network-uri >=2.6.2.0 && <2.8 - , nri-prelude >=0.1.0.0 && <0.7 + , nri-prelude >=0.1.0.0 && <0.8 , text >=1.2.3.1 && <2.2 default-language: Haskell2010 @@ -86,6 +86,6 @@ test-suite tests base >=4.18 && <4.22 , modern-uri >=0.3.1.0 && <0.4 , network-uri >=2.6.2.0 && <2.8 - , nri-prelude >=0.1.0.0 && <0.7 + , nri-prelude >=0.1.0.0 && <0.8 , text >=1.2.3.1 && <2.2 default-language: Haskell2010 diff --git a/nri-env-parser/package.yaml b/nri-env-parser/package.yaml index ad7e094c..a6d13416 100644 --- a/nri-env-parser/package.yaml +++ b/nri-env-parser/package.yaml @@ -16,7 +16,7 @@ extra-doc-files: library: dependencies: &dependencies - base >= 4.18 && < 4.22 - - nri-prelude >= 0.1.0.0 && < 0.7 + - nri-prelude >= 0.1.0.0 && < 0.8 - modern-uri >= 0.3.1.0 && < 0.4 - network-uri >= 2.6.2.0 && < 2.8 - text >= 1.2.3.1 && < 2.2 diff --git a/nri-http/nri-http.cabal b/nri-http/nri-http.cabal index 3dd910d9..a828cf46 100644 --- a/nri-http/nri-http.cabal +++ b/nri-http/nri-http.cabal @@ -65,7 +65,7 @@ library , mime-types >=0.1.0.0 && <0.2 , network-uri >=2.6.0.0 && <2.8 , nri-observability >=0.1.0.0 && <0.5 - , nri-prelude >=0.1.0.0 && <0.7 + , nri-prelude >=0.1.0.0 && <0.8 , safe-exceptions >=0.1.7.0 && <1.3 , text >=1.2.3.1 && <2.2 default-language: Haskell2010 @@ -111,7 +111,7 @@ test-suite spec , mime-types >=0.1.0.0 && <0.2 , network-uri >=2.6.0.0 && <2.8 , nri-observability >=0.1.0.0 && <0.4 - , nri-prelude >=0.1.0.0 && <0.7 + , nri-prelude >=0.1.0.0 && <0.8 , safe-exceptions >=0.1.7.0 && <1.3 , text >=1.2.3.1 && <2.2 , wai >=3.2.0 && <3.3 diff --git a/nri-http/package.yaml b/nri-http/package.yaml index 28d8708d..64eb437f 100644 --- a/nri-http/package.yaml +++ b/nri-http/package.yaml @@ -17,7 +17,7 @@ library: - aeson >= 2.0 && < 2.3 - base >= 4.18 && < 4.22 - bytestring >= 0.10.8.2 && < 0.13 - - nri-prelude >= 0.1.0.0 && < 0.7 + - nri-prelude >= 0.1.0.0 && < 0.8 - nri-observability >= 0.1.0.0 && < 0.5 - conduit >= 1.3.0 && < 1.4 - case-insensitive >= 1.1 && < 2.0 @@ -38,7 +38,7 @@ tests: - aeson >= 2.0 && < 2.3 - base >= 4.18 && < 4.22 - bytestring >= 0.10.8.2 && < 0.13 - - nri-prelude >= 0.1.0.0 && < 0.7 + - nri-prelude >= 0.1.0.0 && < 0.8 - nri-observability >= 0.1.0.0 && < 0.4 - conduit >= 1.3.0 && < 1.4 - case-insensitive >= 1.1 && < 2.0 diff --git a/nri-http/test/Main.hs b/nri-http/test/Main.hs index 4855aba4..47e03eb5 100644 --- a/nri-http/test/Main.hs +++ b/nri-http/test/Main.hs @@ -233,6 +233,7 @@ spanForTask task = do Expect.fromIO <| do Platform.rootTracingSpanIO "test-request" + Platform.silentTrack (MVar.putMVar spanVar) "test-root" (\log -> Task.attempt log task) diff --git a/nri-kafka/nri-kafka.cabal b/nri-kafka/nri-kafka.cabal index 97899901..d59de942 100644 --- a/nri-kafka/nri-kafka.cabal +++ b/nri-kafka/nri-kafka.cabal @@ -76,7 +76,7 @@ library , hw-kafka-client >=4.0.3 && <5.0 , nri-env-parser >=0.1.0.0 && <0.5 , nri-observability >=0.1.1.1 && <0.5 - , nri-prelude >=0.1.0.0 && <0.7 + , nri-prelude >=0.1.0.0 && <0.8 , safe-exceptions >=0.1.7.0 && <1.3 , stm >=2.4 && <2.6 , text >=1.2.3.1 && <2.2 @@ -121,7 +121,7 @@ executable pause-resume-bug-consumer , nri-env-parser >=0.1.0.0 && <0.5 , nri-kafka , nri-observability >=0.1.1.1 && <0.5 - , nri-prelude >=0.1.0.0 && <0.7 + , nri-prelude >=0.1.0.0 && <0.8 , safe-exceptions >=0.1.7.0 && <1.3 , stm >=2.4 && <2.6 , text >=1.2.3.1 && <2.2 @@ -170,7 +170,7 @@ executable pause-resume-bug-producer , nri-env-parser >=0.1.0.0 && <0.5 , nri-kafka , nri-observability >=0.1.1.1 && <0.5 - , nri-prelude >=0.1.0.0 && <0.7 + , nri-prelude >=0.1.0.0 && <0.8 , safe-exceptions >=0.1.7.0 && <1.3 , stm >=2.4 && <2.6 , text >=1.2.3.1 && <2.2 @@ -233,7 +233,7 @@ test-suite tests , hw-kafka-client >=4.0.3 && <5.0 , nri-env-parser >=0.1.0.0 && <0.5 , nri-observability >=0.1.1.1 && <0.5 - , nri-prelude >=0.1.0.0 && <0.7 + , nri-prelude >=0.1.0.0 && <0.8 , safe-exceptions >=0.1.7.0 && <1.3 , stm >=2.4 && <2.6 , text >=1.2.3.1 && <2.2 diff --git a/nri-kafka/package.yaml b/nri-kafka/package.yaml index 639a9ac0..b298504f 100644 --- a/nri-kafka/package.yaml +++ b/nri-kafka/package.yaml @@ -23,7 +23,7 @@ dependencies: - hw-kafka-client >=4.0.3 && < 5.0 - nri-env-parser >= 0.1.0.0 && < 0.5 - nri-observability >= 0.1.1.1 && < 0.5 - - nri-prelude >= 0.1.0.0 && < 0.7 + - nri-prelude >= 0.1.0.0 && < 0.8 - safe-exceptions >= 0.1.7.0 && < 1.3 - stm >= 2.4 && < 2.6 - text >= 1.2.3.1 && < 2.2 diff --git a/nri-kafka/src/Kafka/Worker/Internal.hs b/nri-kafka/src/Kafka/Worker/Internal.hs index b6d0ff40..5fee1a12 100644 --- a/nri-kafka/src/Kafka/Worker/Internal.hs +++ b/nri-kafka/src/Kafka/Worker/Internal.hs @@ -456,6 +456,7 @@ cleanUp observabilityHandler rebalanceInfo stopping maybeException consumer = do -- at some point, k8s should report system crashes. In the mean time, we'll do it. Platform.rootTracingSpanIO requestId + Platform.silentTrack (Observability.report observabilityHandler requestId) "Kafka consumer shutting down" <| \log -> do diff --git a/nri-kafka/src/Kafka/Worker/Partition.hs b/nri-kafka/src/Kafka/Worker/Partition.hs index 206c4353..9a3d3130 100644 --- a/nri-kafka/src/Kafka/Worker/Partition.hs +++ b/nri-kafka/src/Kafka/Worker/Partition.hs @@ -248,6 +248,7 @@ processMsgLoop skipOrNot messageFormat commitOffsets observabilityHandler state (RequestId requestId, details) <- getTracingDetails (analytics state) processAttempts record Platform.rootTracingSpanIO requestId + Platform.silentTrack (Observability.report observabilityHandler requestId) "Assigned Kafka message" ( \log -> do diff --git a/nri-log-explorer/nri-log-explorer.cabal b/nri-log-explorer/nri-log-explorer.cabal index 68dc3402..99ab547b 100644 --- a/nri-log-explorer/nri-log-explorer.cabal +++ b/nri-log-explorer/nri-log-explorer.cabal @@ -59,7 +59,7 @@ executable log-explorer , fuzzy >=0.1.0.0 && <0.2 , io-streams >=1.5.0.0 && <1.6 , microlens >=0.4.11.0 && <0.5 - , nri-prelude >=0.1.0.0 && <0.7 + , nri-prelude >=0.1.0.0 && <0.8 , pcre-light >=0.4.1.0 && <0.4.2 , process >=1.6.0.0 && <1.7 , safe-exceptions >=0.1.7.0 && <1.3 diff --git a/nri-log-explorer/package.yaml b/nri-log-explorer/package.yaml index a543821a..ad88fc83 100644 --- a/nri-log-explorer/package.yaml +++ b/nri-log-explorer/package.yaml @@ -28,7 +28,7 @@ executables: - pcre-light >= 0.4.1.0 && < 0.4.2 - unordered-containers >= 0.2.0.0 && < 0.3 - microlens >= 0.4.11.0 && < 0.5 - - nri-prelude >= 0.1.0.0 && < 0.7 + - nri-prelude >= 0.1.0.0 && < 0.8 - process >= 1.6.0.0 && < 1.7 - safe-exceptions >= 0.1.7.0 && < 1.3 - text >= 1.2.3.1 && < 2.2 diff --git a/nri-observability/nri-observability.cabal b/nri-observability/nri-observability.cabal index 57647282..a9fc96dd 100644 --- a/nri-observability/nri-observability.cabal +++ b/nri-observability/nri-observability.cabal @@ -77,7 +77,7 @@ library , http-client >=0.6.0 && <0.8 , http-client-tls >=0.3.0 && <0.4 , nri-env-parser >=0.1.0.0 && <0.5 - , nri-prelude >=0.1.0.0 && <0.7 + , nri-prelude >=0.1.0.0 && <0.8 , random >=1.1 && <1.3 , safe-exceptions >=0.1.7.0 && <1.3 , stm >=2.4 && <2.6 @@ -123,7 +123,7 @@ executable memory-leak-test , http-client-tls >=0.3.0 && <0.4 , nri-env-parser >=0.1.0.0 && <0.5 , nri-observability - , nri-prelude >=0.1.0.0 && <0.7 + , nri-prelude >=0.1.0.0 && <0.8 , random >=1.1 && <1.3 , safe-exceptions >=0.1.7.0 && <1.3 , stm >=2.4 && <2.6 @@ -194,7 +194,7 @@ test-suite tests , http-client >=0.6.0 && <0.8 , http-client-tls >=0.3.0 && <0.4 , nri-env-parser >=0.1.0.0 && <0.5 - , nri-prelude >=0.1.0.0 && <0.7 + , nri-prelude >=0.1.0.0 && <0.8 , random >=1.1 && <1.3 , safe-exceptions >=0.1.7.0 && <1.3 , stm >=2.4 && <2.6 diff --git a/nri-observability/package.yaml b/nri-observability/package.yaml index b5e329be..04e2daff 100644 --- a/nri-observability/package.yaml +++ b/nri-observability/package.yaml @@ -26,7 +26,7 @@ dependencies: - http-client-tls >= 0.3.0 && < 0.4 - hostname >= 1.0 && < 1.1 - nri-env-parser >= 0.1.0.0 && < 0.5 - - nri-prelude >= 0.1.0.0 && < 0.7 + - nri-prelude >= 0.1.0.0 && < 0.8 - random >= 1.1 && < 1.3 - unordered-containers >= 0.2.0.0 && < 0.3 - safe-exceptions >= 0.1.7.0 && < 1.3 diff --git a/nri-observability/scripts/memory-leak-test/Main.hs b/nri-observability/scripts/memory-leak-test/Main.hs index ead5c1ad..91d201d0 100644 --- a/nri-observability/scripts/memory-leak-test/Main.hs +++ b/nri-observability/scripts/memory-leak-test/Main.hs @@ -35,6 +35,7 @@ runRequests handler = ( \requestId -> do Platform.rootTracingSpanIO requestId + Platform.silentTrack (handler.report requestId) ("Running task" ++ requestId) ( \log -> do diff --git a/nri-postgresql/nri-postgresql.cabal b/nri-postgresql/nri-postgresql.cabal index 30dd14b8..1edca8dd 100644 --- a/nri-postgresql/nri-postgresql.cabal +++ b/nri-postgresql/nri-postgresql.cabal @@ -68,7 +68,7 @@ library , network >=3.1.0.0 && <3.3 , nri-env-parser >=0.1.0.0 && <0.5 , nri-observability >=0.1.0.0 && <0.5 - , nri-prelude >=0.1.0.0 && <0.7 + , nri-prelude >=0.1.0.0 && <0.8 , postgresql-typed ==0.6.* , resource-pool >=0.2.0.0 && <0.5 , resourcet >=1.2.0 && <1.4 @@ -126,7 +126,7 @@ test-suite tests , network >=3.1.0.0 && <3.3 , nri-env-parser >=0.1.0.0 && <0.5 , nri-observability >=0.1.0.0 && <0.5 - , nri-prelude >=0.1.0.0 && <0.7 + , nri-prelude >=0.1.0.0 && <0.8 , postgresql-typed ==0.6.* , resource-pool >=0.2.0.0 && <0.5 , resourcet >=1.2.0 && <1.4 diff --git a/nri-postgresql/package.yaml b/nri-postgresql/package.yaml index a29614a3..e8ec7c95 100644 --- a/nri-postgresql/package.yaml +++ b/nri-postgresql/package.yaml @@ -23,7 +23,7 @@ dependencies: - network >= 3.1.0.0 && < 3.3 - nri-env-parser >= 0.1.0.0 && < 0.5 - nri-observability >= 0.1.0.0 && < 0.5 - - nri-prelude >= 0.1.0.0 && < 0.7 + - nri-prelude >= 0.1.0.0 && < 0.8 - postgresql-typed >= 0.6 && < 0.7 - resource-pool >= 0.2.0.0 && < 0.5 - resourcet >= 1.2.0 && < 1.4 diff --git a/nri-postgresql/test/ObservabilitySpec.hs b/nri-postgresql/test/ObservabilitySpec.hs index 00cc2881..ee96a301 100644 --- a/nri-postgresql/test/ObservabilitySpec.hs +++ b/nri-postgresql/test/ObservabilitySpec.hs @@ -53,6 +53,7 @@ spanForTask task = res <- Platform.rootTracingSpanIO "test-request" + Platform.silentTrack (MVar.putMVar spanVar) "test-root" (\log -> Task.attempt log task) diff --git a/nri-prelude/CHANGELOG.md b/nri-prelude/CHANGELOG.md index 5d688acd..badea395 100644 --- a/nri-prelude/CHANGELOG.md +++ b/nri-prelude/CHANGELOG.md @@ -1,3 +1,10 @@ +# 0.7.0.0 + +- **Breaking:** `Platform.rootTracingSpanIO` and the internal `mkHandler` now take an additional `Aeson.Value -> IO ()` callback for analytics event delivery. Existing callers should pass `Platform.silentTrack` to preserve previous behavior. +- New: `Platform.Analytics.Internal.trackEvent`. The `.Internal` suffix is intentional — wrap it in your own typed `track` API. This module is NOT re-exported from `Platform`. +- New: `Platform.silentTrack` (a no-op `Aeson.Value -> IO ()`). +- New: `LogHandler.trackAnalyticsEventIO` field. `nullHandler` defaults this to `silentTrack`. + # Unreleased - Drop support for GHC 8.10.7, GHC 9.2.x, GHC 9.4.x, `aeson-1.x` diff --git a/nri-prelude/nri-prelude.cabal b/nri-prelude/nri-prelude.cabal index 3ccd3026..73276f4e 100644 --- a/nri-prelude/nri-prelude.cabal +++ b/nri-prelude/nri-prelude.cabal @@ -5,7 +5,7 @@ cabal-version: 1.18 -- see: https://github.com/sol/hpack name: nri-prelude -version: 0.6.1.2 +version: 0.7.0.0 synopsis: A Prelude inspired by the Elm programming language description: Please see the README at . category: Web @@ -45,6 +45,7 @@ library NriPrelude NriPrelude.Plugin Platform + Platform.Analytics.Internal Process Result Set @@ -146,6 +147,7 @@ test-suite tests NriPrelude.Plugin NriPrelude.Plugin.GhcVersionDependent Platform + Platform.Analytics.Internal Platform.DevLog Platform.DoAnything Platform.Internal diff --git a/nri-prelude/package.yaml b/nri-prelude/package.yaml index f3d28375..cd21b863 100644 --- a/nri-prelude/package.yaml +++ b/nri-prelude/package.yaml @@ -3,7 +3,7 @@ synopsis: A Prelude inspired by the Elm programming language description: Please see the README at . homepage: https://github.com/NoRedInk/haskell-libraries/tree/trunk/nri-prelude#readme author: NoRedInk -version: 0.6.1.2 +version: 0.7.0.0 maintainer: haskell-open-source@noredink.com copyright: 2024 NoRedInk Corp. github: NoRedInk/haskell-libraries/nri-prelude @@ -57,6 +57,7 @@ library: - NriPrelude - NriPrelude.Plugin - Platform + - Platform.Analytics.Internal - Process - Result - Set diff --git a/nri-prelude/src/Platform.hs b/nri-prelude/src/Platform.hs index 9da52d00..d3caf61f 100644 --- a/nri-prelude/src/Platform.hs +++ b/nri-prelude/src/Platform.hs @@ -13,6 +13,7 @@ module Platform logHandler, requestId, silentHandler, + Internal.silentTrack, -- * Creating custom tracingSpans in libraries Internal.tracingSpan, diff --git a/nri-prelude/src/Platform/Analytics/Internal.hs b/nri-prelude/src/Platform/Analytics/Internal.hs new file mode 100644 index 00000000..46b32a28 --- /dev/null +++ b/nri-prelude/src/Platform/Analytics/Internal.hs @@ -0,0 +1,44 @@ +{-# LANGUAGE FlexibleInstances #-} + +-- | Internal entry point for emitting analytics events from `Task` code. +-- +-- This module is intentionally `.Internal`. It is NOT re-exported from +-- the prelude's public `Platform` module. Higher layers (NoRedInk's +-- `Analytics.track`) wrap this and own the user-facing API; downstream +-- code that imports `Platform.Analytics.Internal` directly is bypassing +-- the closed event dictionary and should be flagged in review. +module Platform.Analytics.Internal + ( trackEvent, + AnalyticsEventDetails, + ) +where + +import qualified Data.Aeson as Aeson +import NriPrelude +import qualified Platform +import qualified Platform.Internal as Internal +import Task (Task) +import qualified Prelude + +-- | Send an analytics event. Opens a child tracing span named +-- @analytics.track@, attaches the JSON payload as the span's details, +-- and synchronously invokes the `LogHandler`'s analytics callback. +trackEvent :: (Aeson.ToJSON e) => e -> Task err () +trackEvent event = + let value = Aeson.toJSON event + in Platform.tracingSpan "analytics.track" <| do + Platform.setTracingSpanDetails (AnalyticsEventDetails value) + Internal.Task + ( \handler -> do + Internal.trackAnalyticsEventIO handler value + Prelude.pure (Ok ()) + ) + +-- | A `TracingSpanDetails` wrapper around the analytics event payload, so +-- that the JSON we send to the analytics backend is also attached to the +-- @analytics.track@ span and visible in the existing observability +-- reporters. +newtype AnalyticsEventDetails = AnalyticsEventDetails Aeson.Value + deriving (Aeson.ToJSON) + +instance Internal.TracingSpanDetails AnalyticsEventDetails diff --git a/nri-prelude/src/Platform/Internal.hs b/nri-prelude/src/Platform/Internal.hs index d39554b7..213bd5dc 100644 --- a/nri-prelude/src/Platform/Internal.hs +++ b/nri-prelude/src/Platform/Internal.hs @@ -573,9 +573,20 @@ data LogHandler = LogHandler -- platform(s) are used. Once we're done collecting data for child -- tracingSpans we'll want to add the "completed" child tracingSpan to -- its parent. - finishTracingSpan :: Maybe Exception.SomeException -> IO () + finishTracingSpan :: Maybe Exception.SomeException -> IO (), + -- | Deliver an analytics event payload to the configured analytics + -- backend. The prelude knows nothing about the backend; it only + -- threads this opaque callback from `rootTracingSpanIO` through + -- every child `LogHandler`. See `Platform.Analytics.Internal.trackEvent` + -- for the user-facing wrapper. Default: `silentTrack`. + trackAnalyticsEventIO :: Aeson.Value -> IO () } +-- | A no-op analytics callback. Used as the default for `nullHandler` +-- and for platforms that have not opted in to analytics tracking yet. +silentTrack :: Aeson.Value -> IO () +silentTrack _ = pure () + -- | Helper that creates one of the handler's above. This is intended for -- internal use in this library only and not for exposing. Outside of this -- library the @rootTracingSpanIO@ is the more user-friendly way to get hands @@ -584,13 +595,15 @@ mkHandler :: (Stack.HasCallStack) => Text -> Clock -> + -- | Analytics callback, propagated to every descendant `LogHandler`. + (Aeson.Value -> IO ()) -> -- Finalizer for this loghandler (TracingSpan -> IO ()) -> -- Root finalizer Maybe (TracingSpan -> IO ()) -> Text -> IO LogHandler -mkHandler requestId clock onFinish onFinishRoot' name' = do +mkHandler requestId clock trackEventIO onFinish onFinishRoot' name' = do let onFinishRoot = Maybe.withDefault onFinish onFinishRoot' tracingSpanRef <- Stack.withFrozenCallStack startTracingSpan clock name' @@ -599,8 +612,8 @@ mkHandler requestId clock onFinish onFinishRoot' name' = do pure LogHandler { requestId, - startChildTracingSpan = mkHandler requestId clock (appendTracingSpanToParent tracingSpanRef) (Just onFinishRoot), - startNewRoot = mkHandler requestId clock onFinishRoot Nothing, + startChildTracingSpan = mkHandler requestId clock trackEventIO (appendTracingSpanToParent tracingSpanRef) (Just onFinishRoot), + startNewRoot = mkHandler requestId clock trackEventIO onFinishRoot Nothing, setTracingSpanDetailsIO = \details' -> updateIORef tracingSpanRef @@ -613,7 +626,8 @@ mkHandler requestId clock onFinish onFinishRoot' name' = do updateIORef tracingSpanRef (\tracingSpan' -> tracingSpan' {succeeded = succeeded tracingSpan' ++ Failed, containsFailures = True}), - finishTracingSpan = finalizeTracingSpan clock allocationCounterStartVal tracingSpanRef >> andThen onFinish + finishTracingSpan = finalizeTracingSpan clock allocationCounterStartVal tracingSpanRef >> andThen onFinish, + trackAnalyticsEventIO = trackEventIO } -- | Helper that creates a handler that does nothing. This is intended to power @@ -632,7 +646,8 @@ nullHandler = do setTracingSpanDetailsIO = \_ -> pure (), setTracingSpanSummaryIO = \_ -> pure (), markTracingSpanFailedIO = pure (), - finishTracingSpan = \_ -> pure () + finishTracingSpan = \_ -> pure (), + trackAnalyticsEventIO = silentTrack } -- | Set the details for a tracingSpan created using the @tracingSpan@ @@ -842,14 +857,22 @@ newRootIO handler name run = do -- Instead of taking a parent handler it takes a continuation that will be -- called with this root tracingSpan after it has run. -- --- > rootTracingSpanIO "request-23" Prelude.print "incoming request" <| \handler -> +-- > rootTracingSpanIO "request-23" silentTrack Prelude.print "incoming request" <| \handler -> -- > handleRequest -- > |> Task.perform handler -rootTracingSpanIO :: (Stack.HasCallStack) => Text -> (TracingSpan -> IO ()) -> Text -> (LogHandler -> IO a) -> IO a -rootTracingSpanIO requestId onFinish name runIO = do +rootTracingSpanIO :: + (Stack.HasCallStack) => + Text -> + -- | Analytics callback. Pass `silentTrack` for platforms that don't track. + (Aeson.Value -> IO ()) -> + (TracingSpan -> IO ()) -> + Text -> + (LogHandler -> IO a) -> + IO a +rootTracingSpanIO requestId trackEventIO onFinish name runIO = do clock' <- mkClock Exception.bracketWithError - (Stack.withFrozenCallStack mkHandler requestId clock' onFinish Nothing name) + (Stack.withFrozenCallStack mkHandler requestId clock' trackEventIO onFinish Nothing name) (Prelude.flip finishTracingSpan) runIO diff --git a/nri-prelude/src/Test/Internal.hs b/nri-prelude/src/Test/Internal.hs index a51f79a7..0379f399 100644 --- a/nri-prelude/src/Test/Internal.hs +++ b/nri-prelude/src/Test/Internal.hs @@ -533,6 +533,7 @@ runSingle test' = res <- Platform.Internal.rootTracingSpanIO "" + Platform.Internal.silentTrack ( \span -> do when (Platform.Internal.name span == spanName) <| MVar.putMVar spanVar span diff --git a/nri-prelude/tests/LogSpec.hs b/nri-prelude/tests/LogSpec.hs index 8cc12820..d75d4c8f 100644 --- a/nri-prelude/tests/LogSpec.hs +++ b/nri-prelude/tests/LogSpec.hs @@ -195,6 +195,7 @@ newHandler = do Internal.mkHandler "" (Internal.Clock (Prelude.pure 0)) + Internal.silentTrack (\span -> IORef.modifyIORef recordedTracingSpans (\cs -> cs ++ Internal.children span)) Nothing "" diff --git a/nri-prelude/tests/PlatformSpec.hs b/nri-prelude/tests/PlatformSpec.hs index 37a70a1a..2908dffb 100644 --- a/nri-prelude/tests/PlatformSpec.hs +++ b/nri-prelude/tests/PlatformSpec.hs @@ -3,10 +3,13 @@ module PlatformSpec (tests) where import qualified Control.Concurrent.MVar as MVar import Control.Monad.Catch (catchAll) import Data.Aeson as Aeson +import qualified Data.IORef as IORef import qualified Expect import qualified Log import NriPrelude import qualified Platform +import qualified Platform.Analytics.Internal +import qualified Platform.Internal import Task import Test (Test, describe, test) import qualified Prelude @@ -31,7 +34,33 @@ tests = runTaskAndExpectTacingSpan <| Log.error "error" [] Expect.true (isSucceeded span) - Expect.true (Platform.containsFailures span) + Expect.true (Platform.containsFailures span), + test "trackAnalyticsEventIO threaded by rootTracingSpanIO is invoked from a child span" <| \_ -> do + ref <- Expect.fromIO (IORef.newIORef []) + let track v = IORef.atomicModifyIORef' ref (\xs -> (v : xs, ())) + Expect.fromIO + <| Platform.rootTracingSpanIO "test-req" track (\_ -> Prelude.pure ()) "root" + <| \log -> do + child <- Platform.Internal.startChildTracingSpan log "child-span" + Platform.Internal.trackAnalyticsEventIO child (Aeson.toJSON ("hello" :: Text)) + observed <- Expect.fromIO (IORef.readIORef ref) + observed |> Expect.equal [Aeson.toJSON ("hello" :: Text)], + test "nullHandler.trackAnalyticsEventIO is a silent no-op" <| \_ -> + Expect.fromIO + <| Platform.Internal.trackAnalyticsEventIO Platform.Internal.nullHandler Aeson.Null, + test "Platform.Analytics.Internal.trackEvent invokes the current LogHandler's analytics callback with toJSON of the event" <| \_ -> do + ref <- Expect.fromIO (IORef.newIORef []) + let track v = IORef.atomicModifyIORef' ref (\xs -> (v : xs, ())) + let event = Aeson.object ["kind" Aeson..= ("LessonStarted" :: Text)] + result <- + Expect.fromIO + <| Platform.rootTracingSpanIO "test-req" track (\_ -> Prelude.pure ()) "root" + <| \log -> Task.attempt log (Platform.Analytics.Internal.trackEvent event) + case result of + Ok () -> Expect.pass + Err _ -> Expect.fail "trackEvent task failed" + observed <- Expect.fromIO (IORef.readIORef ref) + observed |> Expect.equal [event] ] newtype CustomTracingSpanDetails = CustomTracingSpanDetails Text @@ -48,6 +77,7 @@ runTaskAndExpectTacingSpan task = catchAll ( Platform.rootTracingSpanIO "" + Platform.silentTrack (MVar.putMVar spanVar) "test" (\log -> Task.attempt log task) diff --git a/nri-prelude/tests/golden-results-9.10/debug b/nri-prelude/tests/golden-results-9.10/debug index a2629768..6b3bcde9 100644 --- a/nri-prelude/tests/golden-results-9.10/debug +++ b/nri-prelude/tests/golden-results-9.10/debug @@ -6,7 +6,7 @@ Just ( "debug" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 40 diff --git a/nri-prelude/tests/golden-results-9.10/debug-todo-stacktrace b/nri-prelude/tests/golden-results-9.10/debug-todo-stacktrace index bfe57c72..544c8666 100644 --- a/nri-prelude/tests/golden-results-9.10/debug-todo-stacktrace +++ b/nri-prelude/tests/golden-results-9.10/debug-todo-stacktrace @@ -1,6 +1,6 @@ foo CallStack (from HasCallStack): - todo, called at tests/TestSpec.hs:177:20 in nri-prelude-0.6.1.2-inplace-tests:TestSpec + todo, called at tests/TestSpec.hs:177:20 in nri-prelude-0.7.0.0-inplace-tests:TestSpec HasCallStack backtrace: - todo, called at tests/TestSpec.hs:177:20 in nri-prelude-0.6.1.2-inplace-tests:TestSpec + todo, called at tests/TestSpec.hs:177:20 in nri-prelude-0.7.0.0-inplace-tests:TestSpec diff --git a/nri-prelude/tests/golden-results-9.10/error b/nri-prelude/tests/golden-results-9.10/error index 4b550b43..0ccd5662 100644 --- a/nri-prelude/tests/golden-results-9.10/error +++ b/nri-prelude/tests/golden-results-9.10/error @@ -6,7 +6,7 @@ Just ( "error" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 66 diff --git a/nri-prelude/tests/golden-results-9.10/log-async-exceptions b/nri-prelude/tests/golden-results-9.10/log-async-exceptions index 9960f182..fb749c61 100644 --- a/nri-prelude/tests/golden-results-9.10/log-async-exceptions +++ b/nri-prelude/tests/golden-results-9.10/log-async-exceptions @@ -6,7 +6,7 @@ Just ( "withContext" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 113 @@ -29,7 +29,7 @@ Just ( "withContext" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 112 diff --git a/nri-prelude/tests/golden-results-9.10/log-info b/nri-prelude/tests/golden-results-9.10/log-info index 9bc7042a..2d8e3184 100644 --- a/nri-prelude/tests/golden-results-9.10/log-info +++ b/nri-prelude/tests/golden-results-9.10/log-info @@ -6,7 +6,7 @@ Just ( "info" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 30 diff --git a/nri-prelude/tests/golden-results-9.10/log-nested-spans b/nri-prelude/tests/golden-results-9.10/log-nested-spans index 5bee1860..9a2ea38d 100644 --- a/nri-prelude/tests/golden-results-9.10/log-nested-spans +++ b/nri-prelude/tests/golden-results-9.10/log-nested-spans @@ -6,7 +6,7 @@ Just ( "withContext" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 81 @@ -29,7 +29,7 @@ Just ( "withContext" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 80 @@ -52,7 +52,7 @@ Just ( "info" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 79 diff --git a/nri-prelude/tests/golden-results-9.10/log-new-root b/nri-prelude/tests/golden-results-9.10/log-new-root index 0547be4d..f08dcf87 100644 --- a/nri-prelude/tests/golden-results-9.10/log-new-root +++ b/nri-prelude/tests/golden-results-9.10/log-new-root @@ -6,7 +6,7 @@ Just ( "info" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 174 @@ -30,7 +30,7 @@ Just ( "info" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 177 @@ -54,7 +54,7 @@ Just ( "info" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 176 @@ -78,7 +78,7 @@ Just ( "withContext" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 173 @@ -101,7 +101,7 @@ Just ( "info" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 173 diff --git a/nri-prelude/tests/golden-results-9.10/log-unexpected-exceptions b/nri-prelude/tests/golden-results-9.10/log-unexpected-exceptions index 94fa4f8f..9deeb593 100644 --- a/nri-prelude/tests/golden-results-9.10/log-unexpected-exceptions +++ b/nri-prelude/tests/golden-results-9.10/log-unexpected-exceptions @@ -6,7 +6,7 @@ Just ( "withContext" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 94 @@ -29,7 +29,7 @@ Just ( "withContext" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 93 diff --git a/nri-prelude/tests/golden-results-9.10/test-report-logfile-all-passed b/nri-prelude/tests/golden-results-9.10/test-report-logfile-all-passed index 085c55b8..d752330c 100644 --- a/nri-prelude/tests/golden-results-9.10/test-report-logfile-all-passed +++ b/nri-prelude/tests/golden-results-9.10/test-report-logfile-all-passed @@ -61,7 +61,7 @@ "file": "tests/TestSpec.hs", "module": "TestSpec", "name": "report", - "package": "nri-prelude-0.6.1.2-inplace-tests", + "package": "nri-prelude-0.7.0.0-inplace-tests", "startCol": 22, "startLine": 430 }, diff --git a/nri-prelude/tests/golden-results-9.10/test-report-logfile-no-tests-in-suite b/nri-prelude/tests/golden-results-9.10/test-report-logfile-no-tests-in-suite index 4fb70627..214949fd 100644 --- a/nri-prelude/tests/golden-results-9.10/test-report-logfile-no-tests-in-suite +++ b/nri-prelude/tests/golden-results-9.10/test-report-logfile-no-tests-in-suite @@ -10,7 +10,7 @@ "file": "tests/TestSpec.hs", "module": "TestSpec", "name": "report", - "package": "nri-prelude-0.6.1.2-inplace-tests", + "package": "nri-prelude-0.7.0.0-inplace-tests", "startCol": 22, "startLine": 469 }, diff --git a/nri-prelude/tests/golden-results-9.10/test-report-logfile-onlys-passed b/nri-prelude/tests/golden-results-9.10/test-report-logfile-onlys-passed index 9025a273..d4b4788c 100644 --- a/nri-prelude/tests/golden-results-9.10/test-report-logfile-onlys-passed +++ b/nri-prelude/tests/golden-results-9.10/test-report-logfile-onlys-passed @@ -61,7 +61,7 @@ "file": "tests/TestSpec.hs", "module": "TestSpec", "name": "report", - "package": "nri-prelude-0.6.1.2-inplace-tests", + "package": "nri-prelude-0.7.0.0-inplace-tests", "startCol": 22, "startLine": 445 }, diff --git a/nri-prelude/tests/golden-results-9.10/test-report-logfile-passed-with-skipped b/nri-prelude/tests/golden-results-9.10/test-report-logfile-passed-with-skipped index 4d09310e..674a9cf4 100644 --- a/nri-prelude/tests/golden-results-9.10/test-report-logfile-passed-with-skipped +++ b/nri-prelude/tests/golden-results-9.10/test-report-logfile-passed-with-skipped @@ -61,7 +61,7 @@ "file": "tests/TestSpec.hs", "module": "TestSpec", "name": "report", - "package": "nri-prelude-0.6.1.2-inplace-tests", + "package": "nri-prelude-0.7.0.0-inplace-tests", "startCol": 22, "startLine": 460 }, diff --git a/nri-prelude/tests/golden-results-9.10/test-report-logfile-tests-failed b/nri-prelude/tests/golden-results-9.10/test-report-logfile-tests-failed index 20a66ae9..e622f4ff 100644 --- a/nri-prelude/tests/golden-results-9.10/test-report-logfile-tests-failed +++ b/nri-prelude/tests/golden-results-9.10/test-report-logfile-tests-failed @@ -109,7 +109,7 @@ "file": "tests/TestSpec.hs", "module": "TestSpec", "name": "report", - "package": "nri-prelude-0.6.1.2-inplace-tests", + "package": "nri-prelude-0.7.0.0-inplace-tests", "startCol": 22, "startLine": 489 }, diff --git a/nri-prelude/tests/golden-results-9.10/warn b/nri-prelude/tests/golden-results-9.10/warn index aaf7b246..43d7930e 100644 --- a/nri-prelude/tests/golden-results-9.10/warn +++ b/nri-prelude/tests/golden-results-9.10/warn @@ -6,7 +6,7 @@ Just ( "warn" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 53 diff --git a/nri-prelude/tests/golden-results-9.12/debug b/nri-prelude/tests/golden-results-9.12/debug index a2629768..6b3bcde9 100644 --- a/nri-prelude/tests/golden-results-9.12/debug +++ b/nri-prelude/tests/golden-results-9.12/debug @@ -6,7 +6,7 @@ Just ( "debug" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 40 diff --git a/nri-prelude/tests/golden-results-9.12/error b/nri-prelude/tests/golden-results-9.12/error index 4b550b43..0ccd5662 100644 --- a/nri-prelude/tests/golden-results-9.12/error +++ b/nri-prelude/tests/golden-results-9.12/error @@ -6,7 +6,7 @@ Just ( "error" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 66 diff --git a/nri-prelude/tests/golden-results-9.12/log-async-exceptions b/nri-prelude/tests/golden-results-9.12/log-async-exceptions index 9960f182..fb749c61 100644 --- a/nri-prelude/tests/golden-results-9.12/log-async-exceptions +++ b/nri-prelude/tests/golden-results-9.12/log-async-exceptions @@ -6,7 +6,7 @@ Just ( "withContext" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 113 @@ -29,7 +29,7 @@ Just ( "withContext" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 112 diff --git a/nri-prelude/tests/golden-results-9.12/log-info b/nri-prelude/tests/golden-results-9.12/log-info index 9bc7042a..2d8e3184 100644 --- a/nri-prelude/tests/golden-results-9.12/log-info +++ b/nri-prelude/tests/golden-results-9.12/log-info @@ -6,7 +6,7 @@ Just ( "info" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 30 diff --git a/nri-prelude/tests/golden-results-9.12/log-nested-spans b/nri-prelude/tests/golden-results-9.12/log-nested-spans index 5bee1860..9a2ea38d 100644 --- a/nri-prelude/tests/golden-results-9.12/log-nested-spans +++ b/nri-prelude/tests/golden-results-9.12/log-nested-spans @@ -6,7 +6,7 @@ Just ( "withContext" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 81 @@ -29,7 +29,7 @@ Just ( "withContext" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 80 @@ -52,7 +52,7 @@ Just ( "info" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 79 diff --git a/nri-prelude/tests/golden-results-9.12/log-new-root b/nri-prelude/tests/golden-results-9.12/log-new-root index 0547be4d..f08dcf87 100644 --- a/nri-prelude/tests/golden-results-9.12/log-new-root +++ b/nri-prelude/tests/golden-results-9.12/log-new-root @@ -6,7 +6,7 @@ Just ( "info" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 174 @@ -30,7 +30,7 @@ Just ( "info" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 177 @@ -54,7 +54,7 @@ Just ( "info" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 176 @@ -78,7 +78,7 @@ Just ( "withContext" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 173 @@ -101,7 +101,7 @@ Just ( "info" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 173 diff --git a/nri-prelude/tests/golden-results-9.12/log-unexpected-exceptions b/nri-prelude/tests/golden-results-9.12/log-unexpected-exceptions index 94fa4f8f..9deeb593 100644 --- a/nri-prelude/tests/golden-results-9.12/log-unexpected-exceptions +++ b/nri-prelude/tests/golden-results-9.12/log-unexpected-exceptions @@ -6,7 +6,7 @@ Just ( "withContext" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 94 @@ -29,7 +29,7 @@ Just ( "withContext" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 93 diff --git a/nri-prelude/tests/golden-results-9.12/test-report-logfile-all-passed b/nri-prelude/tests/golden-results-9.12/test-report-logfile-all-passed index 085c55b8..d752330c 100644 --- a/nri-prelude/tests/golden-results-9.12/test-report-logfile-all-passed +++ b/nri-prelude/tests/golden-results-9.12/test-report-logfile-all-passed @@ -61,7 +61,7 @@ "file": "tests/TestSpec.hs", "module": "TestSpec", "name": "report", - "package": "nri-prelude-0.6.1.2-inplace-tests", + "package": "nri-prelude-0.7.0.0-inplace-tests", "startCol": 22, "startLine": 430 }, diff --git a/nri-prelude/tests/golden-results-9.12/test-report-logfile-no-tests-in-suite b/nri-prelude/tests/golden-results-9.12/test-report-logfile-no-tests-in-suite index 4fb70627..214949fd 100644 --- a/nri-prelude/tests/golden-results-9.12/test-report-logfile-no-tests-in-suite +++ b/nri-prelude/tests/golden-results-9.12/test-report-logfile-no-tests-in-suite @@ -10,7 +10,7 @@ "file": "tests/TestSpec.hs", "module": "TestSpec", "name": "report", - "package": "nri-prelude-0.6.1.2-inplace-tests", + "package": "nri-prelude-0.7.0.0-inplace-tests", "startCol": 22, "startLine": 469 }, diff --git a/nri-prelude/tests/golden-results-9.12/test-report-logfile-onlys-passed b/nri-prelude/tests/golden-results-9.12/test-report-logfile-onlys-passed index 9025a273..d4b4788c 100644 --- a/nri-prelude/tests/golden-results-9.12/test-report-logfile-onlys-passed +++ b/nri-prelude/tests/golden-results-9.12/test-report-logfile-onlys-passed @@ -61,7 +61,7 @@ "file": "tests/TestSpec.hs", "module": "TestSpec", "name": "report", - "package": "nri-prelude-0.6.1.2-inplace-tests", + "package": "nri-prelude-0.7.0.0-inplace-tests", "startCol": 22, "startLine": 445 }, diff --git a/nri-prelude/tests/golden-results-9.12/test-report-logfile-passed-with-skipped b/nri-prelude/tests/golden-results-9.12/test-report-logfile-passed-with-skipped index 4d09310e..674a9cf4 100644 --- a/nri-prelude/tests/golden-results-9.12/test-report-logfile-passed-with-skipped +++ b/nri-prelude/tests/golden-results-9.12/test-report-logfile-passed-with-skipped @@ -61,7 +61,7 @@ "file": "tests/TestSpec.hs", "module": "TestSpec", "name": "report", - "package": "nri-prelude-0.6.1.2-inplace-tests", + "package": "nri-prelude-0.7.0.0-inplace-tests", "startCol": 22, "startLine": 460 }, diff --git a/nri-prelude/tests/golden-results-9.12/test-report-logfile-tests-failed b/nri-prelude/tests/golden-results-9.12/test-report-logfile-tests-failed index 20a66ae9..e622f4ff 100644 --- a/nri-prelude/tests/golden-results-9.12/test-report-logfile-tests-failed +++ b/nri-prelude/tests/golden-results-9.12/test-report-logfile-tests-failed @@ -109,7 +109,7 @@ "file": "tests/TestSpec.hs", "module": "TestSpec", "name": "report", - "package": "nri-prelude-0.6.1.2-inplace-tests", + "package": "nri-prelude-0.7.0.0-inplace-tests", "startCol": 22, "startLine": 489 }, diff --git a/nri-prelude/tests/golden-results-9.12/warn b/nri-prelude/tests/golden-results-9.12/warn index aaf7b246..43d7930e 100644 --- a/nri-prelude/tests/golden-results-9.12/warn +++ b/nri-prelude/tests/golden-results-9.12/warn @@ -6,7 +6,7 @@ Just ( "warn" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 53 diff --git a/nri-prelude/tests/golden-results-9.8/debug b/nri-prelude/tests/golden-results-9.8/debug index a2629768..6b3bcde9 100644 --- a/nri-prelude/tests/golden-results-9.8/debug +++ b/nri-prelude/tests/golden-results-9.8/debug @@ -6,7 +6,7 @@ Just ( "debug" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 40 diff --git a/nri-prelude/tests/golden-results-9.8/debug-todo-stacktrace b/nri-prelude/tests/golden-results-9.8/debug-todo-stacktrace index c493c9d1..b3913453 100644 --- a/nri-prelude/tests/golden-results-9.8/debug-todo-stacktrace +++ b/nri-prelude/tests/golden-results-9.8/debug-todo-stacktrace @@ -1,3 +1,3 @@ foo CallStack (from HasCallStack): - todo, called at tests/TestSpec.hs:177:20 in nri-prelude-0.6.1.2-inplace-tests:TestSpec \ No newline at end of file + todo, called at tests/TestSpec.hs:177:20 in nri-prelude-0.7.0.0-inplace-tests:TestSpec \ No newline at end of file diff --git a/nri-prelude/tests/golden-results-9.8/error b/nri-prelude/tests/golden-results-9.8/error index 4b550b43..0ccd5662 100644 --- a/nri-prelude/tests/golden-results-9.8/error +++ b/nri-prelude/tests/golden-results-9.8/error @@ -6,7 +6,7 @@ Just ( "error" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 66 diff --git a/nri-prelude/tests/golden-results-9.8/log-async-exceptions b/nri-prelude/tests/golden-results-9.8/log-async-exceptions index 9960f182..fb749c61 100644 --- a/nri-prelude/tests/golden-results-9.8/log-async-exceptions +++ b/nri-prelude/tests/golden-results-9.8/log-async-exceptions @@ -6,7 +6,7 @@ Just ( "withContext" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 113 @@ -29,7 +29,7 @@ Just ( "withContext" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 112 diff --git a/nri-prelude/tests/golden-results-9.8/log-info b/nri-prelude/tests/golden-results-9.8/log-info index 9bc7042a..2d8e3184 100644 --- a/nri-prelude/tests/golden-results-9.8/log-info +++ b/nri-prelude/tests/golden-results-9.8/log-info @@ -6,7 +6,7 @@ Just ( "info" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 30 diff --git a/nri-prelude/tests/golden-results-9.8/log-nested-spans b/nri-prelude/tests/golden-results-9.8/log-nested-spans index 5bee1860..9a2ea38d 100644 --- a/nri-prelude/tests/golden-results-9.8/log-nested-spans +++ b/nri-prelude/tests/golden-results-9.8/log-nested-spans @@ -6,7 +6,7 @@ Just ( "withContext" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 81 @@ -29,7 +29,7 @@ Just ( "withContext" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 80 @@ -52,7 +52,7 @@ Just ( "info" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 79 diff --git a/nri-prelude/tests/golden-results-9.8/log-new-root b/nri-prelude/tests/golden-results-9.8/log-new-root index 0547be4d..f08dcf87 100644 --- a/nri-prelude/tests/golden-results-9.8/log-new-root +++ b/nri-prelude/tests/golden-results-9.8/log-new-root @@ -6,7 +6,7 @@ Just ( "info" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 174 @@ -30,7 +30,7 @@ Just ( "info" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 177 @@ -54,7 +54,7 @@ Just ( "info" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 176 @@ -78,7 +78,7 @@ Just ( "withContext" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 173 @@ -101,7 +101,7 @@ Just ( "info" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 173 diff --git a/nri-prelude/tests/golden-results-9.8/log-unexpected-exceptions b/nri-prelude/tests/golden-results-9.8/log-unexpected-exceptions index 94fa4f8f..9deeb593 100644 --- a/nri-prelude/tests/golden-results-9.8/log-unexpected-exceptions +++ b/nri-prelude/tests/golden-results-9.8/log-unexpected-exceptions @@ -6,7 +6,7 @@ Just ( "withContext" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 94 @@ -29,7 +29,7 @@ Just ( "withContext" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 93 diff --git a/nri-prelude/tests/golden-results-9.8/test-report-logfile-all-passed b/nri-prelude/tests/golden-results-9.8/test-report-logfile-all-passed index 085c55b8..d752330c 100644 --- a/nri-prelude/tests/golden-results-9.8/test-report-logfile-all-passed +++ b/nri-prelude/tests/golden-results-9.8/test-report-logfile-all-passed @@ -61,7 +61,7 @@ "file": "tests/TestSpec.hs", "module": "TestSpec", "name": "report", - "package": "nri-prelude-0.6.1.2-inplace-tests", + "package": "nri-prelude-0.7.0.0-inplace-tests", "startCol": 22, "startLine": 430 }, diff --git a/nri-prelude/tests/golden-results-9.8/test-report-logfile-no-tests-in-suite b/nri-prelude/tests/golden-results-9.8/test-report-logfile-no-tests-in-suite index 4fb70627..214949fd 100644 --- a/nri-prelude/tests/golden-results-9.8/test-report-logfile-no-tests-in-suite +++ b/nri-prelude/tests/golden-results-9.8/test-report-logfile-no-tests-in-suite @@ -10,7 +10,7 @@ "file": "tests/TestSpec.hs", "module": "TestSpec", "name": "report", - "package": "nri-prelude-0.6.1.2-inplace-tests", + "package": "nri-prelude-0.7.0.0-inplace-tests", "startCol": 22, "startLine": 469 }, diff --git a/nri-prelude/tests/golden-results-9.8/test-report-logfile-onlys-passed b/nri-prelude/tests/golden-results-9.8/test-report-logfile-onlys-passed index 9025a273..d4b4788c 100644 --- a/nri-prelude/tests/golden-results-9.8/test-report-logfile-onlys-passed +++ b/nri-prelude/tests/golden-results-9.8/test-report-logfile-onlys-passed @@ -61,7 +61,7 @@ "file": "tests/TestSpec.hs", "module": "TestSpec", "name": "report", - "package": "nri-prelude-0.6.1.2-inplace-tests", + "package": "nri-prelude-0.7.0.0-inplace-tests", "startCol": 22, "startLine": 445 }, diff --git a/nri-prelude/tests/golden-results-9.8/test-report-logfile-passed-with-skipped b/nri-prelude/tests/golden-results-9.8/test-report-logfile-passed-with-skipped index 4d09310e..674a9cf4 100644 --- a/nri-prelude/tests/golden-results-9.8/test-report-logfile-passed-with-skipped +++ b/nri-prelude/tests/golden-results-9.8/test-report-logfile-passed-with-skipped @@ -61,7 +61,7 @@ "file": "tests/TestSpec.hs", "module": "TestSpec", "name": "report", - "package": "nri-prelude-0.6.1.2-inplace-tests", + "package": "nri-prelude-0.7.0.0-inplace-tests", "startCol": 22, "startLine": 460 }, diff --git a/nri-prelude/tests/golden-results-9.8/test-report-logfile-tests-failed b/nri-prelude/tests/golden-results-9.8/test-report-logfile-tests-failed index 20a66ae9..e622f4ff 100644 --- a/nri-prelude/tests/golden-results-9.8/test-report-logfile-tests-failed +++ b/nri-prelude/tests/golden-results-9.8/test-report-logfile-tests-failed @@ -109,7 +109,7 @@ "file": "tests/TestSpec.hs", "module": "TestSpec", "name": "report", - "package": "nri-prelude-0.6.1.2-inplace-tests", + "package": "nri-prelude-0.7.0.0-inplace-tests", "startCol": 22, "startLine": 489 }, diff --git a/nri-prelude/tests/golden-results-9.8/warn b/nri-prelude/tests/golden-results-9.8/warn index aaf7b246..43d7930e 100644 --- a/nri-prelude/tests/golden-results-9.8/warn +++ b/nri-prelude/tests/golden-results-9.8/warn @@ -6,7 +6,7 @@ Just ( "warn" , SrcLoc - { srcLocPackage = "nri-prelude-0.6.1.2-inplace-tests" + { srcLocPackage = "nri-prelude-0.7.0.0-inplace-tests" , srcLocModule = "LogSpec" , srcLocFile = "tests/LogSpec.hs" , srcLocStartLine = 53 diff --git a/nri-redis/nri-redis.cabal b/nri-redis/nri-redis.cabal index 8d358c1c..6a3d72f3 100644 --- a/nri-redis/nri-redis.cabal +++ b/nri-redis/nri-redis.cabal @@ -76,7 +76,7 @@ library , modern-uri >=0.3.1.0 && <0.4 , nri-env-parser >=0.1.0.0 && <0.5 , nri-observability >=0.1.0 && <0.5 - , nri-prelude >=0.1.0.0 && <0.7 + , nri-prelude >=0.1.0.0 && <0.8 , pcre-light >=0.4.1.0 && <0.4.2 , resourcet >=1.2.0 && <1.4 , safe-exceptions >=0.1.7.0 && <1.3 @@ -141,7 +141,7 @@ test-suite tests , modern-uri >=0.3.1.0 && <0.4 , nri-env-parser >=0.1.0.0 && <0.5 , nri-observability >=0.1.0 && <0.5 - , nri-prelude >=0.1.0.0 && <0.7 + , nri-prelude >=0.1.0.0 && <0.8 , pcre-light >=0.4.1.0 && <0.4.2 , resourcet >=1.2.0 && <1.4 , safe-exceptions >=0.1.7.0 && <1.3 diff --git a/nri-redis/package.yaml b/nri-redis/package.yaml index 4edb35e4..568ca854 100644 --- a/nri-redis/package.yaml +++ b/nri-redis/package.yaml @@ -28,7 +28,7 @@ dependencies: - modern-uri >= 0.3.1.0 && < 0.4 - nri-env-parser >= 0.1.0.0 && < 0.5 - nri-observability >= 0.1.0 && < 0.5 - - nri-prelude >= 0.1.0.0 && < 0.7 + - nri-prelude >= 0.1.0.0 && < 0.8 - pcre-light >= 0.4.1.0 && < 0.4.2 - resourcet >= 1.2.0 && < 1.4 - safe-exceptions >= 0.1.7.0 && < 1.3 diff --git a/nri-redis/test/Spec/Redis.hs b/nri-redis/test/Spec/Redis.hs index 85ffca1a..4e7af3d8 100644 --- a/nri-redis/test/Spec/Redis.hs +++ b/nri-redis/test/Spec/Redis.hs @@ -30,6 +30,7 @@ spanForTask task = res <- Platform.rootTracingSpanIO "test-request" + Platform.silentTrack (MVar.putMVar spanVar) "test-root" (\log -> Task.attempt log task) @@ -46,6 +47,7 @@ spanForFailingTask task = res <- Platform.rootTracingSpanIO "test-request" + Platform.silentTrack (MVar.putMVar spanVar) "test-root" (\log -> Task.attempt log task) diff --git a/nri-test-encoding/nri-test-encoding.cabal b/nri-test-encoding/nri-test-encoding.cabal index dc1b25a3..3a3f710d 100644 --- a/nri-test-encoding/nri-test-encoding.cabal +++ b/nri-test-encoding/nri-test-encoding.cabal @@ -58,7 +58,7 @@ library , base >=4.18 && <4.22 , bytestring >=0.10.8.2 && <0.13 , filepath >=1.4.2.1 && <1.6 - , nri-prelude >=0.1.0.0 && <0.7 + , nri-prelude >=0.1.0.0 && <0.8 , nri-redis >=0.1.0.0 && <0.5 , servant >=0.20.2 && <0.21 , servant-auth-server >=0.4.9.0 && <0.5 @@ -99,7 +99,7 @@ test-suite tests , base >=4.18 && <4.22 , bytestring >=0.10.8.2 && <0.13 , filepath >=1.4.2.1 && <1.6 - , nri-prelude >=0.1.0.0 && <0.7 + , nri-prelude >=0.1.0.0 && <0.8 , nri-redis >=0.1.0.0 && <0.5 , servant >=0.20.2 && <0.21 , servant-auth-server >=0.4.9.0 && <0.5 diff --git a/nri-test-encoding/package.yaml b/nri-test-encoding/package.yaml index 3278281a..89d64d3b 100644 --- a/nri-test-encoding/package.yaml +++ b/nri-test-encoding/package.yaml @@ -23,7 +23,7 @@ dependencies: - servant-auth-server >= 0.4.9.0 && < 0.5 - servant-server >= 0.20.2 && < 0.21 - text >= 1.2.3.1 && < 2.2 - - nri-prelude >= 0.1.0.0 && < 0.7 + - nri-prelude >= 0.1.0.0 && < 0.8 - nri-redis >= 0.1.0.0 && < 0.5 library: exposed-modules: